Java 10特性是什么?

Java 10是其23年历史上发展速度最快的Java版本。长期以来,Java因其发展缓慢而受到批评,但Java 10打破了这一观念。Java 10是一个拥有许多未来化变化的版本,其范围和影响可能不太明显,但却具有深远的意义。在本文中,我们将讨论Java 10版本中添加的各种功能。在此之前,让我们回顾一下Java发布模型引入的一些变化。

长期支持模式

2017年起,Oracle和Java社区宣布将Java迁移到新的6个月发布周期。它转向了长期支持(LTS)模式,为Oracle Java SE产品提供了持久且优质的支持。这意味着什么?产品的LTS版本将得到Oracle的首要和持续支持,每3年发布一次。每个Java版本都模仿一个或两个主要特性,这些特性推动了发布进度。任何障碍都会延迟发布并导致市场推出较晚。Java 9的一个重要特性是Project Jigsaw,它延迟了发布日期多次,推迟了1.5年以上。6个月的发布周期将遵循一个发布计划。发布计划每6个月更新一次。符合要求的特性将被纳入计划,否则它们将等待下一个计划的发布。

Oracle JDK与Open JDK之间的比较

为了更加开发者友好,Oracle和Java社区现在推广OpenJDK二进制文件作为未来的主要JDK。相比以前,这是一个巨大的解脱,因为JDK二进制文件以前是Oracle专有和许可的,受到了各种重新分发的限制。然而,Oracle将继续制作他们的JDK,但只为长期支持版本提供支持。这是向更云和容器友好的一步,因为开源JDK二进制文件可以作为容器的一部分进行分发。这是什么意思呢?OpenJDK二进制文件将每6个月发布一次,而Oracle JDK二进制文件将每3年发布一次(LTS版本)。哪个JDK二进制文件将被采用?大型组织需要时间来在不同版本之间迁移;他们会一直保留旧版本直到能够迁移为止。Java 6的工业采用比Java 7更多,然后工业逐渐转向Java 8。在我看来,LTS版本将是企业最青睐的版本。然而,到底是Oracle JDK的LTS版本还是OpenJDK的LTS版本尚不得而知,部分原因是云空间发生了许多变化。Java 9和10是非LTS版本。Java 11计划在2018年9月发布,将是LTS版本。

Java 10的特性

让我们来偷偷看看Java 10中可用的功能吧。

    基于时间的发布版本控制(JEP 322)

随着时间为基础的发布周期的采用,Oracle 改变了 Java SE 平台和 JDK 的版本字符串方案,以及与当前和未来时间为基础的发布模型相关的版本信息。新的版本号模式为:$FEATURE.$INTERIM.$UPDATE.$PATCH

$FEATURE:该计数器每6个月递增一次,并基于特性发布版本,例如 JDK 10,JDK 11。

$INTERIM:该计数器用于非特性发布,包含兼容的错误修复和功能增强,但没有不兼容的更改。通常,这个值为零,因为在六个月的周期内不会有中间发布。这个计数器保留供将来版本修订使用。

$UPDATE:该计数器用于兼容性更新发布,修复新功能中的安全问题、回归问题和错误。该计数器在特性发布后一个月更新,之后每三个月更新一次。例如,2018年4月的发布版本是JDK 10.0.1,7月的发布版本是JDK 10.0.2,依此类推。

$PATCH:该计数器用于紧急发布,以修复关键问题。新增了一些API以便通过程序获取这些计数器的值。让我们来看一下。

Version version = Runtime.version();
version.feature();
version.interim();
version.update();
version.patch();

现在,让我们来看一下返回版本信息的Java启动程序。

$ java -version
java version "10" 2018-03-20
Java(TM) SE Runtime Environment 18.3 (build 10+46)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+46, mixed mode)

版本号格式为“10”,因为除零以外没有其他计数器。发布日期被添加了进来。18.3可以理解为2018年的第3个月,构建编号10+46表示第10个版本的第46个构建。对于假设的JDK 10.0.1的第93个构建,构建编号将为10.0.1+939。局部变量类型推断(JEP 286)。

在Java 10中,本地变量类型推断是开发人员最重要的新功能。它为具有初始值的本地变量声明添加了类型推断。本地类型推断只能在以下情况下使用:

  • Limited only to Local Variable with initializer
  • Indexes of enhanced for loop or indexes
  • Local declared in for loop

