JDK11新特性

目录

  • 传送门
  • 前言
  • 一、Dynamic Class-File Constants
  • 二、局部变量类型推断升级
  • 三、新增字符串处理方法
  • 四、移除的一些内容
    • 1、移除项
    • 2、废弃项
  • 五、更简化的编译运行程序
  • 六、Unicode 10
  • 七、移除JavaEE和CORBA模块
  • 八、废弃Nashorn JavaScript引擎
  • 九、废弃Pack20工具和API
  • 十、Epsilon垃圾收集器
  • 十一、ZGC垃圾收集器
  • 十二、支持G1上的并行完全垃圾收集
  • 十三、免费的低耗能飞行记录仪和堆分析仪
  • 十四、两种加密算法
  • 十五、新的默认根权限证书集
  • 十六、Java Flight Recorder
  • 十七、Optional加强

传送门

JDK8新特性
JDK9新特性
JDK10新特性
JDK11新特性
JDK12新特性
JDK13新特性
JDK14新特性
JDK15新特性
JDK16新特性
JDK17新特性
JDK18新特性
JDK19新特性
JDK20新特性
JDK21新特性

前言

北京时间 2018 年 9 月 26 日,Oracle 官方宣布 Java 11 正式发布。这是 Java 大版本周期变化后的第一个长期支持版本,非常值得关注。从官网即可下载,最新发布的 Java11 将带来 ZGC、Http Client 等重要特性,一共包含 17 个 JEP(JDK Enhancement Proposals,JDK 增强提案)。

JDK 11 将是一个 企业不可忽视 的版本。从时间节点来看,JDK 11 的发布正好处在 JDK 8 免费更新到期的前夕,同时 JDK 9、10 也陆续成为 历史版本。

JDK 更新很重要吗?非常重要,在过去的很多年中,Oracle 和 OpenJDK 社区提供了接近免费的午餐,导致人们忽略了其背后的海量工作和价值,这其中包括但不仅仅限于:最新的安全更新,如,安全协议等基础设施的升级和维护,安全漏洞的及时修补,这是 Java 成为企业核心设施的基础之一。大量的新特性、Bug 修复,例如,容器环境支持,GC 等基础领域的增强。很多生产开发中的 Hack,其实升级 JDK 就能解决了。不断改进的 JVM,提供接近零成本的性能优化…

JDK 11 是一个长期支持版本(LTS, Long-Term-Support)
对于企业来说,选择 11 将意味着长期的、可靠的、可预测的技术路线图。其中免费的 OpenJDK11 确定将得到 OpenJDK 社区的长期支持,LTS 版本将是可以放心选择的版本。

从 JVM GC 的角度,JDK11 引入了两种新的 GC,其中包括也许是划时代意义的 ZGC,虽然其目前还是实验特性,但是从能力上来看,这是 JDK 的一个巨大突破,为特定生产环境的苛刻需求提供了一个可能的选择。例如,对部分企业核心存储等产品,如果能够保证不超过 10ms 的 GC 暂停,可靠性会上一个大的台阶,这是过去我们进行 GC 调优几乎做不到的,是能与不能的问题。
JDK11新特性_第1张图片
对于 G1 GC,相比于 JDK 8,升级到 JDK 11 即可免费享受到:并行的 Full GC,快速的 CardTable 扫描,自适应的堆占用比例调整(IHOP),在并发标记阶段的类型卸载等等。这些都是针对 G1 的不断增强,其中串行 Full GC 等甚至是曾经被广泛诟病的短板,你会发现 GC 配置和调优在 JDK11 中越来越方便。

云计算时代的监控、诊断和 Profiling 能力,这个是相比 ZGC 更具生产实践意义的特性。
Java 的应用场景跨度很大,从单机长时间运行的 Java 应用,发展成为分布式、大的单体应用或小的 function、瞬时或长时间运行等,应用场景非常复杂。
我们用什么工具诊断 Java 应用?

