百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术流 > 正文

Java11、Java17、Java21

citgpt 2024-10-20 01:47 6 浏览 0 评论

1.Java11

  Java 11 于 2018 年 9 月 25 日正式发布,这是很重要的一个版本!Java 11 和 2017 年 9 月份发布的 Java 9 以及 2018 年 3 月份发布的 Java 10 相比,其最大的区别就是:在长期支持(Long-Term-Support)方面,Oracle 表示会对 Java 11 提供大力支持,这一支持将会持续至 2026 年 9 月。这是据 Java 8 以后支持的首个长期版本。

Java11、Java17、Java21

(1)HTTP Client 标准化

  Java 11 对 Java 9 中引入并在 Java 10 中进行了更新的 Http Client API 进行了标准化,在前两个版本中进行孵化的同时,Http Client 几乎被完全重写,并且现在完全支持异步非阻塞。并且,Java 11 中,Http Client 的包名由 jdk.incubator.http 改为java.net.http,该 API 通过 CompleteableFuture 提供非阻塞请求和响应语义。



var request = HttpRequest.newBuilder()

    .uri(URI.create("https://javastack.cn"))

    .GET()

    .build();

var client = HttpClient.newHttpClient();


// 同步

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

System.out.println(response.body());


// 异步

client.sendAsync(request, HttpResponse.BodyHandlers.ofString())

    .thenApply(HttpResponse::body)

    .thenAccept(System.out::println);


(2)String 增强

Java 11 增加了一系列的字符串处理方法:


//判断字符串是否为空

" ".isBlank();//true

//去除字符串首尾空格

" Java ".strip();// "Java"

//去除字符串首部空格

" Java ".stripLeading();   // "Java "

//去除字符串尾部空格

" Java ".stripTrailing();  // " Java"

//重复字符串多少次

"Java".repeat(3);             // "JavaJavaJava"

//返回由行终止符分隔的字符串集合。

"A\nB\nC".lines().count();    // 3

"A\nB\nC".lines().collect(Collectors.toList());


(3)Optional 增强

新增了isEmpty()方法来判断指定的 Optional 对象是否为空。


var op = Optional.empty();

System.out.println(op.isEmpty());//判断指定的 Optional 对象是否为空

(4)ZGC(可伸缩低延迟垃圾收集器)

ZGC 即 Z Garbage Collector,是一个可伸缩的、低延迟的垃圾收集器。ZGC 主要为了满足如下目标进行设计:

GC 停顿时间不超过 10ms

即能处理几百 MB 的小堆,也能处理几个 TB 的大堆

应用吞吐能力不会下降超过 15%(与 G1 回收算法相比)

方便在此基础上引入新的 GC 特性和利用 colored 针以及 Load barriers 优化奠定基础

当前只支持 Linux/x64 位平台

  ZGC 目前 处在实验阶段,只支持 Linux/x64 平台。与 CMS 中的 ParNew 和 G1 类似,ZGC 也采用标记-复制算法,不过 ZGC 对该算法做了重大改进。在 ZGC 中出现 Stop The World 的情况会更少!

ZGC(转正)

Java11 的时候 ,ZGC 还在试验阶段。


经过多个版本的迭代,不断的完善和修复问题,ZGC 在 Java 15 已经可以正式使用了!


不过,默认的垃圾回收器依然是 G1。你可以通过下面的参数启动 ZGC:


java -XX:+UseZGC className

2.Java17

  Java 17 在 2021 年 9 月 14 日正式发布,是一个长期支持(LTS)版本。Spring 6.x 和 Spring Boot 3.x 最低支持的就是 Java 17。这次更新共带来 14 个新特性:

JEP 306:Restore Always-Strict Floating-Point Semantics(恢复始终严格的浮点语义)JEP 356:Enhanced Pseudo-Random Number Generators(增强的伪随机数生成器)

JEP 382:New macOS Rendering Pipeline(新的 macOS 渲染管道)

JEP 391:macOS/AArch64 Port(支持 macOS AArch64)

