JDK8,JDK11,JDK17特性解释和代码举例

一、版本roadmap图最新版

在这里插入图片描述

官方地址:
https://www.oracle.com/java/technologies/java-se-support-roadmap.html

从上图可以很清晰得可以看出,JDK7,JDK8,JDK11,JDK17,JDK21是长期维护的版本。从目前来看,JDK8到2023年已经有将近10年的历史了,大多数依据JDK8的相关技术内容已经很成熟了,但是大家也看到,JDK在不断地迭代,JDK有很多的新特性,而且能够对开发及系统性能有很大帮助。所以现在很多公司在建新系统的时候,在考虑新的JDK。再加上重要的一点是新的spring boot3及对应的spring cloud 2022.X及以上版本,最低支持的JDK也需要JDK17了。所以要想跟上技术迭代,还需我们自己对于JDK进行了解,然后根据自己的实际选择相应的版本。

二、版本与特性

特性列表(包含正式特性,孵化的,未孵化的等)
OpenJdk: JEP 0: JEP Index

在这里插入图片描述
如图所示,文中列举了每个jdk有对应的新特性,但是有些特性在经历几个jdk的迭代后,被移除了,或者被更好的特性所取代了,这篇文章只说几个长期支持版本,JDK8,JDK11,JDK17和JDK21

1:Java8特性

1.8.1:Lambda 表达式

Lambda 表达式简单来讲是一个匿名函数,Java 8 允许将函数作为参数传递到方法之中。

它是 Java 8 发布的最为重要的新特性之一,跟上了目前语言发展的趋势,是继泛型(Generics)和注解(Annotation)以来最大的突破。

采用 Lambda 表达式可以大幅简化代码的编写,开发人员在熟练之后,可以很简单的书写相关的功能,并且提升了相应的效率。

1.8.2:Stream流

在 JDK 1.8 中,Stream 是一种新引入的接口,它是 Java 集合框架的一部分,用于提供一种声明式的方式来进行数据处理。Stream 旨在将数据源中的元素通过管道进行操作,并产生结果。Stream 流提供了一种简洁、高效的方式来处理大量数据,而无需将整个数据集加载到内存中。

Stream 接口位于 java.util.stream 包中,它定义了一些操作数据的静态方法,例如 map、filter、reduce 等。这些方法可以与集合类(如 List、Set)一起使用,以执行各种数据处理操作。

Stream 流具有以下特点:

延迟计算:Stream 中的操作只有在需要时才会执行,这有助于节省内存。
函数式编程:Stream 支持使用 lambda 表达式和方法引用来定义操作,这使得代码更加简洁和易于理解。
链式操作:Stream 中的操作可以链式调用,以实现复杂的处理逻辑。
并行处理:Stream 支持并行处理数据,以提高性能。
使用 Stream 流可以方便地处理以下场景:

数据筛选和过滤:例如从列表中筛选出符合特定条件的元素。
数据转换:例如将列表中的字符串转换为整数。
数据聚合:例如计算列表中元素的平均值或总和。
数据并行处理:例如对大型数据集进行并行计算以提高性能。
下面是一个简单的示例,演示了如何使用 Stream 流来过滤和转换一个列表中的元素:

List<String> names = Arrays.asList("John", "Jane", "Alice", "Bob");  
List<Integer> ages = names.stream()            // 将列表转换为 Stream  
    .filter(name -> name.startsWith("A"))      // 筛选出以 "A" 开头的字符串  
    .map(name -> name.length())                // 将字符串长度作为新的元素  
    .collect(Collectors.toList());             // 将结果收集到一个新的列表中  
System.out.println(ages);                      // 输出结果:[4, 6]

1.8.3:Optional

Optional 是一个 Java 容器类,属于 java.util 包。它用于表示一个值存在或不存在的情况,通常用于避免 null 值引发空指针异常。

Optional 类的出现是为了更好地处理一个值可能为 null 的情况,通过将值包装在 Optional 容器中,可以避免直接操作 null 值而引发异常。Optional 提供了一系列方法来检查、获取和处理值。

