Java 16的三个主要新特性


可用于生产的 Java 16 通用可用性 (GA) 版本已经发布了,Java 16 中有一些可用的新特性,我们现在就来看看。
 
Record记录
记录声明一种数据类,这种类在 ORM 框架中被定义为数据传输对象 (DTO) 或实体。
传统创建类的方法是创建一个具有属性和所有参数构造函数的public类,并定义所有 getter/setter 以及 equals、hashCode 和 toString。这需要大量额外的代码,人们于是使用代码生成库和插件(如 Lombok)来减少这些代码,但仍然很麻烦。
Java 16 引入了记录Record类型来简化此类类的创建:

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");  
                }  
           }  
      }  
 }

上面的例子展示了在Java16中使用一个记录的方法。Record Student定义为一个静态变量,它具有id、name和grade属性。默认情况下,Java编译器将生成带有equals、hashCode和toString的getter/setter。

一旦它被实例化,记录对象就充当常规对象。唯一的区别是,生成的访问器/修饰符不遵循javabean约定(name的getter方式是name()而不是传统getName()),因此不是javabean的替代品。由于这个原因,JSON序列化程序和ORM框架还不支持记录类型,但正在进行中。
 
流接口的新方法
流接口中引入了几种新方法,可以用来提高性能和减少样板代码。一个是Stream.toList()方法。

List<Integer> evenNos = nos.stream().filter(i -> i % 2 == 0).toList(); //.collect(Collectors.toList())  
System.out.println(
"Even numbers : "+evenNos);

当需要将流值聚合到列表时,此方法删除了collect方法的调用。

此外,还引入了一个新方法Stream.mapMulti(),它是Stream.flatMap()的更重要的实现。它的实际应用有点复杂。
 
模式匹配
模式匹配是对Java16的一个非常有用的补充,它消除了在使用instanceof操作符之后强制转换的需要。

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;  
           }  
      }  
 }

此功能允许在使用instanceof运算符之后立即使用本地作用域变量名,该运算符与所使用的类型匹配,并且可以在不强制转换的情况下使用。这消除了许多样板代码。