JDK 11 为我们提供了更加强大的基础能力,主要是两部分:
第一部分JEP 328:Flight Recorder(JFR) :是 Oracle 刚刚开源的强大特性
JFR 是一套集成进入 JDK、JVM 内部的事件机制框架,通过良好架构和设计的框架,硬件层面的极致优化,生产环境的广泛验证,它可以做到极致的可靠和低开销。在 SPECjbb2015 等基准测试中,JFR 的性能开销最大不超过 1%,所以,工程师可以基本没有心理负担地在大规模分布式的生产系统使用,这意味着,我们既可以随时主动开启 JFR 进行特定诊断,也可以让系统长期运行 JFR,用以在复杂环境中进行「After-the-fact」分析。
在保证低开销的基础上,JFR 提供的能力可以应用在对锁竞争、阻塞、延迟,JVM GC、SafePoint 等领域,进行非常细粒度分析。甚至深入 JIT Compiler 内部,全面把握热点方法、内联、逆优化等等。JFR 提供了标准的 Java、C++ 等扩展 API,可以与各种层面的应用进行定制、集成,为复杂的企业应用栈或者复杂的分布式应用,提供 All-in-One 解决方案。
而这一切都是内建在 JDK 和 JVM 内部的,并不需要额外的依赖,开箱即用。
**简单概括:**飞行记录仪 记录问题,监控诊断问题,以前收费现在开源。

第二部分JEP 331: Low-Overhead Heap Profiling
它来源于 Google 等业界前沿厂商的一线实践,通过获取对象分配细节,为 JDK 补足了对象分配诊断方面的一些短板,工程师可以通过 JVMTI 使用这个能力增强自身的工具。
简单概括:补充分析工具,主要是对堆分析。

从 Java 类库发展的角度来看,JDK 11 最大的进步也是两个方面:
第一,HTTP/2 Client API,新的 HTTP API 提供了对 HTTP/2 等业界前沿标准的支持,精简而又友好的 API 接口,与主流开源 API(如,Apache HttpClient, Jetty, OkHttp 等)对等甚至更高的性能。与此同时它是 JDK 在 Reactive-Stream 方面的第一个生产实践,广泛使用了 Java Flow API 等,终于让 Java 标准 HTTP 类库在扩展能力等方面,满足了现代互联网的需求。
第二,就是安全类库、标准等方面的大范围升级,其中特别是 JEP 332: Transport Layer Security (TLS) 1.3,除了在安全领域的重要价值,它还是中国安全专家范学雷所领导的 JDK 项目,完全不同于以往的修修补补,是个非常大规模的工程。

除此之外,JDK 还在逐渐进行瘦身工作,或者偿还 JVM、Java 规范等历史欠账,例如:
335: Deprecate the Nashorn JavaScript Engine
它进一步明确了 Graal 很有可能将成为 JVM 向前演进的核心选择,Java-on-Java 正在一步步的成为现实。

一、Dynamic Class-File Constants

这是类文件新添的一种结构。具体看官方的介绍:http://openjdk.java.net/jeps/309
Java 的类型文件格式将被拓展,支持一种新的常量池格式:CONSTANT_Dynamic,加载 CONSTANT_Dynamic 会将创建委托给 bootstrap 方法。
其目标是降低开发新形式的可实现类文件约束带来的成本和干扰

二、局部变量类型推断升级

在 var 上添加注解的语法格式,在 Java10 中是不能实现的。在 Java11 中加入了这样的语法。

在声明隐式类型的 lambda 表达式的形参时允许使用 var,使用 var 的好处是在使用 lambda 表达式时给参数加上注解,如下:

// 引入var形参前面可以加注解了,当然用String代替var也可以
Consumer<String> consumer = (@Deprecated var x, @Nullable var y) -> x.process(y);

因为不使用 var 的话,是会报错 非法的表达式开始,如下:

Consumer<String> consumer = (@Deprecated x, @Nullable y) -> x.process(y);// 会报错

三、新增字符串处理方法

判断字符串是否为空白 isBlank()

public void test() {
    String str = "\t \r\n ";
    // 判断字符串的内容是否都是空白
    System.out.println(str.isBlank()); // 输出:true
    System.out.println(str.isEmpty());// 输出:false
}

去除首尾空白 strip()
和 trim() 的区别在于,strip() 去除字符串首尾的空白,包括英文和其他所有语言中的空白字符(范围更大,更好用);而 trim() 去除字符串首尾的空白,只能去除码值小于等于 32 的空白字符,如中文空格无法去除。

public void test() {
    // 去除字符串首尾的空白,包括英文和其他所有语言中的空白字符
    String str1 = " youngkbt.cn ".strip();
    System.out.println(str1); // 输出:youngkbt.cn

    // 去除字符串首尾的空白,只能去除码值小于等于 32 的空白字符,如中文空格无法去除
    String str2 = " youngkbt.cn ".trim();
    System.out.println(str2); // 输出:youngkbt.cn
}

