关于java:JDK-15已发布你所要知道的都在这里

7次阅读

共计 9787 个字符,预计需要花费 25 分钟才能阅读完成。

JDK 15 曾经在 2020 年 9 月 15 日公布!详情见 JDK 15 官网打算。上面是对 JDK 15 所有新个性的具体解析!

官网打算

  • 2019/12/12 Rampdown Phase One (fork from main line)
  • 2020/06/11 Rampdown Phase One (fork from main line)
  • 2020/07/16 Rampdown Phase Two
  • 2020/08/06 Initial Release Candidate
  • 2020/08/20 Final Release Candidate
  • 2020/09/15 General Availability

个性预览

  • 339: 爱德华兹曲线数字签名算法(EdDSA)
  • 360: Sealed Classes (Preview)
  • 371: Hidden Classes
  • 372: 移除 Nashorn JavaScript 引擎
  • 373: 从新实现 DatagramSocket API
  • 374: 禁用偏差锁
  • 375: instanceof 的模式匹配(Second Preview)
  • 377: ZGC: 可扩大的低提早垃圾收集器
  • 378: 文本块
  • 379: Shenandoah: 低暂停工夫的垃圾收集器
  • 381: 删除 Solaris 和 SPARC Ports
  • 383: 内部存储器拜访 API (Second Incubator)
  • 384: Records (Second Preview)
  • 385: 废除 RMI Activation

深刻了解新个性

339: 爱德华兹曲线数字签名算法(EdDSA)

JEP 339: Edwards-Curve Digital Signature Algorithm (EdDSA)

与其余签名计划相比,EdDSA 具备更高的安全性和性能,并且已有很多其余加密库(如 OpenSSL 和 BoringSSL)反对此签名计划。EdDSA 是 TLS 1.3 的可选组件,且是 TLS 1.3 中仅有的三种签名计划之一。用户能够不用再应用第三方库了。

360: Sealed Classes (Preview)

JEP 360: Sealed Classes (Preview)

为什么须要此个性

在 Java 语言中,代码的重用是通过类的继承实现的:多个子类能够继承同一个超类(并重用超类的办法)。然而重用代码并不是类层次结构的惟一目标,有时类层次结构仅仅是对某个畛域的建模。以这种形式应用类层次结构时,限度子类汇合能够简化建模。

比方在图形库中,Shape 类的开发者可能只心愿无限个数的类扩大 Shape 类,开发者并不想为未知子类编写进攻代码。以前的 Java 并不会限度 Shape 类的扩大属性,Shape 类能够领有任意数量的子类。在关闭类(Sealed Classes)中,类层次结构是关闭的,然而代码依然能够在无限范畴内重用。

个性形容

通过 sealed 修饰符将一个类申明为密封类,permits 子句指定容许扩大密封类的类。例如上面的 Shape 类申明指定了三个可扩大的子类。

package com.example.geometry;

public abstract sealed class Shape
    permits Circle, Rectangle, Square {...}

在子类数量很少时,在密封类的源文件中申明子类会很不便。当以这种形式申明子类时,密封类能够省略 allows 子句,同时 Java 编译器将从源文件中推断容许的子类。例如上面的例子:

package com.example.geometry;

abstract sealed class Shape {...}
... class Circle    extends Shape {...}
... class Rectangle extends Shape {...}
... class Square    extends Shape {...}

密封类能够让代码更简洁,代码能够明确推断出所有容许的子类。比方传统的 if-else 和 instanceof 代码编译器剖析起来很艰难,无奈确定子句是否笼罩了所有容许的子类。上面的办法会导致编译期谬误:

int getCenter(Shape shape) {if (shape instanceof Circle) {return ... ((Circle)shape).center() ...} else if (shape instanceof Rectangle) {return ... ((Rectangle)shape).length() ...} else if (shape instanceof Square) {return ... ((Square)shape).side() ...}
}

