Java 10 最重要的 5 个新特性!

2020-06-01 16:08:00来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

Java 10 最重要的 5 个新特性!

局部变量类型推断是有争议的热点,但 Java 10 在 JVM 中的垃圾收集和容器识别上带来了可喜的变化。

关于本系列

所以你认为你了解 Java 编程? 事实是,大多数开发人员只是浮于 Java 平台的表面上,仅仅为了完成工作而学习。在这个正在进行的系列中,Java 技术深入挖掘了 Java 平台的核心功能,提出了一些技巧和诀窍,可以帮助你解决即使是最棘手的编程挑战。

Java? 开发人员已经习惯了等待新的 Java 版本发布,但是新的、高频率的发布节奏改变了这一情况。Java 9 出现之后仅仅过去 6 个月,现在 Java 10 已经在敲门了。再过 6 个月,我们将迎来 Java 11。一些开发人员可能会发现这样的快速发布是多余的,但是新的节奏标志着一个长期需求的改变。

与它的版本号一样,Java 10 提供了 10 个新特性,本文提供了我认为最重要的 5 个特性(您可以在 Open JDK 10 项目页面上查看它们)。

Java的新版本节奏

从历史上看,JDK 发行的节奏是由大的新特性驱动的。作为最近的例子,Java 8 以 lambda 和流的形式引入了函数式编程,而 Java 9 引入了模块化 Java 系统。每个新版本都被热切地期待着,但是次要的修复程序经常束之高阁,等待更大的组件版本被最终确定。Java 的进化落后于其他语言。

新的高频节奏将 Java 以更小的增量向前推进。在发布日期准备好的特性将被包括在内,而那些不能被安排在下一个版本中,就在 6 个月之后。在这个新周期下的第一个 Java 版本是 Java 9,它于 2017 年 10 月发布。Java 10 于 2018 年 3 月发布,Java 11 将于 2018 年 9 月发布。

作为新节奏的一部分,甲骨文表示,它将只支持每个主要版本,直到下一个主要版本发布为止。 当 Java 11 发布时,Oracle 将停止支持 Java 10。支持 Java 版本的开发人员必须每 6 个月迁移一次主要版本。 不希望或不需要频繁迁移的开发人员可以使用 LTS(长期支持)版本,该版本每三年更新一次。 目前的 LTS 版本 Java 8 将在今年秋季发布 Java 11 之前得到支持。

局部变量类型推断

局部变量类型推断是 Java 10 中最显着的特性。在进入 JDK 10 之前,争论非常激烈,该特性允许编译器推断局部变量的类型,而不是要求程序员明确指定它。

清单 1 显示了如何在 Java 10 之前定义一个String变量类型。

清单 1. 声明并分配一个 String 类型的变量

String?name?=?"Alex"

清单 2 展示了在 Java10 中定义与 String 类型相同的变量

清单 2. 用局部变量类型推断 String 类型的变量

var?name?=?"Alex";

正如你看到的,唯一的区别就是使用了 var 保留类型名称。使用右边的表达式,编译器可以将变量名的类型推断为 String。

这看起来有点简单,让我们来看一个更加复杂的例子。如果一个变量分配给了调用方法的返回值是怎样的?在这种情况下,编译器可以根据方法的返回类型推断变量的类型,如清单 3 所示。

清单 3. 从返回类型推断 String 类型

var?name?=?getName();

String?getName(){

????return?"Alex";

}

使用局部变量类型

顾名思义,局部变量类型推断功能仅适用于局部变量。 它不能用于定义实例或类变量,也不能用于方法参数或返回类型。 但是,您可以在类和增强型循环中使用 var,可以从迭代器中推断出类型,如清单 4 所示。

清单 4. 在循环中使用 var

for(var?book?:?books){}

for(var?i?=?0;?i?<?10;?i++){}

使用这种类型的最明显的原因是为了减少代码中的冗长。?看看清单 5 中的示例。

清单 5. 很长的类型名称使得代码很长

String?message?=?"Incy?wincy?spider...";