去除尾部空白 stripTrailing()
相比较 strip(),只是去除了尾部的空白。

public void test() {
    // 去除字符串尾部的空白
    String str = " youngkbt.cn ".stripTrailing();
    System.out.println(str1); // 输出: youngkbt.cn
}

去除首部空白 stripLeading()
相比较 strip(),只是去除了首部的空白。

public void test() {
    // 去除字符串首部的空白
    String str = " youngkbt.cn ".stripLeading();
    System.out.println(str1); // 输出:youngkbt.cn 
}

复制字符串 repeat()

public void test() {
    // 复制字符串 3 次
    String str = "youngkbt.cn".repeat(3);
    System.out.println(str1); // 输出:youngkbt.cnyoungkbt.cnyoungkbt.cn
}

行数统计 lines().count()
注意是行数的统计,而不是字数的统计。

public void test() {
    long count = "ABC".lines().count();
    System.out.println(count); // 输出:1
    
    long count = "A\nB\nC".lines().count();
    System.out.println(count); // 输出:3
}

lines() 有一个很有用的用途,就是读取文件的内容,如:

public void test() {
  FileInputStream fis = new FileInputStream("文件路径");
    byte[] buffer = new byte[fis.available()];
    fis.read(buffer);
    fis.close();
    
    String str = new String(buffer);
    str.lines().forEach(System.out::println);
}

str.lines()返回的是Stream流。

四、移除的一些内容

1、移除项

移除了 com.sun.awt.AWTUtilities
移除了 sun.misc.Unsafe.defineClass,使用 java.lang.invoke.MethodHandles.Lookup.defineClass来替代
移除了 Thread.destroy() 以及 Thread.stop(Throwable) 方法
移除了 sun.nio.ch.disableSystemWideOverlappingFileLockCheck、sun.locale.formatasdefault 属性
移除了 jdk.snmp 模块
移除了 javafx,OpenJDK 在 Java10 版本就移除了,但是 Oracle JDK10 还尚未移除 javafx,而 Oracle JDK11 版本移除了 javafx
移除了 Java Mission Control,从 JDK 中移除之后,需要自己单独下载
移除了这些 Root Certificates:Baltimore Cybertrust Code Signing CA,SECOM,AOL and Swisscom

2、废弃项

-XX+AggressiveOpts 选项(侵略性的选项)
-XX:+UnlockCommercialFeatures 选项(解锁商业性特征,例如飞行记录仪不用再加这个指令了,可以直接用)
-XX:+LogCommercialFeatures 选项(日志商业特征,GC统一用Log了,这个指令也不用了)

五、更简化的编译运行程序

EP 330: 增强 Java 启动器支持运行单个 Java 源代码文件的程序。
在 Java 11 之前,我们要想运行一个 Java 文件,首先利用 javac 将 Java 文件编译处 Class 文件,再 java来运行 Class 文件,而在 Java 11 中,我们可以直接使用 java 对一个 Java 文件运行,不需要编译成 Class 文件,也不会在目录下生成 Class 文件。
注意点:
● 执行源文件中的类可以有多个,但是第一个类必须包含主方法
● 并且不可以使用别的源文件中的自定义类,本文件中的自定义类是可以使用的
● 不会生成Class文件了
假设有一个 Java 文件,在命令行使用 java TestJava.java 就会输出 Hello,Java 11,内容如下:

public class TestJava {
    public static void main(String[] args) {
        System.out.println("Hello,Java 11");
    }
}

如果是Java 11之前,先要编译 javac TestJava.java,然后运行 java TestJava 。

六、Unicode 10

Unicode 10 增加了 8518 个字符,总计达到了 136690 个字符。并且增加了 4 个脚本.同时还有 56 个新的 emoji 表情符号。
因此 Java11 新增了四个 Java 文件(注意截图为JDK17,在JDK11中没有CharacterData03)
JDK11新特性_第2张图片

七、移除JavaEE和CORBA模块