Optional 类的常用方法包括:

  1. isPresent():检查容器中是否有值。
  2. get():获取容器中的值,如果容器为空,则抛出 NoSuchElementException。
  3. orElse():获取容器中的值,如果容器为空,则返回一个默认值。
  4. orElseGet():获取容器中的值,如果容器为空,则从提供的 supplier 中获取一个默认值。
  5. orElseThrow():获取容器中的值,如果容器为空,则抛出一个指定的异常。
  6. ifPresent():如果容器中有值,则执行指定的操作。
  7. ifPresentOrElse():如果容器中有值,则执行指定的操作,否则执行另一个指定的操作。
  8. stream():将容器中的值转换为一个流。
  9. of():创建一个包含指定值的 Optional 对象。
  10. empty():创建一个不包含值的 Optional 对象。

使用 Optional 可以帮助我们更好地处理可能为 null 的情况,降低异常风险,提高代码的可读性和健壮性。

import java.util.Optional;  
  
public class OptionalExample {  
    public static void main(String[] args) {  
        String nullString = null;  
        Optional<String> optionalString = Optional.ofNullable(nullString);  
  
        // 使用 ifPresentOrElse 处理 null 值  
        optionalString.ifPresentOrElse(str -> System.out.println("字符串不为空:" + str),  
                () -> System.out.println("字符串为空"));  
  
        // 使用 orElseGet 提供一个默认值  
        String defaultString = optionalString.orElseGet(() -> "默认值");  
        System.out.println("默认值:" + defaultString);  
    }  
}

输出结果:

字符串为空  
默认值

在这个例子中,我们使用 Optional.ofNullable 方法将一个可能为 null 的字符串包装在 Optional 容器中。然后,我们使用 ifPresentOrElse 方法来检查 Optional 容器中是否有值,如果有值则执行特定的操作,否则执行另一个操作。我们还使用了 orElseGet 方法来提供一个默认值,如果 Optional 容器为空,则返回这个默认值。通过使用 Optional,我们可以更灵活地处理可能为 null 的情况,提高代码的健壮性和可读性。

1.8.4:Interface

在 JDK 1.8 中,Interface(接口)是一种定义抽象行为的类型。它允许我们定义一组方法的签名,而具体的实现由实现该接口的类来提供。接口在 Java 中是非常重要的,它用于实现多态性、抽象性和代码的可重用性。

以下是一些关于 Interface 的用法的例子:

  1. 定义接口:
public interface MyInterface {
    // 接口方法(抽象方法)的声明
    void myMethod();
}
  1. 实现接口:
public class MyClass implements MyInterface {
    // 实现接口方法
    @Override
    public void myMethod() {
        System.out.println("MyClass 中的 myMethod 实现");
    }
}
  1. 使用接口:
public class Main {
    public static void main(String[] args) {
        MyInterface obj = new MyClass(); // 创建实现接口的类的对象
        obj.myMethod(); // 调用接口方法
    }
}

输出:

MyClass 中的 myMethod 实现

注意:从 Java 8 开始,接口可以包含默认方法和静态方法。此外,从 Java 9 开始,还可以在接口中定义私有方法。这些功能增强了接口的灵活性和实用性。
在Java 8及以后的版本中,接口可以包含默认方法和静态方法。让我们分别讨论如何使用这两种方法。

  1. 默认方法:
    默认方法允许我们在接口中提供方法的默认实现,可以被实现接口的类选择性重写。默认方法主要用于解决Java 8以前的版本中由于接口不能包含实现而导致的兼容性问题。

要在一个接口中定义默认方法,使用default关键字。下面是一个示例:

public interface MyInterface {
    default void defaultMethod() {
        System.out.println("这是默认方法");
    }
}

然后,实现该接口的类可以选择性地重写默认方法。例如:

public class MyClass implements MyInterface {
    @Override
    public void defaultMethod() {
        System.out.println("这是重写的默认方法");
    }
}
  1. 静态方法:
    静态方法允许我们在接口中定义与接口本身相关的方法,通常用于提供工具方法或静态工厂方法。从Java 9开始,接口还可以定义私有方法。

要在一个接口中定义静态方法,使用static关键字。下面是一个示例:

public interface MyInterface {
    static void staticMethod() {
        System.out.println("这是静态方法");
    }
}

然后,你可以直接通过接口名调用静态方法,如下所示:

MyInterface.staticMethod(); // 输出:"这是静态方法"

需要注意的是,从Java 8开始,接口可以包含默认方法和静态方法,这增加了接口的灵活性和实用性。

默认方法允许我们在接口中提供方法的默认实现,可以被实现接口的类选择性重写。静态方法则允许我们在接口中定义与接口本身相关的方法,通常用于提供工具方法或静态工厂方法。私有方法允许我们在接口中定义内部逻辑,但不会暴露给实现接口的类。