StringReader?reader?=?new?StringReader(message);

StreamTokenizer?tokenizer?=?new?StreamTokenizer(reader);

请注意,使用 var 保留类型名称重写清单5时发生了什么。

清单 6. var 类型减少了代码的冗长性

var?message?=?"Incy?wincy?spider...";

var?reader?=?new?StringReader(message);

var?tokenizer?=?new?StreamTokenizer(reader);

清单 6 中的类型声明是垂直排列的,并且在构造函数调用的右侧每个申明中都会提到一次类型。 想象一下使用这种类型在一些 Java 框架中常见的长类名的好处。

局部变量类型的问题

1. var 掩盖了类型

你已经看到了 var 如何提高代码的可读性,但是从另一方面来看,它也可以掩盖它。 看看清单7中的示例。

清单 7. 返回类型不清楚

var?result?=?searchService.retrieveTopResult();

在清单 7 中,我们必须猜测返回类型。 让读者猜测发生了什么的代码是难以维护的。

2. var 不能与 lambda 一起使用

与 lambda 表达式一起使用时,类型推断效果不佳,主要原因是编译器缺少类型信息。 清单8中的 lambda 表达式不会被编译。

清单 8. 类型信息不足

Function<String,?String>?quotify?=?m?->?"'"?+?message?+?"'";

var?quotify?=?m?->?"'"?+?message?+?"'";

在清单 8 中,编译器的右边表达式中没有足够的类型信息来推断变量类型。 Lambda 语句必须始终声明一个显式类型。

3. var 不会与菱形操作符混在一起

与菱形操作符一起使用时,类型推断也不能很好地工作。 看看清单 9 中的例子。

清单 9. 使用带有 var 的菱形运算符

var?books?=?new?ArrayList?<>();

亲自尝试一下

想要亲自尝试本地变量类型推断,您需要下载 JDK 10 和一个支持它的 IDE。 IntelliJ 的 EAP(Early Access Program)版本具有此支持。 一旦你下载并安装了它,你可以从本文附带的 GitHub 存储库中检出代码开始。 你会在那里找到局部变量类型推断的例子。

在代码清单 9 中,books 的 ArrayList 的参数类型是什么呢?你可能明白你是希望 ArrayList 存储一个书的列表,但是编译器不能推断出来。反之,编译器会做的唯一它能做的事情,就是推断出来这是一个参数是 Object类型ArrayList:ArrayList()。

另外一种方法就是在右端表达式中的菱形运算符中定义具体类型。然后你可以让编译器从而推断出来变量的类型,就像在代码清单 10 中写的一样。或者使用另外一种方式,即你必须明确地以传统方式声明变量:List books。事实上,你可能更喜欢这种方式,因为它能让你定义一个抽象类型,并对List接口编程:

清单 10. 定义出具体类型

var?books?=?new?ArrayList<Book>();

增加、删除和弃用

删除

Java 10 删除了很多工具:

● 命令行工具 javah,可以使用 javac -h 代替。

●?命令行选项 -X:prof,尽管可以使用 jmap 工具来访问分析信息。

●?政策工具。

一些从 Java1.2 开始标记的为已弃用的 API 也被永久删除了。包括 java.lang.SecurityManager.inCheck 字段和以下方法:

java.lang.SecurityManager.classDepth(java.lang.String)

java.lang.SecurityManager.classLoaderDepth()

java.lang.SecurityManager.currentClassLoader()

java.lang.SecurityManager.currentLoadedClass()

java.lang.SecurityManager.getInCheck()

java.lang.SecurityManager.inClass(java.lang.String)

java.lang.SecurityManager.inClassLoader()

java.lang.Runtime.getLocalizedInputStream(java.io.InputStream)

java.lang.Runtime.getLocalizedOutputStream(java.io.OutputStream)

弃用

