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. .Net分表分库动态化处理

    介绍 本期主角:ShardingCore 一款ef-core下高性能.轻量级针对分表分库读写分离的解决方案,具有零依赖.零学习成本.零业务代码入侵 背景 最近有个小伙伴来问我,分表下他有一批数据,这个 ...

  2. 10个常见触发IO瓶颈的高频业务场景

    摘要:本文从应用业务优化角度,以常见触发IO慢的业务SQL场景为例,指导如何通过优化业务去提升IO效率和降低IO. 本文分享自华为云社区<GaussDB(DWS)性能优化之业务降IO优化> ...

  3. DevOps落地实践点滴和踩坑记录-(1)

    记录初衷 本人一直在从事企业内DevOps落地实践的工作,走了不少弯路,也努力在想办法解决面临的问题,期间也经历过不少人和事情,最近突然有想法把经历过的,不管好的不好的都记录下来,分享给和我一样的一线 ...

  4. ”只用 1 分钟“ - 超简极速 Apk 签名 & 多渠道打包神器

    众所周知,渠道包作为当下国内 Android 应用市场常见的分发方式,当 APP 和后台交互或进行数据上报时,会带上各自的 channel 渠道信息,以此方便企业 & 开发者统计 APP 在各 ...

  5. 【C#/VB.NET】 将PDF转为SVG/Image, SVG/Image转PDF

    SVG是一种图形文件格式,它的英文全称为Scalable Vector Graphics,意思为可缩放的矢量图形.它在放大或者改变尺寸的情况下其图形质量不会有所损失,且与 JPG 和 GIF 图像比起 ...

  6. mysql5.7安装要踩的坑

    因为官网下载的是绿色版,所以要做一些配置 1.在mysql根目录新增data文件夹和my.ini文件 my.ini文件内容 [mysql]# 设置mysql客户端默认字符集default-charac ...

  7. .NET6 开源之JSON 2 SQL (JORM框架)

    什么是JORM框架? 全称 :Json  Object Relational Mapping   ,它是通过JSON 对象 去实现数据库的一个关系映射 ,我理想中完整的JORM包含功能有 ·1.表权授 ...

  8. MySQL查询为什么没走索引?这篇文章带你全面解析

    工作中,经常遇到这样的问题,我明明在MySQL表上面加了索引,为什么执行SQL查询的时候却没有用到索引? 同一条SQL有时候查询用到了索引,有时候却没用到索引,这是咋回事? 原因可能是索引失效了,失效 ...

  9. @ConditionalOnMissingBean 如何实现覆盖第三方组件中的 Bean

    1. 自定义一个简单 spring-boot 组件 创建 olive-starter 项目 对应的 pom.xml文件如下 <project xmlns="http://maven.a ...

  10. 零基础学Java(11)自定义类

    前言   之前的例子中,我们已经编写了一些简单的类.但是,那些类都只包含一个简单的main方法.现在来学习如何编写复杂应用程序所需要的那种主力类.通常这些类没有main方法,却有自己的实例字段和实例方 ...