1.8.5:functional interface 函数式接口

函数式接口是在Java 8中引入的一个新特性,它是一个只有一个抽象方法的接口,通常用于配合Lambda表达式使用。

例如,我们定义了一个名为Action的函数式接口,它只有一个抽象方法execute()

@FunctionalInterface
public interface Action {
    void execute();
}

在这个接口中,我们定义了一个抽象方法execute(),没有具体的实现。

接着,我们可以使用Lambda表达式来实现这个接口。Lambda表达式是一种简洁、匿名的函数,可以作为参数传递给其他函数或方法。

例如,我们使用Lambda表达式() -> System.out.println("Hello, World!")来隐式地实现了Action接口的execute()方法:

Action action = () -> System.out.println("Hello, World!");

Lambda表达式() -> System.out.println("Hello, World!")表示一个没有参数并且没有返回值的函数。在这里,它将作为参数传递给Action接口的实例化对象。

当我们调用action.execute()时,实际上是调用了Lambda表达式中的代码。输出结果为Hello, World!

除了Action接口,还有其他常见的函数式接口,如Comparator。这个接口可以用于比较两个对象,并返回一个整数表示它们的大小关系。

例如,我们使用Lambda表达式(s1, s2) -> s1.compareTo(s2)来实现Comparator接口的compare()方法:

Comparator<String> comparator = (s1, s2) -> s1.compareTo(s2);

这个Lambda表达式表示一个接受两个字符串参数并返回一个整数的函数。它将字符串s1s2进行比较,并返回它们的大小关系。

然后,我们可以将这个比较器用于对一个字符串列表进行排序。例如:

List<String> list = Arrays.asList("apple", "banana", "cherry");
List<String> sortedList = list.stream().sorted(comparator).collect(Collectors.toList());

这里,我们使用Java 8的Stream API来对字符串列表进行排序。我们将比较器comparator作为参数传递给sorted()方法,该方法将根据比较器的结果对列表进行排序。最终结果存储在sortedList中。

1.8.6:Date-Time API

JDK 1.8对Date和Time类进行了一系列改进,引入了新的Date/Time API。这个API被设计为完全替代java.util.Date和java.util.Calendar,因为这两个类在使用时存在许多问题,包括线程不安全、时间处理麻烦以及设计不佳。

以下是JDK 1.8中Date-Time API的一些主要变化:

  1. 新的时间单位:JDK 1.8引入了新的时间单位,包括纳米(Nanoseconds)、微秒(Microseconds)和纳秒(Nanoseconds),以便更精确地处理时间。
  2. 时间点类(Instant):Instant类表示一个具体的时间点,它是一个不可变的对象,可以用于记录事件的日期和时间。它提供了方便的方法来获取当前时间、计算时间差等。
  3. 时区类(ZoneId):ZoneId类表示时区,它提供了多种获取时区的方式,包括获取默认时区、获取特定时区等。
  4. 日期时间类(LocalDate、LocalTime、LocalDateTime):LocalDate和LocalTime分别表示日期和时间,它们也是不可变的对象。LocalDateTime则表示日期和时间的组合,是LocalDate和LocalTime的结合体。这些类提供了一致的方法来处理日期和时间,使得代码更加简洁易懂。
  5. 时间轴类(ZonedDateTime、OffsetDateTime):ZonedDateTime和OffsetDateTime分别表示带有时区和偏移量的日期时间以及没有时区的日期时间。它们提供了更复杂的时间处理能力,比如计算特定时间点在特定时区中的日期和时间。
  6. 时间间隔类(Duration):Duration类表示两个时间点之间的间隔,它可以用于计算两个时间点之间的时间长度,或者将一个时间长度转换为特定单位的时间间隔。
  7. 解析器和格式化器(DateTimeFormatter):DateTimeFormatter类提供了强大的日期时间解析和格式化功能,可以方便地将日期时间字符串转换为Date/Time对象,或者将Date/Time对象转换为字符串。

总之,JDK 1.8的Date/Time API提供了更加直观、灵活和可读性更好的方式来处理日期和时间相关的任务。

2:Java11特性

针对JDK8的变动:
JDK 11 对 JDK 8 的新增和移除的功能包括:

新增的功能:

  1. V11引入了一个新的String API,可以在不创建新对象的情况下重复字符串,这有助于减少内存占用,提升性能。
  2. V11引入了新的集合API,增强了对List、Set、Map等数据结构的处理能力。
  3. V11引入了新的Stream API,可以在Java中使用C++ STL风格的数据处理方式,更方便、更高效。
  4. V11提供了对Java原生JSON API的支持,方便开发者处理JSON数据。
  5. V11支持新的Switch表达式,可以在switch语句中使用字符串作为标签,同时增强了switch语句的功能。
  6. V11支持新的JVM常量API,方便开发者对JVM常量进行管理。
  7. V11提供了新的方法,可以在不创建新对象的情况下获取字符串的子串。
  8. V11引入了新的异常处理机制,方便开发者更好地处理异常。
  9. V11增强了JVM的垃圾回收功能,提高了垃圾回收效率。

移除的功能:

  1. V11移除了Java EE和CORBA模块,这些模块在Java 9中已经被标记为废弃,而在Java 11中终于被移除。
  2. V11移除了因安全原因和性能问题而被标记为废弃的API和功能。
  3. V11移除了对32位系统的支持。
  4. V11移除了对Java Applet的支持。
  5. V11移除了对IPv6的支持。
  6. V11移除了对Java本地的接口支持。
  7. V11移除了对Java本地的原始类型的支持。
  8. V11移除了对Java本地的字符串的支持。

2.11.1:垃圾回收器的改变

JDK 11 中,默认的垃圾收集器是 G1 收集器(jdk9成为默认收集器)。G1 收集器是一种并发的垃圾收集器,它会尽可能地与应用程序的执行并发运行。G1 将堆内存划分为多个大小相等的区域,并尽量减少全局停顿的时间,以提高系统的吞吐量和响应能力。同时,G1 也会对堆内存进行整理,以减少内存碎片和空间浪费。因此,JDK 11 的 HotSpot 虚拟机使用的是 G1 收集器,并采用了并发、分代的垃圾收集模型。

2.11.2:低开销的Heap Profiling

例如,开发人员可以使用低开销的Heap Profiling来监控Java程序在运行过程中创建的对象,包括对象的类型、数量、大小以及生命周期等信息。以下是一些使用低开销的Heap Profiling的示例:

  1. 分析内存泄漏:如果程序在长时间运行后出现OutOfMemoryError错误,或者内存使用持续增长,这可能意味着程序存在内存泄漏问题。使用低开销的Heap Profiling可以监控对象创建和销毁的情况,帮助开发人员找到可能的内存泄漏点。
  2. 分析对象大小:通过低开销的Heap Profiling,开发人员可以获取各个对象的类型和大小信息,以便更好地了解程序中不同对象的内存占用情况,从而进行针对性的优化。
  3. 分析对象生命周期:低开销的Heap Profiling还可以提供对象的创建和销毁信息,帮助开发人员了解程序的内存分配情况以及对象的生命周期,以便更好地优化程序的内存管理。

要使用低开销的Heap Profiling,需要按照以下步骤进行操作:

  1. 打开浏览器并进入要监视的网站。
  2. F12打开调试工具,并转到"Profiles"标签。
  3. 点击"Take Heap Snapshot"按钮,然后选择"Take Heap Snapshot"选项。
  4. 等待一段时间,直到Heap Profiling完成并生成当前JS堆的快照。
  5. 在生成的堆快照中,可以查看当前JS运行时使用的所有对象,以及这些对象所占用的内存大小和引用的层级关系等信息。

通过分析生成的堆快照文件,开发人员可以更深入地了解Java程序的内存分配和使用情况,从而优化程序的性能、减少内存泄漏等问题。

2.11.3:飞行记录器(Java Flight Recorder)

Java Flight Recorder(JFR)是Java JDK中的一个工具,用于收集Java虚拟机(JVM)的详细性能数据。它能够以极低的性能开销记录JVM运行过程中的事件和数据,包括Java层面的事件(如线程事件、锁事件)以及Java虚拟机内部的事件(如新建对象、垃圾回收、即时编译事件)。

使用Java Flight Recorder可以分析Java程序的性能瓶颈,优化程序性能,以及诊断异常行为。

要使用Java Flight Recorder,需要按照以下步骤进行操作:

  1. 启动Java程序时,添加"-XX:+UnlockCommercialFeatures"和"-XX:+FlightRecorder"参数。例如:
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder MyApplication