在之后反对模式匹配的版本中,编译器能够间接推断出 Shape 所有容许的子类,不须要 default 语句。此外,如果短少子类的任意一个,编译器就会报错。

int getCenter(Shape shape) {return switch (shape) {case Circle c    -> ... c.center() ...
        case Rectangle r -> ... r.length() ...
        case Square s    -> ... s.side() ...};
}

JDK 中的密封类

package java.lang.constant;

public sealed interface ConstantDesc
    permits String, Integer, Float, Long, Double,
            ClassDesc, MethodTypeDesc, DynamicConstantDesc {...}

// ClassDesc is designed for subclassing by JDK classes only
public sealed interface ClassDesc extends ConstantDesc
    permits PrimitiveClassDescImpl, ReferenceClassDescImpl {...}
final class PrimitiveClassDescImpl implements ClassDesc {...}
final class ReferenceClassDescImpl implements ClassDesc {...} 

// MethodTypeDesc is designed for subclassing by JDK classes only
public sealed interface MethodTypeDesc extends ConstantDesc
    permits MethodTypeDescImpl {...}
final class MethodTypeDescImpl implements MethodTypeDesc {...}

// DynamicConstantDesc is designed for subclassing by user code
public non-sealed abstract class DynamicConstantDesc implements ConstantDesc {...}

JVM 反对

JVM 在运行时辨认密封类和接口,并避免未经受权的子类和子接口扩大密封类。

只管 sealed 关键字是类修饰符,然而 ClassFile 中并没有 ACC_SEALED 标记。相同,密封类的类文件具备 PermittedSubclasses 属性,该属性隐式批示密封修饰符,并显式指定容许的子类:

PermittedSubclasses_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 number_of_classes;
    u2 classes[number_of_classes];
}

Reflection API

java.lang.Class 将减少如下 public 办法:

  • java.lang.constant.ClassDesc[] getPermittedSubclasses()
  • boolean isSealed()

371: Hidden Classes

JEP 371: Hidden Classes

为什么须要此个性

暗藏类不能被其余类的字节码间接应用,适宜在运行时生成类、并通过反射间接应用暗藏类的框架。

个性形容

许多时机 JVM 构建的语言都通过动静生成类,进步灵活性和效率。比方在 Java 语言中,javac 不会在编译时将 lambda 表达式转换成非凡的类文件,而是保留在字节码中,该字节码能够把 lambda 表达式动静生成为相应的对象。同样地,非 Java 语言常常通过运行时生成动静代理,来实现语言的高级个性。

语言的实现者通常心愿将动静生成的类,在逻辑上成为动态生成类的实现的一部分:

  • 不可发现。仅通过名字就发现该类是不必要且无害的,因为这毁坏了 动静生成类仅是动态生成类的实现细节 这一指标。
  • 访问控制。可能心愿将动态生成类的访问控制扩大到动静生成类。
  • 生命周期。动静生成类的生命周期可能很短,在动态生成类中保留它们会占用不必要的内存。针对这种状况的现有解决方案(类加载器)不仅麻烦,而且效率低下。

可怜的是,类定义的规范 API(ClassLoader::defineClass 和 Lookup::defineClass)并不在意该类的字节码是动静生成(在运行时)还是动态生成(在编译时)的。如果规范 API 能够定义无奈被发现,且具备无限生命周期的暗藏类,则动静生成类的 JDK 外部和内部框架都能够定义暗藏类,这样做能够进步 JVM 语言实现的效率。比方:

  • java.lang.reflect.Proxy 能够定义暗藏类作为实现代理接口的代理类;
  • java.lang.invoke.StringConcatFactory 能够生成暗藏类来保留常量连贯办法;
  • java.lang.invoke.LambdaMetaFactory 能够生成暗藏的 nestmate 类,以包容拜访关闭变量的 lambda 主体。

372: 移除 Nashorn JavaScript 引擎

JEP 372: Remove the Nashorn JavaScript Engine

个性形容