让我们来看一下它的使用方法:

var numbers = List.of(1, 2, 3, 4, 5); // inferred value ArrayList<String>
// Index of Enhanced For Loop
for (var number : numbers) {
	System.out.println(number);
}
// Local variable declared in a loop
for (var i = 0; i < numbers.size(); i++) {
	System.out.println(numbers.get(i));
}

您可以在我们关于Java 10本地变量类型推断的专属帖子中了解更多相关信息。13. ###实验性Java JIT编译器(JEP 317)。

这个功能使得基于Java的JIT编译器Graal能够在Linux/x64平台上作为试验性的JIT编译器使用。这绝对是Java 10功能清单中最具未来感的一项。Graal在Java 9中被引入。它是我们一直以来使用的JIT编译器的替代方案。它是JVM的插件,这意味着JIT编译器与JVM没有绑定,可以动态地插入和替换任何符合JVMCI(Java级JVM编译器接口)的插件。它还为Java世界带来了静态编译(Ahead of Time,AOT)编译。它还支持多语言解释。”一个用Java编写的基于Java的即时编译器,用于将Java字节码转换为机器代码。”这是否令人困惑?如果JVM是用Java编写的,那么你不是需要一个JVM来运行JVM吗?JVM可以编译AOT,然后在JVM内部使用JIT编译器来通过实时代码优化提高性能。Graal是用Java完全从头开始重写的JIT编译器。之前的JIT编译器是用C++编写的。它被认为是任何编程语言进化的最后阶段之一。你可以通过以下JVM参数切换到Graal:

-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler

你可以从Chris Seaton的演讲中了解更多关于Graal的信息。

这个特性有助于改善启动时的占用空间,将现有的Class-Data Sharing(“CDS”)特性扩展到允许将应用程序类放置在共享归档文件中。在启动JVM时,会执行一些预备步骤,其中之一是将类加载到内存中。如果有多个包含多个类的JAR文件,则首次请求的延迟明显可见。这对于无服务器架构来说成为一个问题,因为启动时间至关重要。为了缩短应用程序的启动时间,可以使用应用程序类数据共享功能。其思想是通过在不同的Java进程之间共享常见的类元数据来减少占用空间。可以通过以下三个步骤实现:确定要归档的类:使用Java启动器创建一个文件列表来进行归档,可以通过以下参数实现:

$java -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=hello.lst -cp hello.jar HelloWorld

创建AppCDS存档:使用Java启动器来创建用于应用程序CDS的文件列表存档,可以通过以下参数实现:

$java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=hello.lst -XX:SharedArchiveFile=hello.jsa -cp hello.jar

使用AppCDS存档:使用以下参数的Java启动器来使用应用程序CDS。

$java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa -cp hello.jar HelloWorld
    G1的并行全垃圾回收(JEP 307)

G1垃圾收集器在JDK 9中成为默认设置。G1垃圾收集器避免了任何全量垃圾收集,但当用于收集的并发线程无法快速恢复内存时,用户的体验会受到影响。这个改动通过将完整的GC并行化来改善G1的最坏情况延迟。作为这个改动的一部分,G1收集器中的标记-清扫-压缩算法也被并行化,并且将在并发线程无法快速恢复内存时触发。

这个JEP是一种具有未来感的变化。它通过引入一个通用的垃圾回收接口来改善不同垃圾回收器的代码隔离性。这个变化为内部GC代码提供了更好的模块化。它将有助于在未来添加新的GC而不需要改变现有的代码库,也有助于移除或清理之前的GC。

此功能加强了java.util.Locale和相关API,以实现BCP 47语言标签的附加Unicode扩展。从Java SE 9开始,支持的BCP 47 U语言标签扩展是“ca”和“nu”。此JEP将添加对以下附加扩展的支持:

  • cu (currency type)
  • fw (first day of week)
  • rg (region override)
  • tz (time zone)

为了支持这些额外的扩展,各种API进行了更改,以提供基于U或其他扩展的信息。

java.text.DateFormat::get*Instance
java.text.DateFormatSymbols::getInstance
java.text.DecimalFormatSymbols::getInstance
java.text.NumberFormat::get*Instance
java.time.format.DateTimeFormatter::localizedBy
java.time.format.DateTimeFormatterBuilder::getLocalizedDateTimePattern
java.time.format.DecimalStyle::of
java.time.temporal.WeekFields::of
java.util.Calendar::{getFirstDayOfWeek,getMinimalDaysInWeek}
java.util.Currency::getInstance
java.util.Locale::getDisplayName
java.util.spi.LocaleNameProvider
    根证书(JEP 319)

