Java is nearing its next Long Term Support (LTS) Release which is Java 17. Thus far it has released Java 16 General Availability (GA) Release which can be used in Production. There are some new features available in Java 16 which we are going to look at right now.
Record
Record is simplified way to declare a class which is used only to represent data. This type of classes are defined as Data Transfer Objects (DTO) or Entities in ORM frameworks to represent Tables. The current way to declare this type of classes is to create a public class with properties and all argument constructor and define all getters/setters along with equals, hashCode and toString. This requires a lot of additional code which can be reduced using code generation libraries and plugins like Lombok yet it is still an hassle.
Java 16 introduces record type to ease creation of such classes.
import java.util.*;
public class RecordTest {
public static void main(String... args) {
Student s1 = new Student(1, "Shazin", 1);
Student s2 = new Student(2, "Shahim", 2);
System.out.println("Student 1 : "+s1);
System.out.println("Student 2 : "+s2);
System.out.println("s1 == s2 : "+(s1 == s2));
System.out.println("s1.equals(s1) : "+(s1.equals(s1)));
System.out.println("s1.equals(s2) : "+(s1.equals(s2)));
record GraduateStudent(Student student, List<String> qualifications) {};
GraduateStudent gs1 = new GraduateStudent(s1, Arrays.asList("A/S", "BSc"));
System.out.println("GraduateStudent 1 : " + gs1);
}
private static record Student(Integer id, String name, Integer grade) {
public Student { // All args constructor
if (grade < 0 || grade > 13) {
throw new IllegalArgumentException("Grade must be between 1 and 13");
}
}
}
}
The above example shows the use a Record in Java 16. The record Student is defined below as a static variable with attributes id, name and grade. The getters/setters with equals, hashCode and toString will be generated by default for this. List<Integer> evenNos = nos.stream().filter(i -> i % 2 == 0).toList(); //.collect(Collectors.toList())
System.out.println("Even numbers : "+evenNos);
This method reduces the need to call collect method when there is need to aggregate a Stream values to a List.
import java.util.*;
public class PatternMatchingTest {
public static void main(String... args) {
String name = "Shazin";
List<Integer> nos = Arrays.asList(1, 2, 3, 4, 5);
Map map = Collections.singletonMap("Key", "Value");
Long bigInt = 1l;
System.out.println("Name Length : " + length(name));
System.out.println("Nos Length : " + length(nos));
System.out.println("Map Length : " + length(map));
System.out.println("bigInt Length : " + length(bigInt));
}
private static int length(Object o) {
if (o instanceof String s) { // s variable of type String
return s.length();
} else if (o instanceof Collection c) { // c variable of type Collection
return c.size();
} else if (o instanceof Map m) { // m variable of type Map
return m.size();
} else { // o variable of type Object
return 0;
}
}
}
This feature allows to use a local scoped variable name right after the use of instanceof operator which matches the type used and can be used without casting. This eliminates a lot of boilerplate code.