Java 11 中曾经将该引擎标记为废除,并明确示意要在未来的版本中删除它。Nashorn JavaScript 引擎最开始是 JDK 8 通过 JEP 174 继承的,用来代替 Rhino 脚本引擎,过后 Nashorn JavaScript 引擎是 ECMAScript-262 5.1 规范的残缺实现。然而随着 ECMAScript 语言结构以及 API 的批改,咱们发现 Nashorn 难以保护。

JDK 的两个模块会永恒删除:

  • jdk.scripting.nashorn
  • jdk.scripting.nashorn.shell

373: 从新实现 DatagramSocket API

JEP 373: Reimplement the Legacy DatagramSocket API

Java.net.DatagramSocket 和 java.net.MulticastSocket API 重构了根底实现,使得其更易于保护和调试。新的实现能更好地适应虚构线程的工作。

374: 禁用偏差锁

JEP 374: Disable and Deprecate Biased Locking

个性形容

默认状况下禁用偏差锁,并废除所有相干的命令行。

为什么须要此个性

偏差锁是 HotSpot 虚拟机应用的一项优化技术,可能缩小无竞争锁定时的开销。偏差锁的目标是假设 monitor 始终由某个特定线程持有,直到另一个线程尝试获取它,这样就能够防止获取 monitor 时执行 cas 的原子操作。monitor 首次锁定时偏差该线程,这样就能够防止同一对象的后续同步操作步骤须要原子指令。从历史上看,偏差锁使得 JVM 的性能失去了显著改善。

然而过来看到的性能晋升,在当初看来曾经不那么显著了。受害于偏差锁的应用程序,往往是应用了晚期 Java 汇合 API 的程序(JDK 1.1),这些 API(Hasttable 和 Vector)每次拜访时都进行同步。JDK 1.2 引入了针对单线程场景的非同步汇合(HashMap 和 ArrayList),JDK 1.5 针对多线程场景推出了性能更高的并发数据结构。这意味着如果代码更新为应用较新的类,因为不必要同步而受害于偏差锁的应用程序,可能会看到很大的性能进步。此外,围绕线程池队列和工作线程构建的应用程序,性能通常在禁用偏差锁的状况下变得更好。

偏差锁为同步零碎引入了许多简单的代码,并且对 HotSpot 的其余组件产生了影响。这种复杂性曾经成为了解代码的阻碍,也妨碍了对同步零碎进行重构。因而,咱们心愿禁用、废除并最终删除偏差锁。

375: instanceof 的模式匹配(Second Preview)

JEP 375: Pattern Matching for instanceof (Second Preview)

为什么须要此个性

通过对 instanceof 运算符进行模式匹配,来减少 Java 语言。模式匹配能够使应用程序更简洁、平安地提取特定对象。

个性形容

很多程序都会判断一个表达式是否具备某种类型或构造,而后有条件地进一步解决,比方上面的 instanceof-and-cast 用法:

if (obj instanceof String) {String s = (String) obj;
    // use s
}

上述代码做了 3 件事:

  • 判断 obj 是否是 string 类型
  • 将 obj 转换为 string 类型
  • 申明了一个新的局部变量 s

这种模式很简略,然而这样的写法并不是最优的。第 2 步的类型转换是反复的,同时反复可能会带来谬误。模式匹配容许扼要地表白对象的所需“形态”(模式),并容许各种语句和表达式针对其输出来测试“形态”(匹配)。从 Haskell 到 C# 等很多语言都承受了模式匹配。

在上面的代码中,短语 String s 是类型测试模式:

