JDK 10 的新特性和加强功能

本文是对底部参考资料的整理获得的,因为本人技术水平和英语水平都不是很高,有些词若有翻译错误或句子的理解错误还请指出。

JEP 286 局部变量推断: var

传统的 Java 代码中,声明一个变量是很是繁琐的:html

List<String> list = new ArrayList<String>();

如今则引入了 var,既保持 Java 对静态类型安全的承诺,又能让开发者省略没必要要的局部变量类型的声明。java

好比像这样:程序员

var list = new ArrayList<String>();

var 只能用在如下状况:算法

  • 声明的同时赋值,好比上面那个例子
  • 加强的 for 循环中的索引 (这将在后面提到)
  • 传统 for 循环中声明的本地变量

它不能被用于方法签名、构造器声明、方法返回类型、字段、异常捕获或任何其余类型的变量声明。数组

类型推断在 Java 8 中已经获得了显著的扩展,包括了对嵌套和连接的泛型方法的推导以及 lambda 表达式的推导,好比下面这样:安全

int maxWeight = blocks.stream()
                    .filter(b -> b.getColor() == BLUE)
                    .mapToInt(Block::getWeight)
                    .max();

没有必要去在乎 blocks.stream*() 返回的是 Stream<Block>,也不用在乎 filterlambda 表达式的参数类型没有被显式声明,由于它们都能经过类型推导获得。oracle

对于局部类型变量,类型推导是很是有用的,由于一般状况下均可以写成下面这种代码:框架

var path = Paths.get(fileName);
var bytes = Files.readAllBytes(path);

可是要注意的是,var 并非一个关键字,而是一个保留的类型名称,这意味着你能够将一个变量、方法、包名写成 var 。不过通常状况下不会有人这么写的,由于这自己就违反了广泛的命名规范。工具

var 不能用来声明没有赋值的变量、不能用于声明多个变量的状况、不能声明具备额外纬度的数组或引用了正在初始化的其余变量的变量。oop

JEP 322 基于时间的版本号管理

JEP 223 引入的版本号方案相比以前的方法都要好不少,可是对于如今 Java 所走的 六个月节奏 并不适合。

JEP 223 的问题在于,版本号中编码了它和它对以前版本的兼容性信息。可是在 六个月节奏 的状况下,这些信息都是未知的,在发布前任何事情均可能发生,由此 JEP 223 规范下的版本号也会是未知的。

JEP 223 的语义中,每一个基于 JDK 构建或使用组件的开发者(包括 JDK 的发布者)都必须提早敲定版本号,而后切换过去。而库、框架和工具的开发者则必须在代码中修改检查版本号的相关代码,这形成了混乱。

更多关于 JEP 322 的详细状况请访问这里

core-libs/java.util Optional.orElseThrow() 方法

这次更新中为 Optional 类添加了一个新的方法,这个方法与 orElseThrow(exSupplier) 是不一样的,它没有参数。

Optional.get() 是一个容易误导程序员的方法,它实际上有可能抛出 NoSuchElementException 运行时异常,所以须要一个语义明确的方法来帮助程序员清楚的认识到本身在作什么。

在以前的规划中,Optional.getWhenPresent() 是一个备选方法,虽然这个名字强调了值必定会存在,可是其中的 when 彷佛会让人以为这是个阻塞方法。所以最后委员会选择了 Optional.orElseThrow(),可是 Optional.get() 并无被单纯得弃用。

Unicode 标签扩展

加强了 java.util.Locale 和相关 API 以实现关于 BCP 47 语言标签Unicode 扩展。

详情请访问这里

core-libs/java.util 建立不可变集合的一系列 API

新的 API 中包括了一些用于建立不可见集合的方法:

List.copyOfSet.copyOfMap.copyOf() 能够用来从已有的集合中建立一个新的集合;

toUnmodifiableListtoUnmodifiableSettoUnmodifiableMap 则存在于 Stream.Collectors 类中,经过它们能够将流的元素收集到一个不可变集合当中。

copyOf 系列的方法签名基本是下面这样:

static <T> List <T> copyOf (Collection <? extends T> coll)

SetMap 也会有相似的方法。

值得注意的是,这个方法会检测 coll 是否是一个 不可变 的集合,若是是,则会直接返回该引用,至关于一个浅拷贝。

另外对于不可变集合而言,下面这种状况是被容许的:

List <String> list = List.of(...);
List <CharSequence> newList = List.copyOf(list);

这对于可变集合而言是不容许的,由于这可能会致使堆污染。

core-svc/java.lang.management 用于关闭 JRE Last Usage Tracking 的系统属性

引入了新的 jdk.disableLastUsageTracking 属性以禁用 JVMJRE 上次使用状况追踪 功能。

若是使用了此属性,那么 com.oracle.usagetracker.track.last.usage 的设置将被忽略。

core-svc/java.lang.management 开箱即用的 JMX 代理使用的散列密码

在之前,JMX 存储的是明文密码,当时 (2014 年) 你们已经开始手动生成散列密码来替换明文密码,由于这能够避免一些攻击,同时盐 (salt) 的存在可让散列密码的强度更上一层。可是对于管理员而言,即便是使用诸如 Python 之类的脚本语言来生成散列密码,这仍然是极容易出错的。所以最好的办法是用户只须要提供明文密码,让 JMX 来处理散列之类的事情。

