Java SE 10 新增特性

作者:Grey

原文地址:Java SE 10 新增特性

源码

源仓库: Github:java_new_features

镜像仓库: GitCode:java_new_features

类型推断

无需定义变量类型,通过var关键字结合初始化的值,可以推测出变量类型

package git.snippets.jdk10;

/**
* 类型推断
*
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/8/17
* @since 10
*/
public class TypeRefEnhance {
public static void main(String[] args) {
var a = 2; // a表示int
System.out.println(a);
var b = "hello"; // b 表示String
System.out.println(b);
var date = new java.util.Date();
System.out.println(date);
var obj = new Customer("Grey"); // 自定义对象
System.out.println(obj);
var sum = new TypeRefEnhance().add(1, 23);
System.out.println(sum);
var var = 3;
System.out.println(var);
} public int add(int a, int b) {
return a + b;
} static class Customer {
String name; public Customer(String n) {
name = n;
} @Override
public String toString() {
return "Customer{" +
"name=" + name +
'}';
}
}
}

var 看似好用,但是请谨慎使用,比如

var x = someFunction()

是因为如果不追踪someFunction()方法的返回类型,读者就不可能知道x的类型。多年来,人们对动态类型语言提出了类似的抱怨。

所以,记住我们的目标是编写可读的代码。

在Java中,var是一个特殊的新类型,你仍然可以在你的代码的其他地方使用var,比如作为一个变量或类名。这使得Java能够与Java 10之前的代码保持向后兼容,所以如下定义是没问题的

var var = 3;

不可变集合 API

如下代码

package git.snippets.jdk10;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; /**
* 集合API增强
*
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2021/11/29
* @since 10
*/
public class CollectionEnhance {
public static void main(String[] args) {
var vegetables = new ArrayList<>(List.of("Brocolli", "Celery", "Carrot"));
var unmodifiable = Collections.unmodifiableList(vegetables);
vegetables.set(0, "Radish");
var v = unmodifiable.get(0);
// 以下这行会报错
unmodifiable.set(0, "XXX");
System.out.println(v);
System.out.println(unmodifiable);
}
}

根据Java 10Collections的最新定义,unmodifiableList返回一个不可修改的视图集合。所以unmodifiable.set(0, "XXX");会直接报错

Exception in thread "main" java.lang.UnsupportedOperationException
at java.base/java.util.Collections$UnmodifiableList.set(Collections.java:1308)
at git.snippets.jdk10.CollectionEnhance.main(CollectionEnhance.java:22)

Java 10增加了两个新的API来实现这一点,也就是说,创建完全不能修改的集合。

第一个APIcopyOf,用来制作集合的不可修改的副本。

    static void copyOfTest() {
var list = List.of("a", "b", "c");
var copyList = List.copyOf(list);
list.add("d");
// 由于copyList是副本, 所以copyList不会受到list的影响,打印出[a,b,c]
System.out.println(copyList);
System.out.println(list);
// 由于是不可变集合,所以这里会报错
copyList.add("d");
}

这与用Collections.unmodifiableList包装一个列表是不同的。 copyOf是创建副本(源集合改变不会影响副本集合),而Collections.unmodifiableList是生成视图(源集合改变会影响视图)。

第二个APIStream包中的Collectors类增加的三个新方法。现在你可以使用toUnmodifiableListtoUnmodifiableSettoUnmodifiableMap在生成一个不可修改的集合。代码如下

    static void unmodifiedTest() {
List<String> list = List.of("b", "a", "b", "c");
List<String> c1 = list.stream().collect(Collectors.toUnmodifiableList());
System.out.println(c1);
// 会报错
// c1.add("c");
// System.out.println(c1);
Set<String> c2 = list.stream().collect(Collectors.toUnmodifiableSet());
System.out.println(c2);
// 会报错
// c2.add("a");
// System.out.println(c2);
// 会报错
// c2.add("e");
// System.out.println(c2);
}

注意,虽然这些方法的名字可能会让你想起Collections.unmodifiableList等,但这些新方法产生的是真正的不可修改的列表,而Collections.unmodifiableList则返回一个不可修改的视图。

Unicode 语言标签扩展

Java SE 10实现了最新的LDML 规范中指定的更多的扩展。

主要增加了下面几个扩展方法。

java.time.temporal.WeekFields::of
java.util.Calendar::{getFirstDayOfWeek,getMinimalDaysInWeek}
java.util.Currency::getInstance
java.util.Locale::getDisplayName
java.util.spi.LocaleNameProvider
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

尝试一下。

package git.snippets.jdk10;