为了推广OpenJDK并使其对社区用户更具吸引力,该功能为JDK提供了一组默认的根证书颁发机构(CA)证书。这也意味着Oracle和Open JDK的二进制文件在功能上将是相同的。关键的安全组件,如TLS,将默认在OpenJDK构建中正常工作。30. ###线程本地握手(JEP 312)

这是一个内部的JVM功能,旨在提高性能。握手操作是为每个JavaThread在它处于安全点状态时执行的回调。该回调可以由线程本身执行,也可以由VM线程在保持线程阻塞状态时执行。这个特性提供了一种在不进行全局VM安全点的情况下,在线程上执行回调的方式。使得停止单个线程变得可能且廉价,而不仅仅是所有线程或没有线程。 ### 使用替代内存设备进行堆分配(JEP 316)

应用程序对内存需求日益增加,云原生应用程序、内存数据库、流媒体应用程序也在增加。为了适应这些服务,现有各种内存架构可供选择。这个功能增强了HotSpot VM的能力,可以将Java对象堆分配在用户指定的替代内存设备(如NV-DIMM)上。这个JEP的目标是替代内存设备具有DRAM相同的语义,包括原子操作的语义,因此可以在对象堆中替代DRAM使用,无需对现有应用程序代码进行任何更改。32. ### 移除本地头生成工具 – javah (JEP 313)

这是对JDK进行的一项清理性改变,即将javah工具从JDK中移除。该工具的功能已经在JDK 8中作为javac的一部分添加进去,能够在编译时生成本机头文件,因此使得javah变得无用。### 将JDK Forest合并为一个单一仓库(JEP 296)。

多年来,JDK代码库中存在各种不同的Mercurial代码库。不同的代码库提供了一些优势,但也存在各种操作上的不足。作为这一变化的一部分,JDK代码库的许多代码库被合并成一个单一的代码库,以简化和优化开发流程。 36.### API变更

Java 10 在 API 上增加和删除了一些内容(是的,这不是拼写错误)。Java 9 引入了加强版弃用机制,标记了一些要在未来版本中删除的 API。被删除的 API:你可以在这里找到被删除的 API。新增的 API:Java 10 新增了 73 个 API。你可以在这里找到新增的 API,并进行对比。接下来我们看看其中的几个新增内容。

  • List, Map & Set Interfaces are added with a static copyOf(Collection) method. Its returns an unmodifiable List, Map or Set containing the entries provided. For a List, if the given List is subsequently modified, the returned List will not reflect such modifications.
  • Optional & its primitive variations get a method orElseThrow(). This is exactly same as get(), however the java doc states that it is a preferred alternative then get()
  • Collectors class gets various methods for collecting unmodifiable collections (Set, List, Map)
List<String> actors = new ArrayList<>();
actors.add("Jack Nicholson");
actors.add("Marlon Brando");
System.out.println(actors); // prints [Jack Nicholson, Marlon Brando]
// New API added - Creates an UnModifiable List from a List.
List<String> copyOfActors = List.copyOf(actors);
System.out.println(copyOfActors); // prints [Jack Nicholson, Marlon Brando]
// copyOfActors.add("Robert De Niro"); Will generate an
// UnsupportedOperationException
actors.add("Robert De Niro");
System.out.println(actors);// prints [Jack Nicholson, Marlon Brando, Robert De Niro]
System.out.println(copyOfActors); // prints [Jack Nicholson, Marlon Brando]
		
String str = "";
Optional<String> name = Optional.ofNullable(str);
// New API added - is preferred option then get() method
name.orElseThrow(); // same as name.get()  

// New API added - Collectors.toUnmodifiableList
List<String> collect = actors.stream().collect(Collectors.toUnmodifiableList());
// collect.add("Tom Hanks"); // Will generate an
// UnsupportedOperationException

结论

在本文中,我们详细介绍了Java 10的不同新功能添加。如果你认为有什么重要的被忽略了,请通过评论告诉我们。像往常一样,你可以在GitHub上查看完整的代码。

发表回复 0

Your email address will not be published. Required fields are marked *


广告
将在 10 秒后关闭
bannerAds