在 Java11 中移除了不太使用的 JavaEE 模块和 CORBA 技术。
CORBA 来自于二十世纪九十年代,Oracle 说,现在用 CORBA 开发现代 Java 应用程序已经没有意义了,维护 CORBA 的成本已经超过了保留它带来的好处。
但是删除 CORBA 将使得那些依赖于 JDK 提供部分 CORBA API 的 CORBA 实现无法运行。目前还没有第三方 CORBA 版本,也不确定是否会有第三方愿意接手 CORBA API 的维护工作。
在 Java11 中将 Java9 标记废弃的 Java EE 及 CORBA 模块移除掉,具体如下:

java.xml.ws
java.xml.bind
java.xml.ws
java.xml.ws.annotation
jdk.xml.bind
jdk.xml.ws
    
java.corba
java.se.ee
java.activation
java.transactio

只剩下 java.xml,java.xml.crypto,jdk.xml.dom 这几个模块。但是 Java 11 新增一个 java.transaction.xa 模块。

八、废弃Nashorn JavaScript引擎

废除 Nashorn javascript 引擎,在后续版本准备移除掉,有需要的可以考虑使用 GraalVM。

九、废弃Pack20工具和API

Java5 中带了一个压缩工具:Pack200,这个工具能对普通的 jar 文件进行高效压缩。其实现原理是根据 Java 类特有的结构,合并常数池,去掉无用信息等来实现对 Java 类的高效压缩。由于是专门对 Java 类进行压缩的,所以对普通文件的压缩和普通压缩软件没有什么两样,但是对于 Jar 文件却能轻易达到 10% - 40% 的压缩率。这在 Java 应用部署中很有用,尤其对于移动 Java 计算,能够大大减小代码下载量。
Java5 中还提供了这一技术的 API 接口,你可以将其嵌入到你的程序中使用。使用的方法很简单,下面的短短几行代码即可以实现 jar 的压缩和解压:

// 压缩
Packer packer = Pack200.newPacker(); 
OutputStream output = new BufferedOutputStream(new FileOutputStream(outfile)); 
packer.pack(new JarFile(jarFile), output); 
output.close(); 

// 解压
Unpacker unpacker = Pack200.newUnpacker(); 
output = new JarOutputStream(new FileOutputStream(jarFile)); 
unpacker.unpack(pack200File, output); 
output.close();

Pack200 的压缩和解压缩速度是比较快的,而且压缩率也是很惊人的,在我是使用的包 4.46MB 压缩后成了 1.44MB(0.322%),而且随着包的越大压缩率会根据明显,据说如果 jar 包都是 Class 类可以压缩到 1/9 的大小。其实 Java WebStart 还有很多功能,例如可以按不同的 jar 包进行 lazy 下载和单独更新,设置可以根据 jar 中的类变动进行 Class 粒度的下载。
但是在 Java11 中废除了 Pack200 以及 Unpack200 工具以及 java.util.jar 中的 Pack200 API。因为 Pack200 主要是用来压缩 jar 包的工具,由于网络下载速度的提升以及 Java9 引入模块化系统之后不再依赖 Pack200,Pack200反而会带来一些额外的开销,因此这个版本将其移除掉

十、Epsilon垃圾收集器

A NoOp Garbage Collector。
JDK 对这个特性的描述是:开发一个处理内存分配但不实现任何实际内存回收机制的 GC,一旦可用堆内存用完,JVM 就会退出。
如果有 System.gc() 调用,实际上什么也不会发生(这种场景下和 -XX:+DisableExplicitGC:禁用 GC 效果一样),因为没有内存回收,这个实现可能会警告用户尝试强制 GC 是徒劳。

使用方法:-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC
注意:两个参数要一起使用

class Garbage {
    int n = (int)(Math.random() * 100);
    // 这个方法是GC在清楚本对象时,会调用一次
    @Override
    public void finalize() {
        System.out.println(this + " : " + n + " is dying");
    }
}
public class EpsilonTest {

    public static void main(String[] args) {
        boolean flag = true;
        List<Garbage> list = new ArrayList<>();
        long count = 0;
        while (flag) {// 死循环,内存不够用的时候不一定触发GC,但是报OOM退出JVM,程序结束。
            list.add(new Garbage());
            if (list.size() == 1000000 && count == 0) {
                list.clear();// list一旦clear,之前加入的对象就会变成垃圾对象。
                count++;
            }
        }
        System.out.println("程序结束");
    }
}