import java.util.Calendar;
import java.util.Currency;
import java.util.Locale; /**
* unicode扩展
* @since 10
*/
public class UnicodeTest {
public static void main(String[] args) {
Currency chinaCurrency = Currency.getInstance(Locale.CHINA);
Currency usCurrency = Currency.getInstance(Locale.US);
System.out.println("本地货币:" + chinaCurrency);
System.out.println("US.货币:" + usCurrency); String displayName = Locale.getDefault().getDisplayName();
String displayLanguage = Locale.getDefault().getDisplayLanguage();
String displayCountry = Locale.getDefault().getDisplayCountry();
System.out.println("本地名称:" + displayName);
System.out.println("本地语言:" + displayLanguage);
System.out.println("本地国家:" + displayCountry);
int firstDayOfWeek = Calendar.getInstance().getFirstDayOfWeek();
System.out.println("本地每周第一天:" + firstDayOfWeek);
}
}

输出结果。

本地货币:CNY
US.货币:USD
本地名称:中文 (中国)
本地语言:中文
本地国家:中国
本地每周第一天:1

G1 性能增强

早在 Java 9 时就已经引入了 G1 垃圾收集器,G1 的优点很多。而在 Java 10 中还是做了小小调整,当 G1 的并发收集线程不能快速的完成全 GC 时,就会自动切换到并行收集,这可以减少在最坏情况下的 GC 速度。

类数据共享

Java SE 5引入了类数据共享(CDS),以改善小型Java应用程序的启动时间。

JVM第一次启动时,由引导类加载器加载的任何东西都被序列化并存储在磁盘上的一个文件中,可以在JVM的未来启动中重新加载。这意味着JVM的多个实例共享类元数据,因此它不必每次都加载它们。

共享数据缓存意味着小型应用程序的启动时间有了很大的改善,因为在这种情况下,核心类的相对大小要大于应用程序本身。

Java SE 10将此扩展到包括系统类加载器和平台类加载器。为了利用这一点,你只需要添加以下参数

-XX:+UseAppCDS

Java SE 10还允许你把你自己的应用程序特定的类也存储到类-数据共享缓存中,可能会减少你的启动时间。

基本上,这是一个三步走的过程。第一步是创建应该被归档的类的列表,用适当的标志启动你的应用程序,并指出你希望列表被存储的位置。

java -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=myapp.lst \
-cp $CLASSPATH $MAIN_CLASS

然后,用这个清单,你将创建一个CDS档案

java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=myapp.lst \
-XX:SharedArchiveFile=myapp.jsa \
-cp $CLASSPATH

最后,运行你的应用程序,使用该存档

java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa \
-cp $CLASSPATH $MAIN_CLASS

更多内容参考:JEP 310: Application Class-Data Sharing

新的即时编译器Graal

即时编译器(JIT)是Java的一部分,它在运行时将Java字节码转换为机器代码。最初的JIT编译器是用C++编写的,现在被认为相当难以修改。

Java SE 9引入了一个新的实验性接口,称为JVM编译器接口或JVMCI。新接口的设计使得用纯Java重写JIT编译器成为可能。Graal是由此产生的JIT编译器,完全用Java编写。

Graal目前是一个实验性的JIT编译器。在未来的Java版本之前,只有Linux/x64机器可以使用它。要启用Graal,请在启动应用程序时在命令行参数中添加这些标志。

-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler

更多内容参考:graalvm

Thread-Local Handshakes

在服务性操作中,比如为所有线程收集堆栈跟踪或执行垃圾回收,当JVM需要暂停一个线程时,它需要停止所有线程。有时,这些被称为 "stop-the-world"的暂停。这是由于JVM想要创建一个全局安全点,一旦JVM完成工作,所有应用线程都可以从这个安全点重新开始。

但在Java SE 10中,JVM可以将任意数量的线程放入安全点,并且线程在执行规定的 "握手"后可以继续运行。这导致JVM一次只需暂停一个线程,而以前则必须暂停所有线程。

更多参考:JEP 312: Thread-Local Handshakes

容器感知

JVM现在知道它何时在Docker容器内运行。这意味着应用程序现在拥有关于docker容器分配给内存、CPU和其他系统资源的准确信息。

以前,JVM会查询主机操作系统来获得这些信息,这就造成了一个问题。

例如,假设你想创建一个基于Javadocker镜像,其中运行的JVM被分配了容器所指定的25%的可用内存。在一个拥有2G内存的盒子上,运行一个配置为0.5G内存的容器,Java SE 9和更早的版本会错误地根据2G的数字而不是0.5G来计算Java进程的堆大小。

但是,现在,在Java SE 10中,JVM能够从容器控制组(cgroups)中查找这些信息。

有一些命令行选项可以指定Docker容器内的JVM如何分配内部内存。例如,为了将内存堆设置为容器组的大小,并限制处理器的数量,你可以传入这些参数

-XX:+UseCGroupMemoryLimitForHeap -XX:ActiveProcessorCount=2

