五个Java冠军喜欢的Java 16强大功能 - oracle


Java Magazine 联系了几位 Java Champion,即来自 Java 社区各个领域的技术杰出人物,问题很简单:“ JDK 16中什么是最重要的部分?”
 
1. JEP 395(记录)
作者:Ivar Grimstad,Java 冠军
对我来说,JDK 16 中最重要的特性是JEP 395: Records,它减少了所需的样板代码量。从未写过的代码是最好的代码,因为它保证不包含任何错误!
一段record Point(int x, int y) { }可以替代下面整个代码:

class Point {
    private final int x;
    private final int y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    int x() { return x; }
    int y() { return y; }

    public boolean equals(Object o) {
        if (!(o instanceof Point)) return false;
        Point other = (Point) o;
        return other.x == x && other.y = y;
    }

    public int hashCode() {
        return Objects.hash(x, y);
    }

    public String toString() {
        return String.format("Point[x=%d, y=%d]", x, y);
    }
}

 
2. JEP 394(instanceof 的模式匹配)
作为一名开发人员,我对jep394的当前功能和用法感到兴奋:java16中instanceof的模式匹配,以及它如何扩展到其他语言结构,如switch表达式和未来Java版本中的其他语言结构。而且,这个特性可以在日常代码中经常使用,这使得它更加有用。

在其当前用法中,此功能将模式匹配应用于instanceof运算符,并可以消除以下代码中明显重复的compareUsingInstanceof ifTrue cast:

void outputValueInUppercase(Object obj) {
    if (obj instanceof String) { 
        String s = (String) obj; 
        System.out.println(s.toUpperCase()); 
    }
}

它还可以通过引入模式变量(如str)简化代码,如下所示:
void outputValueInUppercase(Object obj) {
    if (obj instanceof String str) { 
        System.out.println(str.toUpperCase()); 
    }
}

instanceof的模式匹配的简单性可能具有欺骗性。下面是一个示例,说明开发人员通常如何使用两个实例变量model(字符串值)和price(双倍值)重写类(在本例中为Monitor)的equals()方法:
public class Monitor {
   String model;
   double price;
   @Override
   public boolean equals(Object o) {
       if (o instanceof Monitor) {
           Monitor other = (Monitor) o;
           if (model.equals(other.model) && price == other.price) {
               return true;
           }
       }
       return false;
   }
}

下面是如何通过使用instanceof的模式匹配和if语句的进一步简化来简化前面的equals()方法:
public boolean equals(Object o) {
    return o instanceof Monitor other 
        && model.equals(other.model) && price == other.price;
}

这只是冰山一角。作为一个开发人员,您可以使用instanceof的模式匹配来简化您的代码,这在以前是不可行的。例如,以下代码
void processChildNode(Tree tree) {
        if (tree.getChildNodes() instanceof Map) {
            Map<?, Node> childNodes = (Map<?, Node>) tree.getChildNodes();
            if (childNodes.size() == 1) {
                Node node = childNodes.get("root");
                if (node instanceof LetterNode) {
                    LetterNode letterNode = (LetterNode) node;
                    letterNode.isLatin();
                }
            }
        }
    }

简化为:
void processChildNode(Tree tree) {
        if (tree.getChildNodes() instanceof Map<?, Node> childNodes 
            && childNodes.size() == 1 
            && childNodes.get("root") instanceof LetterNode letterNode) {
                letterNode.isLatin();
        }
    }

生成的代码更易于阅读和理解,简洁,并且应该更易于维护。我迫不及待地想看看这个特性将来如何应用到其他语言结构中。
 
3.JEP 394(instanceof 的模式匹配)
作者:Arjan Tijms,Java 冠军
虽然 JDK 16 中有很多非常有趣的东西,但对我来说,亮点是用于instanceof检查时模式匹配的初始版本,它通常非常嘈杂并且容易出错。
在 JEP 394 之前:
if (asyncStartRequest instanceof HttpServletRequest) {
     HttpServletRequest httpServletRequest = (HttpServletRequest) 
         asyncStartRequest;
     path = httpServletRequest
                .getRequestURI()
                .substring(httpServletRequest.getContextPath().length());
  } else {
      path = …
  }

JEP 394 之后:
if (asyncStartRequest instanceof HttpServletRequest httpServletRequest) {
      path = httpServletRequest
                .getRequestURI()
                .substring(httpServletRequest.getContextPath().length());
  } else {
      path = …
  }

if块的嘈杂的第一行现在消失了,您可以立即关注路径分配。您也不会意外地检查ServletRequest并将其转换为HttpServletRequest。

这个新特性非常有趣,因为它将是Java中首次引入模式匹配。
 
4. Stream.toList()
作者:Java Champion Tagir Valeev
自从在 Java 8 中引入Stream以来,Stream API 就因其冗长而受到指责。例如,对列表执行简单的映射转换需要尽可能多地编写list.stream().map(fn).collect(toList());使用新版本,您现在可以编写更短、更清晰的代码,例如list.stream().map(fn).toList(). (没有了collect)
首先,虽然规范不能保证这一点,但是collect(toList())产生了一个可变列表,许多用户已经依赖这个事实。新方法Stream.toList()生成一个不可修改的列表。它也不是collect(toUnmodifiableList())的快捷方式,因为toUnmodifiableList()不接受空值。
其次,Stream.toList()的实现不受collect接口的约束。
因此,Stream.toList()更优化,分配的内存更少,特别是在预先知道流大小的情况下。

5. JEP 338(向量 API)、JEP 389(外部链接器 API)和 JEP 393(外部内存访问 API)
作者Rafael Winterhalter,Java 冠军
Java 16 弥补了更多差距,以更好地与运行 JVM 的硬件配合使用。
使用孵化向量 API (JEP 338),JVM 开发人员可以开始探索如何改进代码的运行时,其中向量化有时可以实现很大的改进。
借助孵化外部链接器 API (JEP 389),开发人员还可以更轻松地包含本机代码。
孵化中的外部内存访问 API (JEP 393)最终允许从 Java 进行适当的直接内存操作。
所有这些变化使我们更接近于更好地将 JVM 库和应用程序与硬件集成,而不依赖于不安全的内部 API,一旦时间准备好并且这些 API 最终确定,这将使 JVM 成为一个更安全、更可靠的平台。未来版本。
我非常期待尝试这些孵化 API,它们共同为 Java 的未来打开了一扇大门。