JEP 398:Deprecate the Applet API for Removal(删除已弃用的 Applet API)

JEP 403:Strongly Encapsulate JDK Internals(更强大的封装 JDK 内部元素)

JEP 406:Pattern Matching for switch (switch 的类型匹配)(预览)

JEP 407:Remove RMI Activation(删除远程方法调用激活机制)JEP 409:Sealed Classes(密封类)(转正)

JEP 410:Remove the Experimental AOT and JIT Compiler(删除实验性的 AOT 和 JIT 编译器)JEP 411:Deprecate the Security Manager for Removal(弃用安全管理器以进行删除)

JEP 412:Foreign Function & Memory API (外部函数和内存 API)(孵化)

JEP 414:Vector(向量) API(第二次孵化)

JEP 415:Context-Specific Deserialization Filters(1)增强的伪随机数生成器

  JDK 17 之前,我们可以借助 Random、ThreadLocalRandom和SplittableRandom来生成随机数。不过,这 3 个类都各有缺陷,且缺少常见的伪随机算法支持。  

  Java 17 为伪随机数生成器 (pseudorandom number generator,PRNG,又称为确定性随机位生成器)增加了新的接口类型和实现,使得开发者更容易在应用程序中互换使用各种 PRNG 算法。


PRNG 用来生成接近于绝对随机数序列的数字序列。一般来说,PRNG 会依赖于一个初始值,也称为种子,来生成对应的伪随机数序列。

只要种子确定了,PRNG 所生成的随机数就是完全确定的,因此其生成的随机数序列并不是真正随机的。


RandomGeneratorFactory<RandomGenerator> l128X256MixRandom = RandomGeneratorFactory.of("L128X256MixRandom");

// 使用时间戳作为随机数种子

RandomGenerator randomGenerator = l128X256MixRandom.create(System.currentTimeMillis());

// 生成随机数

randomGenerator.nextInt(10);


(2)弃用 Applet API 以进行删除

Applet API 用于编写在 Web 浏览器端运行的 Java 小程序,很多年前就已经被淘汰了,已经没有理由使用了。


Applet API 在 Java 9 时被标记弃用(JEP 289),但不是为了删除。


(3)switch 的类型匹配(预览)

  正如 instanceof 一样, switch 也紧跟着增加了类型匹配自动转换功能。对于 null 值的判断也进行了优化(不用if,用 case null)。


instanceof

// Old code

if (o instanceof String) {

    String s = (String)o;

    ... use s ...

}

// New code

if (o instanceof String s) {

    ... use s ...

}


// New code

static String formatterPatternSwitch(Object o) {

    return switch (o) {

        case Integer i -> String.format("int %d", i);

        case Long l    -> String.format("long %d", l);

        case Double d  -> String.format("double %f", d);

        case String s  -> String.format("String %s", s);

        default        -> o.toString();

    };

}


(4)删除实验性的 AOT 和 JIT 编译器

  在 Java 9 的 JEP 295,引入了实验性的提前 (AOT) 编译器,在启动虚拟机之前将 Java 类编译为本机代码。


  Java 17,删除实验性的提前 (AOT) 和即时 (JIT) 编译器,因为该编译器自推出以来很少使用,维护它所需的工作量很大。保留实验性的 Java 级 JVM 编译器接口 (JVMCI),以便开发人员可以继续使用外部构建的编译器版本进行 JIT 编译。


(5)弃用安全管理器以进行删除

  弃用安全管理器以便在将来的版本中删除。安全管理器可追溯到 Java 1.0,多年来,它一直不是保护客户端 Java 代码的主要方法,也很少用于保护服务器端代码。为了推动 Java 向前发展,Java 17 弃用安全管理器,以便与旧版 Applet API ( JEP 398)一起移除。