随着容器成为部署服务的标准方式,这意味着开发者现在有一种基于容器的方式来控制他们的Java应用如何使用资源。

指定替代的内存分配

通过允许用户指定替代的内存设备来分配堆,Java正朝着更加异构的内存系统发展。

一个直接的用例是能够在非易失性DIMMNVDIMM)模块上分配堆,这在大数据应用中是常用的。

另一个用例是在同一台机器上运行许多JVM进程。在这种情况下,让那些需要较低读取延迟的进程映射到DRAM上,其余的进程映射到NVDIMM上。

可以在你的启动参数中添加如下标志

-XX:AllocateHeapAt=<path>

这里的path通常是一个内存映射的目录。

更多

Java SE 7及以后各版本新增特性

参考资料

Java Language Updates

Java 新特性教程

What’s New in Java 10?

Java 10 Features (with Examples)

Java 10 Features and Enhancements

New Features in Java 10

graalvm

JEP 310: Application Class-Data Sharing

Java 10

Java SE 10 新增特性的更多相关文章

  1. Java SE 8 新增特性

    Java SE 8 新增特性 作者:Grey 原文地址: Java SE 8 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new_ ...

  2. Java SE 9 新增特性

    Java SE 9 新增特性 作者:Grey 原文地址: Java SE 9 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new_ ...

  3. Java SE 11 新增特性

    Java SE 11 新增特性 作者:Grey 原文地址:Java SE 11 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  4. Java SE 12 新增特性

    Java SE 12 新增特性 作者:Grey 原文地址:Java SE 12 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  5. Java SE 13 新增特性

    Java SE 13 新增特性 作者:Grey 原文地址:Java SE 13 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  6. Java SE 17 新增特性

    Java SE 17 新增特性 作者:Grey 原文地址:Java SE 17 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  7. Java SE 19 新增特性

    Java SE 19 新增特性 作者:Grey 原文地址: 博客园:Java SE 19 新增特性 CSDN:Java SE 19 新增特性 源码 源仓库: Github:java_new_featu ...

  8. Java SE 14 新增特性

    Java SE 14 新增特性 作者:Grey 原文地址:Java SE 14 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  9. Java SE 15 新增特性

    Java SE 15 新增特性 作者:Grey 原文地址:Java SE 15 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

随机推荐

  1. 用HMS Core地图服务自定义地图样式,给你的应用制作专属个性化地图

    不同行业的开发者对地图样式的展示需求差异很大.例如,物流类应用希望地图样式简洁一些,重点突出城市分布和快递路径:AR游戏类应用中的地图色彩需要和游戏UI适配,做的更酷炫一些:景区导览应用中的地图样式要 ...

  2. 中国程序员容易发错音的单词「GitHub 热点速览 v.22.23」

    中国程序员容易发错音的单词,像极了学生时代的纠错本,收录着偶尔会忘记的单词.不过,它似乎更新频率跟不上我们的进步速度,至少一半以上的单词读起来是没有压力的.同样没有压力的还有让应用程序动起来的 aut ...

  3. JAVA - 序列化的方式

    JAVA - 序列化的方式 序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后,可以通过从存储区中读 ...

  4. ffmpeg使用总结

    2021-07-21 初稿 截图 ffmpeg -i <video> -ss <time> -vframes 1 <output_pic> 设置视频封面 ffmpe ...

  5. Java注解和反射

    1.注解(Annotation) 1.1.什么是注解(Annotation) 注解不是程序本身,可以在程序编译.类加载和运行时被读取,并执行相应的处理.注解的格式为"@注释名(参数值)&qu ...

  6. Javaweb-IDEA 中Maven的操作

    1. 在idea中使用Maven 启动idea 创建一个MavenWeb项目 3.等待项目初始化完毕 4. 观察maven仓库中多了哪些东西 5. idea中的maven设置 注意:idea项目创成功 ...

  7. js中通过ajax调用网上接口

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  8. 【python基础】第10回 周总结

    路径 可以简单的理解为路径就是某个事物所在的具体位置(坐标) 1.相对路径:必须有一个参考系,就是相对于自己的目标文件的位置. 2.绝对路劲:不需要有参考系,是指文件在硬盘上真正存在的路径. 计算机五 ...

  9. vi与vim使用

    简介 Vi是一个命令行界面下的文本编辑工具(最早1976年由Bill Joy开发,原名ex),vi 支持就大多数操作系统(最早在BSD上发布)并且功能已经十分强大. 1991年Bram Moolena ...

  10. 端口被占用的问题解决 Web server failed to start. Port ×× was already in use

    出现此问题是端口被占用了,只需要关闭正在使用的端口就行 解决思路: 1.在服务器中更改port端口号,改为不冲突,没有被占用的端口. 2.找出被占用的端口,结束被占用的端口 解决结束被占用的端口的方法 ...