这将启动Java程序并启用Java Flight Recorder。

  1. 在程序运行一段时间后,使用JDK Mission Control(JMC)工具停止飞行记录并导出报告。在JMC中,可以打开Java Flight Recorder的界面,选择要导出的记录并生成报告。

导出报告后,可以使用JFR Viewer工具查看和分析报告。JFR Viewer提供了丰富的可视化图表和数据,帮助开发人员了解Java程序的性能瓶颈和运行情况。

举个例子,假设我们想要分析一个Java程序的垃圾回收情况。我们可以在程序启动时启用Java Flight Recorder,并在程序运行一段时间后导出报告。在JFR Viewer中,我们可以查看垃圾回收事件的详细信息,包括事件发生的时间、持续时间、回收的内存大小等。通过分析这些数据,我们可以了解程序在运行过程中的垃圾回收情况,以及是否存在内存泄漏等问题。

总之,Java Flight Recorder是一个强大的性能分析工具,可以帮助开发人员深入了解Java程序的运行情况和性能瓶颈,从而优化程序性能并提高程序的稳定性。

2.11.4:String增强

在JDK 11中,关于String的增强主要有以下几个方面:

  1. 字符串字面量可以存储在元空间(Metaspace)中,而不是直接存储在堆内存中。这意味着字符串字面量不再共享,每个字符串字面量都会创建一个新的String对象。这有助于减少内存占用和提高性能。
  2. String类新增了一些方法,如repeat(int count)用于重复字符串,strip()用于去除字符串的头尾空白字符,stripTrailing()用于去除字符串尾部空白字符,isBlank()用于判断字符串是否为空白(包括空格、制表符、换行符等)。
  3. 在拼接字符串时,可以使用String.join(CharSequence delimiter, CharSequence... items)方法,该方法可以方便地拼接多个字符串,并指定分隔符。
  4. 在处理字符串时,可以使用String.matches(String regex)String.split(String regex)方法,这两个方法都支持Pattern和Matcher,使得正则表达式操作更加方便。
  5. 改进了字符串的不可变性。在JDK 11之前,字符串是不可变的,但在某些情况下可能会存在竞争条件。在JDK 11中,字符串的不可变性得到了改进,可以更安全地操作字符串。

以下是几个关于JDK 11中String增强的例子:

  1. 字符串字面量存储在元空间中

在JDK 11之前,字符串字面量会被存储在堆内存中,并且会被共享。例如:

String s1 = "Hello";
String s2 = "World";
String s3 = "HelloWorld";

在JDK 11之前,s3会创建一个新的字符串对象,因为字符串字面量不再共享。而在JDK 11中,s3会直接指向s1s2所指向的同一个字符串对象,因为字符串字面量被存储在元空间中。这样可以减少内存占用和提高性能。

  1. 新增的字符串方法

在JDK 11中,String类新增了一些方法,例如repeat(int count)可以用于重复字符串。例如:

String s = "Hello";
String repeated = s.repeat(3); // "HelloHelloHello"

可以使用strip()方法去除字符串的头尾空白字符,例如:

String s = "   Hello   ";
String stripped = s.strip(); // "Hello"

可以使用isBlank()方法判断字符串是否为空白,包括空格、制表符、换行符等。例如:

String s = "   ";
System.out.println(s.isBlank()); // true
  1. 使用String.join()方法拼接字符串

可以使用String.join()方法拼接多个字符串,并指定分隔符。例如:

String[] names = {"Alice", "Bob", "Charlie"};
String joined = String.join(", ", names); // "Alice, Bob, Charlie"
  1. 使用String.matches()String.split()方法处理字符串

可以使用String.matches()String.split()方法来处理正则表达式。例如:

String s = "apple, banana, cherry";
boolean matches = s.matches("[a-z]+"); // true
String[] fruits = s.split(", "); // ["apple", "banana", "cherry"]

在JDK 11中,字符串的不可变性得到了改进,可以更安全地操作字符串。例如:

String s = "Hello";
s += " World"; // 在JDK 11之前,这会创建一个新的字符串对象,因为在拼接时可能会存在竞争条件。在JDK 11中,这不会创建新的字符串对象,因为字符串的不可变性得到了改进。

2.11.5:Lambda 参数的局部变量语法