(6)外部函数和内存 API(孵化)

  Java 程序可以通过该 API 与 Java 运行时之外的代码和数据进行互操作。通过高效地调用外部函数(即 JVM 之外的代码)和安全地访问外部内存(即不受 JVM 管理的内存),该 API 使 Java 程序能够调用本机库并处理本机数据,而不会像 JNI 那样危险和脆弱。


  外部函数和内存 API 在 Java 17 中进行了第一轮孵化,由 JEP 412提出。第二轮孵化由JEP 419 提出并集成到了 Java 18 中,预览由 JEP 424 提出并集成到了 Java 19 中。


(7)向量 API(第二次孵化)

  向量(Vector) API 最初由 JEP 338 提出,并作为孵化 API集成到 Java 16 中。第二轮孵化由 JEP 414 提出并集成到 Java 17 中,第三轮孵化由 JEP 417 提出并集成到 Java 18 中,第四轮由 JEP 426提出并集成到了 Java 19 中。

  该孵化器 API 提供了一个 API 的初始迭代以表达一些向量计算,这些计算在运行时可靠地编译为支持的 CPU 架构上的最佳向量硬件指令,从而获得优于同等标量计算的性能,充分利用单指令多数据(SIMD)技术(大多数现代 CPU 上都可以使用的一种指令)。尽管 HotSpot 支持自动向量化,但是可转换的标量操作集有限且易受代码更改的影响。该 API 将使开发人员能够轻松地用 Java 编写可移植的高性能向量算法。


3.Java21

JDK 21 于 2023 年 9 月 19 日 发布,这是一个非常重要的版本,里程碑式。


JDK21 是 LTS(长期支持版),至此为止,目前有 JDK8、JDK11、JDK17 和 JDK21 这四个长期支持版了。


JDK 21 共有 15 个新特性,这篇文章会挑选其中较为重要的一些新特性进行详细介绍:


(1)字符串模板(预览)

  String Templates 提供了一种更简洁、更直观的方式来动态构建字符串。通过使用占位符${},我们可以将变量的值直接嵌入到字符串中,而不需要手动处理。在运行时,Java 编译器会将这些占位符替换为实际的变量值。并且,表达式支持局部变量、静态/非静态字段甚至方法、计算结果等特性。

  Java 在没有 String Templates 之前,我们通常使用字符串拼接或格式化方法来构建字符串。这些方法或多或少都存在一些冗长、复杂。Java 使用 String Templates 进行字符串拼接,可以直接在字符串中嵌入表达式,而无需进行额外的处理。


//old code

message = "Greetings " + name + "!";

message = String.format("Greetings %s!", name);  //concatenation

message = new MessageFormat("Greetings {0}!").format(name);

message = new StringBuilder().append("Greetings ").append(name).append("!").toString();


//new code

String message = STR."Greetings \{name}!";


STR 是模板处理器。

\{name}为表达式,运行时,这些表达式将被相应的变量值替换。

Java 目前支持三种模板处理器:


STR:自动执行字符串插值,即将模板中的每个嵌入式表达式替换为其值(转换为字符串)。

FMT:和 STR 类似,但是它还可以接受格式说明符,这些格式说明符出现在嵌入式表达式的左边,用来控制输出的样式

RAW:不会像 STR 和 FMT 模板处理器那样自动处理字符串模板,而是返回一个 StringTemplate 对象,这个对象包含了模板中的文本和表达式的信息

除了 JDK 自带的三种模板处理器外,还可以实现 StringTemplate.Processor 接口来创建自己的模板处理器。

我们可以使用局部变量、静态/非静态字段甚至方法作为嵌入表达式:

message = STR."Greetings \{name}!";

message = STR."Greetings \{getName()}!";

message = STR."Greetings \{this.name}!";

还可以在表达式中执行计算并打印结果:

int x = 10, y = 20;

String s = STR."\{x} + \{y} = \{x + y}";  //"10 + 20 = 30"

为了提高可读性,我们可以将嵌入的表达式分成多行.

(2)序列化集合

  JDK 21 引入了一种新的集合类型:Sequenced Collections(序列化集合,也叫有序集合),这是一种具有确定出现顺序(encounter order)的集合(无论我们遍历这样的集合多少次,元素的出现顺序始终是固定的)。序列化集合提供了处理集合的第一个和最后一个元素以及反向视图(与原始集合相反的顺序)的简单方法。