JMX 如今会使用密码的 SHA3-512 散列结果来覆盖存储在 jmxremote.password 中的明文密码。

其格式以下:

role_name W hashedPassword

其中:

  • role_name 是任何不含空格或制表符的字符串
  • W 是一个空格或制表符

散列密码的格式以下:

hashedPassword = base64_encoded_64_byte_salt W base64_encoded_hash W hash_algorithm

其中:

  • base64_encoded_64_byte_salt 是 64字节的随机值
  • base64_encoded_hashHash_algorithm(password + salt) 的结果
  • W 是一个空格或制表符
  • hash_algorithm列表 中指定的算法名称。这是个可选项,默认值为 SHA3-512

若是密码是明文的,且知足如下条件,那么将被散列值覆盖

  1. management.properties 文件中 com.sun.management.jmxremote.password.toHashes 属性被设为 true
  2. 密码文件是可写的
  3. 安全管理器处于打开状态的状况下系统安全策略容许对密码文件进行写入

若是想更改角色的密码,能够将旧的散列密码替换为新的明文密码或新的散列密码。若是新的密码是明文的,那么在新的登陆发生时系统会使用其散列值替换明文密码。

文件中的角色应该至少有一条记录,不然该角色将无权访问;若是同一个用户下有多条记录,那么会使用最后一条记录。

用户能够自行根据上述的格式来生成的散列值,以替换旧的密码。

文件被拥有者之外的用户访问时将致使错误并退出程序。

为了防止在生产环境中对密码文件进行了无心的编辑,建议只部署可读的散列密码文件。明文密码的散列密码列表能够用 JMX 代理预先生成。

JMX 运行期间,建议不要编辑密码文件。程序会对文件的完整性作一个保护,所以修改既可能丢失。

hotspot/gc JEP 307 G1 的 彻底并行 GC

G1 垃圾收集器就是为了不 彻底 GC (full collections) , 可是当并行收集没法快速回收内存时,会产生一次 彻底回退 GC (fall back full GC) 。

以前 G1彻底GC 使用的是单线程标记扫描压缩算法(mark-sweep-compact),如今经过 JEP 307彻底GC 得以并行化,同时如今会使用与 年轻代混合收集 相同的并行工做线程数量。

security-libs/java.security JEP 319 根证书

OpenJDK 中的 cacerts 密钥库在至关长一段时间内是空的,这将致使未指定 javax.net.ssl.trustStore 属性的状况下 TLS 链接 的建立会被阻止。如今OracleJava SE 根证书 被填充至 OpenJDKcacerts 中。

security-libs/javax.net.ssl TLS 会话散列主密钥扩展 的支持

在是一个对 RFC 7627 的支持。

若是出现兼容问题,能够将 jdk.tls.useExtendedMasterSecret 设置为 false 来禁用此扩展的协商。

若是 jdk.tls.allowLegacyResumption 值为 false,当会话散列和主密钥扩展未协商的状况下,程序能够拒绝简短握手。

若是 jdk.tls.allowLegacyMasterSecret 值为 false,应用将拒毫不支持此扩展的链接。

tools/javac 加强 for 循环的字节码生成

以前的 for 循环在遍历一个大的列表/数组时,它会隐式得持有一个临时引用,并且这个临时引用不会被释放以致于可能产生 OutOfMemoryError 异常,详细的状况能够查看这里

对于下面的 Java 代码:

List<String> data = new ArrayList<>();
for (String b : data);

将会被编译为:

{
    /*synthetic*/
    Iterator i$ = data.iterator();
    for (; i$.hasNext(); ) {
        String b = (String) i$.next();
    }
    b = null;
    i$ = null;
}

这意味着 GC 能够发现再也不被使用的 i$ 所占用的内存并回收它,这对于数组也是适用的。

tools/javadoc(tool) javadoc 支持多个样式表

新的 javadoc 命令行选项 --add-stylesheet ,它支持在生产的文档中使用多个样式表。

而现有的选项 -stylesheetfile 有了一个别名 stylesheetfile --main-stylesheet,用以区分主样式表和其余样式表,更多信息能够查看 javadoc 文档

tools/javadoc(tool) 覆写没有改变规范的方法

默认状况下,若是有方法覆写了超类中的方法,那么 javadoc 会为它生成文档。

可是若是一个方法只是被覆写可是没有改变语义行为时,javadoc 只会在原方法摘要中用 @inheritdoc 标记它。

如今新的选项 --overridden-methods=value 能够将许多 不改变规范的覆写方法 与其余继承而来的方法分组,而不是在类的声明中与其余方法一块儿被记录在文档中。

tools/javadoc(tool) API 描述中摘要的注释标记

{@summary ...} 是一个新的行内标记。默认状况下,会经过简单算法或 java.text.BreakIterator 对描述中的第一句话进行判断以肯定 API 描述内容的摘要,可是这种方法可能会对第一句话结尾有错误的判断,所以新的标签能够显式得指定 API 的描述摘要。

参考资料

相关文章
相关标签/搜索