if (obj instanceof String s) {// can use s here} else {// can't use s here}

上面的代码也是正确的:

if (obj instanceof String s && s.length() > 5) {.. s.contains(..) ..}

377: ZGC: 可扩大的低提早垃圾收集器

JEP 377: ZGC: A Scalable Low-Latency Garbage Collector (Production)

ZGC 曾经在 JEP 333 时集成到了 JDK 11 中,过后是作为试验个性引入的。在 JDK 11 公布以来,咱们收到了很多踊跃的反馈,并修复了许多 bug,增加了很多新性能。更重要的是,ZGC 曾经反对所有支流平台:

  • Linux/x86_64 (JEP 333)
  • Linux/aarch64 (8214527)
  • Windows (JEP 365)
  • macOS (JEP 364)

当初能够通过 -XX:+UnlockExperimentalVMOptions -XX:+UseZGC 命令选项启用 ZGC。

378: 文本块

JEP 378: Text Blocks

Java 语言减少文本块性能。文本块是多行字符串文字,能防止大多数状况下的本义问题。

为什么须要此个性

在 Java 中,HTML, XML, SQL, JSON 等字符串对象都很难浏览和保护。

HTML

应用 one-dimensional 的字符串语法:

String html = "<html>\n" +
              "<body>\n" +
              "<p>Hello, world</p>\n" +
              "</body>\n" +
              "</html>\n";

应用 two-dimensional 文本块语法:

String html = """
              <html>
                  <body>
                      <p>Hello, world</p>
                  </body>
              </html>
              """;
SQL

应用 one-dimensional 的字符串语法:

String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
               "WHERE `CITY` ='INDIANAPOLIS'\n" +
               "ORDER BY `EMP_ID`, `LAST_NAME`;\n";

应用 two-dimensional 文本块语法:

String query = """
               SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
               WHERE `CITY` = 'INDIANAPOLIS'
               ORDER BY `EMP_ID`, `LAST_NAME`;
               """;
多语言示例

应用 one-dimensional 的字符串语法:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval("function hello() {\n" +
                         "print('\"Hello, world\"');\n"+"}\n"+"\n"+"hello();\n");

应用 two-dimensional 文本块语法:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval("""
                         function hello() {print('"Hello, world"');
                         }
                         
                         hello();
                         """);

个性形容

文本块是 Java 语言的新语法,能够用来示意任何字符串,具备更高的表达能力和更少的复杂度。

文本块的结尾定界符是由三个双引号字符(”””)组成的序列,前面跟 0 个或多个空格,最初跟一个行终止符。内容从结尾定界符的行终止符之后的第一个字符开始。

完结定界符是三个双引号字符的序列。内容在完结定界符的第一个双引号之前的最初一个字符处完结。

与字符串文字中的字符不同,文本块的内容中能够间接蕴含双引号字符。容许在文本块中应用 \“,但不是必须的或不倡议应用。

与字符串文字中的字符不同,内容能够间接蕴含行终止符。容许在文本块中应用 \n,但不是必须或不倡议应用。例如,文本块:

"""
line 1
line 2
line 3
"""

等效于字符串文字:

"line 1\nline 2\nline 3\n"

或字符串文字的串联:

"line 1\n" +
"line 2\n" +
"line 3\n"

379: Shenandoah: 低暂停工夫的垃圾收集器

JEP 379: Shenandoah: A Low-Pause-Time Garbage Collector (Production)

个性形容

Shenandoah GC 由 JEP 189 集成到 JDK 12 中。当初,Shenandoah GC 曾经能够用于生产环境了!(Shenandoah GC 的具体个性当前会有专门的文章解说,本篇文章略过)。

381: 删除 Solaris 和 SPARC Ports

JEP 381: Remove the Solaris and SPARC Ports

删除了对 Solaris/SPARC、Solaris/x64 和 Linux/SPARC 端口反对的源代码,并从新构建 JDK。这些代码在 JDK 14 中曾经被标记为废除的,并明确示意在将来版本中会删除。

383: 内部存储器拜访 API (Second Incubator)

JEP 383: Foreign-Memory Access API (Second Incubator)

引入新的能使 Java 程序平安高效拜访 Java 堆内存之外的内部内存的 API。

384: Records (Second Preview)

JEP 384: Records (Second Preview)

通过 Records(不晓得如何翻译,囧……)加强 Java 编程语言。Records 提供了一种紧凑的语法来申明类,这些类是浅层不可变数据的通明持有者。

为什么须要此个性

咱们常常听到这样的埋怨:“Java 太简短”、“Java 规定过多”。首当其冲的就是充当简略汇合的“数据载体”的类。为了写一个数据类,开发人员必须编写许多低价值、反复且容易出错的代码:构造函数、拜访器、equals()、hashCode()和 toString()等等。

只管 IDE 能够帮忙开发人员编写数据载体类的绝大多数编码,然而这些代码依然简短。

从外表上看,将 Records 是为了简化模板编码而生的,然而它还有“远大”的指标:modeling data as data。records 应该更简略、简洁、数据不可变。

形容

records 是 Java 的一种新的类型。同枚举一样,records 也是对类的一种限度。records 放弃了类通常享有的个性:将 API 和示意解耦。然而作为回报,records 使数据类变得十分简洁。

一个 record 具备名称和状态形容。状态形容申明了 record 的组成部分。例如:

record Point(int x, int y) {}

因为 records 在语义上是数据的简略通明持有者,所以记录会主动获取很多规范成员:

  • 状态申明中的每个成员,都有一个 private final 的字段;
  • 状态申明中的每个组件的公共读取拜访办法,该办法和组件具备雷同的名字;
  • 一个公共的构造函数,其签名与状态申明雷同;
  • equals 和 hashCode 的实现;
  • toString 的实现。

限度

records 不能扩大任何类,并且不能申明公有字段以外的实例字段。申明的任何其余字段都必须是动态的。

records 类都是隐含的 final 类,并且不能是抽象类。这些限度使得 records 的 API 仅由其状态形容定义,并且当前不能被其余类实现或继承。

在 record 中额定申明变量

也能够显式申明从状态形容主动派生的任何成员。能够在没有正式参数列表的状况下申明构造函数(这种状况下,假设与状态形容雷同),并且在失常构造函数主体失常实现时调用隐式初始化(this.x=x)。这样就能够在显式构造函数中仅执行其参数的验证等逻辑,并省略字段的初始化,例如:

record Range(int lo, int hi) {
  public Range {if (lo > hi)  /* referring here to the implicit constructor parameters */
      throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi));
  }
}