Sequenced Collections 包括以下三个接口:


SequencedCollection、SequencedSet、SequencedMap

SequencedCollection 接口继承了 Collection接口, 提供了在集合两端访问、添加或删除元素以及获取集合的反向视图的方法。



interface SequencedCollection<E> extends Collection<E> {

  // New Method

  SequencedCollection<E> reversed();


  // Promoted methods from Deque<E>

  void addFirst(E);

  void addLast(E);


  E getFirst();

  E getLast();


  E removeFirst();

  E removeLast();

}


List 和 Deque 接口实现了SequencedCollection 接口。以 ArrayList 为例,演示一下实际使用效果:


ArrayList<Integer> arrayList = new ArrayList<>();

arrayList.add(1);   // List contains: [1]


arrayList.addFirst(0);  // List contains: [0, 1]

arrayList.addLast(2);   // List contains: [0, 1, 2]


Integer firstElement = arrayList.getFirst();  // 0

Integer lastElement = arrayList.getLast();  // 2


List<Integer> reversed = arrayList.reversed();

System.out.println(reversed); // Prints [2, 1, 0]


SequencedSet接口直接继承了 SequencedCollection 接口并重写了 reversed() 方法。

SortedSet 和 LinkedHashSet 实现了SequencedSet接口。

SequencedMap 接口继承了 Map接口, 提供了在集合两端访问、添加或删除键值对、获取包含 key 的 SequencedSet、包含 value 的 SequencedCollection、包含 entry(键值对) 的 SequencedSet以及获取集合的反向视图的方法。

SortedMap 和LinkedHashMap 实现了SequencedMap 接口。

(3)分代 ZGC

  JDK21 中对 ZGC 进行了功能扩展,增加了分代 GC 功能。不过,默认是关闭的,需要通过配置打开:

// 启用分代ZGC

java -XX:+UseZGC -XX:+ZGenerational ...

  在未来版本中,官方会把 ZGenerational 设为默认值,即默认打开 ZGC 的分代 GC。在更晚的版本中,非分代 ZGC 就被移除。分代 ZGC 可以显著减少垃圾回收过程中的停顿时间,并提高应用程序的响应性能。这对于大型 Java 应用程序和高并发场景下的性能优化非常有价值。


(4)switch 的模式匹配

  增强 Java 中的 switch 表达式和语句,允许在 case 标签中使用模式。当模式匹配时,执行 case 标签对应的代码。


  在下面的代码中,switch 表达式使用了类型模式来进行匹配。


(5)未命名类和实例 main 方法 (预览)

这个特性主要简化了 main 方法的的声明。



//Old

public class HelloWorld {

    public static void main(String[] args) {

        System.out.println("Hello, World!");

    }

}


//New

class HelloWorld {

    void main() {

        System.out.println("Hello, World!");

    }

}

//未命名的类允许我们不定义类名

void main() {

   System.out.println("Hello, World!");

}


(6)虚拟线程

  虚拟线程在 Java 19 中进行了第一次预览,由JEP 425提出。JDK 20 中是第二次预览。最终,虚拟线程在 JDK21 顺利转正。


  虚拟线程(Virtual Thread)是 JDK 而不是 OS 实现的轻量级线程(Lightweight Process,LWP),由 JVM 调度。许多虚拟线程共享同一个操作系统线程,虚拟线程的数量可以远大于操作系统线程的数量。


  在引入虚拟线程之前,java.lang.Thread 包已经支持所谓的平台线程,也就是没有虚拟线程之前,我们一直使用的线程。JVM 调度程序通过平台线程(载体线程)来管理虚拟线程,一个平台线程可以在不同的时间执行不同的虚拟线程(多个虚拟线程挂载在一个平台线程上),当虚拟线程被阻塞或等待时,平台线程可以切换到执行另一个虚拟线程。


  关于平台线程和系统内核线程的对应关系多提一点:在 Windows 和 Linux 等主流操作系统中,Java 线程采用的是一对一的线程模型,也就是一个平台线程对应一个系统内核线程。Solaris 系统是一个特例,HotSpot VM 在 Solaris 上支持多对多和一对一。


  相比较于平台线程来说,虚拟线程是廉价且轻量级的,使用完后立即被销毁,因此它们不需要被重用或池化,每个任务可以有自己专属的虚拟线程来运行。虚拟线程暂停和恢复来实现线程之间的切换,避免了上下文切换的额外耗费,兼顾了多线程的优点,简化了高并发程序的复杂,可以有效减少编写、维护和观察高吞吐量并发应用程序的工作量。


  虚拟线程在其他多线程语言中已经被证实是十分有用的,比如 Go 中的 Goroutine、Erlang 中的进程。


  4 种创建虚拟线程的方式可以看出,官方为了降低虚拟线程的门槛,尽力复用原有 Thread 线程类,这样可以平滑过渡到虚拟线程的使用。