上面程序默认在JDK11下,默认使用G1去垃圾回收,由于不断地死循环产生垃圾对象和G1中途不定时在回收垃圾对象,所以程序运行时间比较久,最后还是因为死循环OOM退出JVM,程序结束。
如果使用选项 -XX:+UseEpsilonGC(上面两个参数要一起用),程序很快就因为堆空间不足而退出(时间很短,程序很快就结束了),因为该 Epsilon并不会进行垃圾回收。

使用这个选项的原因:
提供完全被动的 GC 实现,具有有限的分配限制和尽可能低的延迟开销,但代价是内存占用和内存吞吐量。
众所周知,Java 实现可广泛选择高度可配置的 GC 实现。各种可用的收集器最终满足不同的需求,即使它们的可配置性使它们的功能相交。有时更容易维护单独的实现,而不是在现有 GC 实现上堆积另一个配置选项。

简单概括:就是没有垃圾回收,程序运行效率非常高,但是不能有内存溢出,一旦溢出程序就挂了。

主要用途:
● 性能测试(它可以帮助过滤掉 GC 引起的性能假象,让问题很快暴露出来)
● 内存压力测试(例如,知道测试用例应该分配不超过 1GB 的内存,我们可以使用-Xmx1g 和 –XX:+UseEpsilonGC,如果程序有问题,则程序会崩溃,说明有内存泄漏)
● 非常短的 JOB 任务(对像这种任务,接受 GC 清理堆那都是浪费空间,就可以给设置Epsilon)
● VM 接口测试(虚拟机的接口测试)
● Last-drop 延迟 & 吞吐改进(实现性质,对于JVM调优很有帮助)

十一、ZGC垃圾收集器

GC 是 Java 主要优势之一。然而,当 GC 停顿太长,就会开始影响应用的响应时间.消除或者减少 GC 停顿时长,Java 将对更广泛的应用场景是一个更有吸引力的平台。此外,现代系统中可用内存不断增长,用户和程序员希望 JVM 能够以高效的方式充分利用这些内存,并且无需长时间的 GC 暂停时间。
ZGC:A Scalable Low-Latency Garbage Collector(Experimental),这应该是 JDK11 最为瞩目的特性,没有之一。但是后面带了 Experimental,说明这还不建议用到生产环境。
特点:

  • GC 暂停时间不会超过 10ms
  • 既能处理几百兆的小堆,也能处理几个 T 的大堆(OMG)
  • 和 G1 相比,应用吞吐能力不会下降超过 15%
  • 为未来的 GC 功能和利用 colord 指针以及 Load barriers 优化奠定基础
  • 初始只支持 64 位系统

ZGC 的设计目标是:支持 TB 级内存容量,暂停时间低(<10ms),对整个程序吞吐量的影响小于 15%。 将来还可以扩展实现机制,以支持不少令人兴奋的功能,例如多层堆(即热对象置于 DRAM 和冷对象置于 NVMe 闪存),或压缩堆。
ZGC 是一个并发,基于 region,压缩型的垃圾收集器,只有 root 扫描阶段会 STW,因此 GC 停顿时间不会随着堆的增长和存活对象的增长而变长。
用法(两个都要使用):

  • -XX:+UnlockExperimentalVMOptions,因为 ZGC 还处于实验阶段,所以需要通过 JVM 参数来解锁这个特性
  • –XX:+UseZGC

十二、支持G1上的并行完全垃圾收集

对于 G1 GC,相比于 JDK 8,升级到 JDK 11 即可免费享受到:并行的 Full GC,快速的 CardTable 扫描,自适应的堆占用比例调整(IHOP),在并发标记阶段的类型卸载等等。这些都是针对 G1 的不断增强,其中串行 Full GC 等甚至是曾经被广泛诟病的短板,你会发现 GC 配置和调优在 JDK11 中越来越方便。

十三、免费的低耗能飞行记录仪和堆分析仪

低耗能飞行记录仪和堆分析仪通过 JVMTI 的 SampledObjectAlloc 回调提供一个低开销的,为了排错 Java 应用问题,以及 JVM 问题的数据收集框架。
希望达到的目标如下:

  • 提供用于生产和消费数据作为事件的API
  • 提供缓存机制和二进制数据格式
  • 允许事件配置和事件过滤
  • 提供 OS,JVM 和 JDK 库的事件

十四、两种加密算法