JDK 10 也弃用了一些 API。 java.security.acl 包已标记为已弃用,也包括 java.security 包中包含各种相关的类(Certificate,Identity,IdentityScope,Singer,auth.Policy)。此外,javax.management.remote.rmi.RMIConnectorServer 类中的 CREDENTIAL_TYPES 被标记为不建议使用。 java.io.FileInputStream 和 java.io.FileOutputStream 中的 finalize()方法已被标记为已弃用。所以在 java.util.zip.Deflater / Inflater / ZipFileclasses 中的 finalize()方法也被弃用。

添加和包含

作为 Oracle JDK 和 Open JDK 正在进行对接的一部分,Open JDK 现在包含 Oracle JDK 中可用的一部分根证书颁发机构。这些包括 Java Flight Recorder 和 Java Mission Control。此外,JDK 10 在 java.text,java.time 和 java.util 包的适当位置中增加了对 BCP 47 语言标记的 Unicode 扩展的增强支持。另一项新功能允许在不执行全局 VM 安全点的情况下执行线程回调。这使停止单个线程既可行又便宜,而不是要求你停止所有线程或不需要任何线程。

提高容器意识

如果你部署到像 Docker 这样的容器,那么这个功能特别适合你。 现在 JVM 意识到它正在容器中运行,并查询容器中可用处理器的数量,而不是查询主机操作系统。 也可以从外部附加到在容器中运行的 Java 进程,这使监视 JVM 进程变得更加容易。

以前,JVM 不知道它的容器,并会向主机操作系统询问活动 CPU 的数量。?在某些情况下,这会导致 JVM过度报告资源,导致多个容器在同一操作系统上运行时出现问题。?在 Java 10 中,您可以将容器配置为使用主机操作系统的 CPU 的子集,并且 JVM 将能够确定正在使用的 CPU 数量。?您还可以使用 -XX:ActiveProcessorCount 标志明确指明能够看到的容器化 JVM 处理器数量。

应用程序类数据共享

此特性的用途是提高运行间和多个运行相同代码的 JVM 启动时间,同时减少内存占用量。 这通过在 JVM 之间共享关于类的元数据来实现。 JVM 的第一次运行收集并归档有关它所加载的类的数据。 然后它将数据文件提供给其他 JVM 以及该 JVM 的后续运行,从而节省 JVM 初始化过程中的时间和资源。 类数据共享实际上已经有一段时间了,但仅限于系统类。 现在这个功能已经扩展到包含所有的应用程序类。

结束语

Java10 中头号特性是把 Var 作为了新的类型名,它可以让代码更加简洁和清晰。但是,如果使用不谨慎也会掩盖住原来的含义和意图。当不明确含义的时候,IDE 或许可以帮助你辨别类型,但是在一个 IDE 中无法读取所有类型的代码。我们经常通过 GitHub 仓库、调试器或者代码审查工具在线阅读代码。开发者使用这个新的特性时,务必注意为了将来的读者和维护人员提高代码可读性。

Java 的新版本如此高频率发布是一个值得欢迎的改变。在发布日期,已经准备好的特性必须发布,那些延迟的特性将在短暂的调整之后再下个版本发布。新的循环将加快 Java 的发展进程,那些已经开发完成并且已经列出来的特性,开发者不需要等好多年。

从一个主要版本到下一个主要版本的发布的支持时间越来越短,这带来一些合理的担忧,但是 LTS 应该可以有效的缓解该问题。发布疲劳是另一个风险,因为开发者对频繁的版本更新感到厌烦。总的来说,我认为这是一个积极的行为,在未来很长的一段时间里,它有助于保证 Java 的活跃度和维持 Java 的发展。

摘自开源中国
译者:Tocy, 无若, 雪落无痕xdj, 琪花亿草

推荐去我的博客阅读更多:

1.Java JVM、集合、多线程、新特性系列教程

2.Spring MVC、Spring Boot、Spring Cloud 系列教程

3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程

4.Java、后端、架构、阿里巴巴等大厂最新面试题

觉得不错,别忘了点赞+转发哦!


原文链接:https://www.cnblogs.com/javastack/p/13024754.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:SpringBoot实现微信小程序登录的完整例子

下一篇:最新115道经典Java面试题及答案解析,快来看看你掌握了多少?