语法

RecordDeclaration:
  {ClassModifier} record TypeIdentifier [TypeParameters] 
    (RecordComponents) [SuperInterfaces] [RecordBody]

RecordComponents:
  {RecordComponent {, RecordComponent}}

RecordComponent:
  {Annotation} UnannType Identifier

RecordBody:
  {{RecordBodyDeclaration} }

RecordBodyDeclaration:
  ClassBodyDeclaration
  RecordConstructorDeclaration

RecordConstructorDeclaration:
  {Annotation} {ConstructorModifier} [TypeParameters] SimpleTypeName
    [Throws] ConstructorBody

反射 API

上面的办法会被加到 java.lang.Class 中:

  • RecordComponent[] getRecordComponents()
  • boolean isRecord()

385: 废除 RMI Activation

JEP 385: Deprecate RMI Activation for Removal

RMI Activation 机制标记为废除,以便在未来的某个版本删除掉。RMI Activation 是 RMI 的过期局部,然而这并不示意会弃用 RMI 的其余局部。

总结

以上就是 JDK 15 的全副新个性,咱们能够看到 G1 GC 曾经退出历史舞台,新的 ZGCShenandoah GC 曾经登上历史舞台。同时也抛弃了像 自旋锁 这种历史包袱,减少了许多诸如 文本块 等简洁的语法个性。咱们能够预感 Java 的性能会越来越好,同时也会越来越简洁。(当然简洁水平跟 Kotlin 这种新兴语言是比不了的,毕竟齐全没有历史包袱)。欢送大家关注我的公众号。

公众号

coding 笔记、点滴记录,当前的文章也会同步到公众号(Coding Insight)中,心愿大家关注 ^_^

代码和思维导图在 GitHub 我的项目中,欢送大家 star!

正文完
 0