Java 11 实现了 RFC 7539 的 ChaCha20 and ChaCha20-Poly1305 加密算法 XECPublicKey 和 XECPrivateKey,代替 RC4。
RFC7748 定义的秘钥协商方案更高效,更安全。JDK 增加两个新的接口

// XECPublicKey 和 XECPrivateKey
KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH");
NamedParameterSpec paramSpec = new NamedParameterSpec("X25519");
kpg.initialize(paramSpec);
KeyPair kp = kgp.generateKeyPair();

KeyFactory kf = KeyFactory.getInstance("XDH");
BigInteger u = new BigInteger("xxx");
XECPublicKeySpec pubSpec = new XECPublicKeySpec(paramSpec, u);
PublicKey pubKey = kf.generatePublic(pubSpec);

KeyAgreement ka = KeyAgreement.getInstance("XDH");
ka.init(kp.getPrivate());
ka.doPhase(pubKey, true);
byte[] secret = ka.generateSecret();

十五、新的默认根权限证书集

Java 11 实现 TLS 协议 1.3 版本,TLS 允许客户端和服务器端通过互联网以一种防止窃听,篡改以及消息伪造的方式进行通信。

十六、Java Flight Recorder

Flight Recorder 源自飞机的黑盒子。
Flight Recorder 以前是商业版的特性,在 Java11 当中开源出来,它可以导出事件到文件中,之后可以用 Java Mission Control 来分析。可以在应用启动时配置 java -XX:StartFlightRecording,或者在应用启动之后,使用 jcmd 来录制,比如:

jcmd JFR.start,开启 Flight Recorder ,监听 Java 程序的 pid
jcmd JFR.dump filename=recording.jfr,将监听到的数据写入 JFR 文件,并继续监听新的数据
jcmd JFR.stop,关闭 Flight Recorder

Flight Recorder 是 Oracle 刚刚开源的强大特性。我们知道在生产系统进行不同角度的 Profiling,有各种工具、框架,但是能力范围、可靠性、开销等,大都差强人意,要么能力不全面,要么开销太大,甚至不可靠可能导致 Java 应用进程宕机。
而 JFR 是一套集成进入 JDK、JVM 内部的事件机制框架,通过良好架构和设计的框架,硬件层面的极致优化,生产环境的广泛验证,它可以做到极致的可靠和低开销。在 SPECjbb2015 等基准测试中,JFR 的性能开销最大不超过 1%,所以,工程师可以基本没有心理负担地在大规模分布式的生产系统使用,这意味着,我们既可以随时主动开启 JFR 进行特定诊断,也可以让系统长期运行 JFR,用以在复杂环境中进行“After-the-fact”分析。还需要苦恼重现随机问题吗?JFR 让问题简化了很多。
在保证低开销的基础上,JFR 提供的能力也令人眼前一亮,例如:我们无需 BCI 就可以进行 Object Allocation Profiling,终于不用担心 BTrace 之类把进程搞挂了。对锁竞争、阻塞、延迟,JVM GC、SafePoint 等领域,进行非常细粒度分析。甚至深入 JIT Compiler 内部,全面把握热点方法、内联、逆优化等等。JFR 提供了标准的 Java、C++ 等扩展 API,可以与各种层面的应用进行定制、集成,为复杂的企业应用栈或者复杂的分布式应用,提供 All-in-One 解决方案。而这一切都是内建在 JDK 和 JVM 内部的,并不需要额外的依赖,开箱即用。

十七、Optional加强

Optional 也增加了几个非常酷的方法,现在可以很方便的将一个 Optional 转换成一个 Stream,或者当一个空 Optional 时给它一个替代的。

JDK11新特性_第3张图片

public void test() {
  Optional<Object> op = Optional.empty();
    // 判断内部的 value 是否存在
    System.out.println(op.isPresent()); // 输出:false
    // 判断内部的 value 是否为空
    System.out.println(op.isEmpty()); // 输出:true
    
    op = Optional.of( "abc" ) ;
    // orELseThrow():value 非空,返回 value;否则抛异常 NoSuchELementException
    var obj = op.orElseThrow();
    System.out.println(obj);
  
    Optional<String> op1 = Optional.of( "hello" );
  // or:value 非空,返回对应的 optional;value 为空,返回形参封装的 optional
    Optional<object> op2 = op.or(() -> op1);
    System.out.println(op2); // sOptional[abc]
}

你可能感兴趣的:(java,spring,jvm,redis,开发语言)