Java 10 开始,便引入了局部变量类型推断这一关键特性。类型推断允许使用关键字 var 作为局部变量的类型而不是实际类型,编译器根据分配给变量的值推断出类型。

Java 10 中对 var 关键字存在几个限制

只能用于局部变量上
声明时必须初始化
不能用作方法参数
不能在 Lambda 表达式中使用
Java11 开始允许开发者在 Lambda 表达式中使用 var 进行参数声明。

// 下面两者是等价的

Consumer<String> consumer = (var c) -> System.out.println(c);
 
Consumer<String> consumer = (String c) -> System.out.println(c);

3.17.1:JDK17特性

Java 17 将是继 Java 8 以来最重要的长期支持(LTS)版本,是 Java 社区八年努力的成果。Spring 6.x 和 Spring Boot 3.x ,Spring Cloud 2022.X最低支持的就是 Java 17。

3.17.1:Sealed Classes(密封类)

密封类是指只允许有限数量的子类继承的类。这个特性可以帮助开发人员更好地控制继承层次结构,减少意外的子类扩展,提高代码的可维护性。

 public sealed class Shape permits Circle, Rectangle {
     // 共享的方法和属性
 }
 
 public final class Circle extends Shape {
     // 圆形的特定方法和属性
 }
 
 public final class Rectangle extends Shape {
     // 矩形的特定方法和属性
 }

在这个例子中,Shape 类被声明为密封类,只允许 Circle 类和 Rectangle 类继承。这样可以限制继承层次结构,防止其他类意外地继承 Shape。

3.17.1:Pattern Matching for Switch(Switch 模式匹配)

JDK 17 引入了模式匹配的语法增强,可以在 switch 语句中使用模式匹配来简化代码。新的语法可以在 switch 中使用类似于 if-else 语句的模式匹配条件,使得代码更加简洁和易读。
Pattern Matching for Switch(Switch 模式匹配):
以下是一个使用模式匹配的 switch 语句的例子:

   public String getShapeType(Shape shape) {
       String type;
       
       switch (shape) {
           case Circle c -> type = "Circle";
           case Rectangle r -> type = "Rectangle";
           case Square s -> type = "Square";
           default -> type = "Unknown";
       }
       
       return type;
   }

在这个例子中,根据不同的 Shape 对象,使用模式匹配的语法来获取形状的类型。

       static String formatter(Object o) {
        String formatted = "unknown";
        if (o instanceof Integer i) {
            formatted = String.format("int %d", i);
        } else if (o instanceof Long l) {
            formatted = String.format("long %d", l);
        } else if (o instanceof Double d) {
            formatted = String.format("double %f", d);
        } else if (o instanceof String s) {
            formatted = String.format("String %s", s);
        }
        return formatted;
    }

    //支持模式匹配的switch
    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();
        };
    }

3.17.1:Concurrent Thread-Local Handshakes(并发线程本地握手)

JDK 17 引入了一种新的机制,允许开发人员在多线程应用程序中进行线程之间的协作。通过简单的 API 调用,线程可以在需要的时候握手,共享信息,以实现更高效的线程之间的通信和同步。

3.17.1:Strong encapsulation for JDK internals(JDK 内部的强封装)

JDK 17 加强了对 JDK 内部类和 API 的封装。这样做有助于提高代码的安全性和可维护性,并鼓励开发人员使用公共 API,而不是直接访问 JDK 的内部实现。

3.17.1:Sealed, immutable records(密封、不可变记录类型)

JDK 17 引入了密封和不可变记录类型的新特性。密封记录类型是对密封类和记录类型的结合,它们定义了一种更加严格的类继承和不可变性模型,从而提供了更强的类型安全性和代码可读性。

3.17.1:Enhanced Pseudo-Random Number Generators(增强的伪随机数生成器)

JDK 17 提供了一些新的伪随机数生成器算法,旨在提供更好的性能和安全性。这些新的算法可以在 java.util 包中使用,并且可以根据应用程序的需求进行定制和配置。

3.17.1:Deprecate and Remove Experimental and Preview Features

JDK 17 删除了一些实验性和预览特性,这些特性已经过时或不再推荐使用。这意味着开发人员需要注意更新他们的代码以适应这些更改,并使用替代的功能或API。

总结

提示:这里对文章进行总结:

例如:以上就是jdk8,jdk11,jdk17的相关内容,主要集中在jvm以及我们常用的方法或者类进行优化,后续还会新增jdk21

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值