Thread thread = Thread.ofVirtual(fn).start();


1.使用 Thread.startVirtualThread() 创建

2.使用 Thread.ofVirtual() 创建

3.使用 ThreadFactory 创建

4.使用 Executors.newVirtualThreadPerTaskExecutor()创建


(7)外部函数和内存 API(第三次预览)

(8)未命名模式和变量(预览)

  未命名模式和变量使得我们可以使用下划线 _ 表示未命名的变量以及模式匹配时不使用的组件,旨在提高代码的可读性和可维护性。


  未命名变量的典型场景是 try-with-resources 语句、 catch 子句中的异常变量和for循环。当变量不需要使用的时候就可以使用下划线 _代替,这样清晰标识未被使用的变量。


  未命名模式是一个无条件的模式,并不绑定任何值。未命名模式变量出现在类型模式中。


相关推荐

js中arguments详解

一、简介了解arguments这个对象之前先来认识一下javascript的一些功能:其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数...

firewall-cmd 常用命令

目录firewalldzone说明firewallzone内容说明firewall-cmd常用参数firewall-cmd常用命令常用命令 回到顶部firewalldzone...

epel-release 是什么

EPEL-release(ExtraPackagesforEnterpriseLinux)是一个软件仓库,它为企业级Linux发行版(如CentOS、RHEL等)提供额外的软件包。以下是关于E...

FullGC详解  什么是 JVM 的 GC
FullGC详解 什么是 JVM 的 GC

前言:背景:一、什么是JVM的GC?JVM(JavaVirtualMachine)。JVM是Java程序的虚拟机,是一种实现Java语言的解...

2024-10-26 08:50 citgpt

使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
跨域(CrossOrigin)

1.介绍  1)跨域问题:跨域问题是在网络中,当一个网络的运行脚本(通常时JavaScript)试图访问另一个网络的资源时,如果这两个网络的端口、协议和域名不一致时就会出现跨域问题。    通俗讲...

微服务架构和分布式架构的区别

1、含义不同微服务架构:微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并...

深入理解与应用CSS clip-path 属性
深入理解与应用CSS clip-path 属性

clip-pathclip-path是什么clip-path 是一个CSS属性,允许开发者创建一个剪切区域,从而决定元素的哪些部分可见,哪些部分会被隐...

2024-10-25 11:51 citgpt

HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
Request.ServerVariables 大全

Request.ServerVariables("Url")返回服务器地址Request.ServerVariables("Path_Info")客户端提供的路...

python操作Kafka

目录一、python操作kafka1.python使用kafka生产者2.python使用kafka消费者3.使用docker中的kafka二、python操作kafka细...

Runtime.getRuntime().exec详解

Runtime.getRuntime().exec详解概述Runtime.getRuntime().exec用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。...

promise.all详解 promise.all是干什么的
promise.all详解 promise.all是干什么的

promise.all详解promise.all中所有的请求成功了,走.then(),在.then()中能得到一个数组,数组中是每个请求resolve抛出的结果...

2024-10-24 16:21 citgpt

Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解

取消回复欢迎 发表评论: