Google

May 21, 2014

7 useful miscellaneous additions you must know in Java 8

The much awaited addition in Java 8 are Lambda expressions to be used in functional programming and default and static methods in interfaces to support multiple behavior inheritance and helper methods. Here are a few other additional handy additions in Java 8.

Addition #1: String.join( ) method, which is an opposite of String.split(...) was there from pre Java 8.

Example 1:

String[] javaTechnologies = {"Java", "JEE", "JDBC", "Spring"};
String joined = String.join(",", javaTechnologies); //Java,JEE,JDBC,Spring

Example 2:

 String joined = String.join("/", "var", "opt", "oracle"); // var/opt/oracle

Addition #2: The Comparator interfaces have a number of useful methods to sort objects with options to nest multiple fields with thenComparing(...), and other handy methods like nullsFirst( ), nullsLast( ), naturalOrder( ), reverseOrder( ), etc. This was made possible as Java 8 interfaces can have default methods (which gives you multiple behavior inheritance) and static methods (a replacement for helper classes).

Example 1:

Arrays.sort(people, Comparator.comparing(Person::getName)  
                               .thenComparing(Person::getAge) ;
  
Example 2:

Comparator<Person> multiFieldComparator = 
    Comparator.comparing(Person::getGender, Comparator.nullsFirst(Comparator.naturalOrder()))
              .thenComparing(Person::getName, Comparator.nullsLast(Comparator.naturalOrder()))
              .thenComparing(Person::getAge,  Comparator.nullsLast(Comparator.reverseOrder())) ;
     
//parallel() processing using Fork/Join 
List<Object> sortedPeople = people.stream().parallel().sorted(multiFieldComparator).collect(Collectors.toList());   


Addition #3: In Java you cannot simply get rid of the null references that have historically existed, but before Java 8, you need to rely on your code and proper documentation to understand if a reference is optional (i.e can be null) as shown below,

import java.util.ArrayList;
import java.util.List;

public class PersonTest {

 public static void main(String[] args) {

  List<Person> people = new ArrayList<>();
  people.add(new Person("John", 35, Person.Gender.MALE));
  people.add(new Person("Simone", 30, Person.Gender.FEMALE));
  people.add(new Person("Shawn", 30, Person.Gender.MALE));
  
  Person foundPerson = find("Sam", people); 
  System.out.println(foundPerson.getName()); //NullPointerException
  
 }

 public static Person find(String name, List<Person> Persons) {
  for (Person person : Persons) {
   if (person.getName().equalsIgnoreCase(name)) {
    return person;
   }
  }
  return null;
 }
}




In Java 8java.util.Optional<T> class has been added to deal with optional object references. The intention with the Optional class is not to replace every null-able reference, but to help in the creation of more robust APIs you could tell if  you can expect an optional reference by reading the signature of a method.

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class PersonTest {

 public static void main(String[] args) {

  List<Person> people = new ArrayList<>();
  people.add(new Person("John", 35, Person.Gender.MALE));
  people.add(new Person("Simone", 30, Person.Gender.FEMALE));
  people.add(new Person("Shawn", 30, Person.Gender.MALE));

  Optional<Person> foundPerson = find("Sam", people);
  System.out.println(foundPerson.orElse(new Person("Sam", 35, Person.Gender.MALE))); 
  
 }

 public static Optional<Person> find(String name, List<Person> Persons) {
  for (Person Person : Persons) {
   if (Person.getName().equals(name)) {
    return Optional.of(Person);
   }
  }
  return Optional.empty();
 }
}


The find method signature tells you that it returns a person optionally.

Addition #4: In cases where you want to detect result overflow errors in int and long, the methods addExact, subtractExact, multiplyExact, and toIntExact in Java 8, the java.lang.Math class throws an ArithmeticException when the results overflow. Generally, it is recommended to use BigInteger if you expect large values.

public class DataOverflowTest {
 
 public static void main(String[] args) {
  
  //for int -2^31 and a maximum value of 2^31-1, which is -2147483648 to 2147483647
  
  int i = 2147483647 + 1;
  System.out.println(i); //wrong -- prints -2147483648 due to data overflow 
  
  //Java 8
  Math.addExact(2147483647, 1);  //java.lang.ArithmeticException: integer overflow
 }
}


Addition #5: The ability to lazily read lines from a file with Files.lines(...). For example, let's read technologies.txt that has

Java
JEE
JDBC
Hibernate
Spring

Now the code that covers previous additions as well.

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.stream.CloseableStream;

public class FileReadTest {
 
 public static void main(String[] args) {
  Path path = Paths.get("c:\\temp\\technologies.txt");
  try(CloseableStream<String> lines = Files.lines(path, Charset.forName("UTF-8"))){
   Optional<String> found = lines.filter(p -> p.contains("Spring")).findFirst();
   System.out.println(found.orElse("NOT FOUND!!"));
  } catch (IOException e) {
   e.printStackTrace();
  }//CloseableStream is AutoCloseable 
 }
}


Addition #6: The @Repeatable annotation.

Pre Java 8:

public @interface Habit {
 String value();
}

public @interface Habits {
     Habit[] value();
}

@Habits({@Habit("habit1"), @Habit("habit2")})
public class Person  {
   //......
}


Post Java 8:

import java.lang.annotation.Repeatable;

@Repeatable(Habits.class)
public @interface Habit {
 String value();
}


@Habit("habit1")
@Habit("habit2")
public class Person  {
   //...
}

In Pre Java 8, if you repeat the same annotation, you will get a compile-time error "Duplicate annotation". In Java 8, you can repeat the same annotation with the @Repeatable annotation.


Addition #7: Java 8 introduces the "Type Annotations", which are annotations that can be placed anywhere you use a type.


  • new operator, 
  • type casts, 
  • implements clauses and 
  • throws clauses. 

Handy for stronger type checking, but can clutter your code. Use them judiciously. For example,

@NotNull String str1 = ...
@Email String str2 = ...
Map.@NonNull Entry = ...
new @NonEmpty List<String>(notEmptySet)
List<@ReadOnly @Localized Message> messages = ...

Labels: ,

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home