JDK1.8之后的版本变更

背景

在2011年JDK1.7版本发布,因其引入了许多新功能、改进和性能优化,大行其道;直至2014年JDK 1.8 版本开启了Lambda表达式实现函数式编程,引入Stream API,新的日期和时间API等特性,使Java编程语言更加现代化,也提供了更多的工具和语言特性,让java 开发者开启了更加简洁的代码编写风格,使得这一个稳定版本得到了广大开发者的喜爱,即使当前JDK版本发布到21,但是1.8任然是大部分程序员的最爱。

本文主要对1.8后的一些新版本做一些简短的介绍,让java 开发对jdk的发展和其走向有一个大致了解,紧跟发展步伐。不能抱有你强任你强,我用 java8 的思想。

RoadMap

任何技术产品都有自己的支持策略,一个产品不可能无期限的给予最高优先级的支持。比如我们习以为常的iOS系统,也不可能将10年前的iPhone一直支持下去。

Oracle也不例外,对自家产品进行分级支持。不同的产品、在不同的时期,支持的强度也不一样。强度分为:

Premier Support(高优支持)
一般为5年,可以得到技术支持、更新、bug修复、安全警报、数据修复、关键补丁更新
Extended Support(扩展支持)
额外3年支持,服务基本同上,但优先级低,更新频率变低
Sustaining Support(持续支持)
它的特点是支持的时间长,但支持的项目较少,响应慢

我们可以将JDK 版本分为以下2个大类,对应不同的支持期限:

  • LTS(long term support)长期支持
  • non-LTS 不长期支持

Oracle 将仅将某些版本指定为长期支持 (LTS) 版本,给与比较长时间的支持。Oracle计划每两年发布一次LTS 版本(每年9月份),对于企业甚至绝大部分个人,注意力主要集中在TLS版本上。

版本发布日期高优支持到扩展支持到持续支持到
7(LTS)2011年7月2019年7月2022年7月不定
8(LTS)2014年3月2022年3月2030年12月不定
9(非LTS)2017年9月2018年3月Not Available不定
10(非LTS)2018年3月2018年9月Not Available不定
11(LTS)2018年9月2023年9月2026年9月不定
12(非LTS)2019年3月2019年9月Not Available不定
13(非LTS)2019年9月2020年3月Not Available不定
14(非LTS)2020年3月2020年9月Not Available不定
15(非LTS)2020年9月2021年3月Not Available不定
16(非LTS)2021年3月2021年9月Not Available不定
17(LTS)2021年9月2026年9月2029年9月不定
18(非LTS)2022年3月2022年9月Not Available不定
19(非LTS)2022年9月2023年3月Not Available不定
20(非LTS)2023年3月2023年9月Not Available不定
21(LTS)2023年9月2028年9月2031年9月不定

Oracle JDK和Oracle OpenJDK

2套JDK 非常接近,主要说下不同之处:OpenJDK 完全开源,任何人或者组织使用都是免费的,更新和维护主要依靠开源社区;Oracle JDK 在过去是免费的,但从 2019 年 1 月开始,也就是JDK11发布后,Oracle 对商业用户使用 Oracle JDK 实施了收费政策。

导致不一样的原因是使用的许可证协议不一样,OpenJDK 使用 GNU General Public License v2 with the Classpath Exception(GPLv2+CPE)许可证,这是一种开源许可证。Oracle JDK 使用 Oracle Technology Network License Agreement for Oracle Java SE,这是一种商业许可证。

JDK11新特性

局部变量类型推断

在JDK 11中,可以使用var关键字进行局部变量声明,让编译器根据变量的初始化值推断出变量的类型。这样可以简化代码,并提高代码的可读性和可维护性。

示例代码: var message = "Hello, World!";

Lambda参数的本地变量语法

在Java 8中引入的Lambda表达式已经成为Java开发中的重要特性。在Java JDK 11中,Lambda表达式的参数也可以使用与局部变量相同的语法,不再需要显式声明参数的类型

HTTP Client API:

Java JDK 11引入了一个新的HTTP Client API,用于进行HTTP通信。该API提供了一种现代、灵活和异步的方式来发送HTTP请求和处理响应,使得开发人员能够更轻松地构建高性能的HTTP客户端。

示例代码:

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com"))
        .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

Epsilon垃圾收集器

Java JDK 11引入了一个新的垃圾收集器,称为Epsilon垃圾收集器。Epsilon垃圾收集器不会实际进行垃圾回收,而是简单地分配内存。它适用于对垃圾收集器没有特殊要求的场景,可以减少垃圾收集的开销,从而提高应用程序的性能。

示例代码:

java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC MyApp

ZGC垃圾收集器

Java JDK 11引入了一个新的垃圾收集器,称为ZGC垃圾收集器。ZGC是一种低延迟的垃圾收集器,具有非常短的停顿时间,适用于需要快速响应和高吞吐量的应用程序。它可以在数毫秒的时间内处理几十GB的堆内存。

传统的垃圾收集器在进行垃圾回收时,会导致应用程序的停顿时间增加,这对于需要实时性能和低延迟的应用程序来说是不可接受的。ZGC通过一些创新的技术和算法来解决这个问题,使得停顿时间可以控制在非常短的时间范围内。

下面是一些ZGC垃圾收集器的关键特性和工作原理:

1. 并发处理:ZGC使用并发处理技术来最大程度地减少停顿时间。它将垃圾收集的不同阶段与应用程序的执行并行进行,以减少对应用程序的干扰。

2. 堆内存压缩:ZGC使用了一种称为“可扩展全局指针”(Scalable Global Pointers)的技术来压缩堆内存。这种技术允许在不停顿应用程序的情况下,对堆内存进行动态压缩和释放。

3. 动态性:ZGC支持动态分配和释放堆内存,使得应用程序可以根据实际需求进行内存的调整。这种动态性使得ZGC适用于处理大型内存堆的应用程序。

4. 可预测性:ZGC垃圾收集器通过将垃圾收集的工作负载分布到不同的线程中,以提供可预测的停顿时间。这样,应用程序可以更好地规划和管理其资源。

示例代码:-XX:UnlockExperimentalVMOptions -XX:+UseZGC

实验阶段,不建议用在生产环境

API增强

字符串

isBlank():用来判断字符串是不是空字符"“或者trim()之后(” ")为空字符

lines():将一个字符串按照行终止符(换行符\n或者回车符\r)进行分割,并将分割为Stream流

repeat(n):按照给定的次数重复串联字符串的内容

strip():去除字符串前后的“全角和半角”空白字符

Steam流

Stream.ofNullable :从单个元素构造流

dropWhile:方法都接受一个谓词来决定从流中放弃哪些元素

takeWhile:方法都接受一个谓词来决定从流中选用哪些元素

Optionals:Optionals 增加了非常方便的新方法,例如,现在可以简单地将 Optionals 转换为流,或者提供另一个 Optionals 作为空 Optionals 的回调

JDK17新特性

Switch表达式新增匹配模式

不用写break了:

int age = switch (name) {
            case "aa" -> 18;
            case "cc" -> 66;
            default -> 0;}

并支持对类进行类型判断

    private static String switchMethod(Object o) {
        return switch (o) {
            case String str -> "字符串类型:" + str;
            case Number number -> "数字类型:" + number;
            case Date date -> "日期类型:" + DateUtil.formatDateTime(date);
            default -> "其他类型";
        };
    }

这里的类型匹配除了可以在switch 语法里这么使用外,还可以:

  private static void instanceOf(Object o) {
        if (o instanceof Integer i) {
            System.out.println("数字:" + i);
        } else if (o instanceof String str) {
            System.out.println("字符串:" + str);
        } else {
            System.out.println("其他类型");
        }
    }

文本块

在Java17之前的版本里,如果我们需要定义一个多行文本字符串,比如一个JSON数据,基本都是如下方式定义:

public void lowVersion() {
    String text = "{\n" +
        "  \"name\": \"Java\",\n" +
        "  \"age\": 18,\n" +
        "  \"address\": \"北京市西城区\"\n" +
        "}";
    System.out.println(text);
}

现在可以通过"""...""",三个引号就可以,看着十分的清爽。

private void highVersion() {
    String text = """
            {
              "name": "Java",
              "age": 18,
              "address": "北京市西城区"
            }
            """;
    System.out.println(text);
}

密封类

提供了一个新的关键字sealec,它的作用修饰父类、接口,变成一个密封类,同时还提供了一个permits,指定与父类接口同包的类才能继承或者实现。


public abstract sealed class Furit permits Apple,Pear {
}

抽象类Fruit 作为父类只能被Apple类和Pear类继承。 并要遵循以下几点:

如果父类使用了sealed关键字,那么它就必须要用permits关键字指定子类

子类要么使用final、no-sealed关键字,要么自己再次使用sealed关键字成为一个父类,并指定子类

他们都在同一个包下面,且不允许其它类进行继承

Record类

Record的目标是扩展Java语言语法,Record为声明类提供了一种紧凑的语法,用于创建一种类中是“字段,只是字段,除了字段什么都没有”的类。

通过对类做这样的声明,编译器可以通过自动创建所有方法并让所有字段参与hashCode()等方法。

record Person (String firstName, String lastName) {}

Person p= new Person("name1","name2")

 对 NullPointerExceptions的优化

在JDK17之前输出将显示NullPointerException发生的行号,但不知道哪个方法调用时产生的null,

在Java 17中,则会准确显示发生NPE的精确位置。

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.px.java17.Person.getName()" because the return value of "com.px.java17.Person.getAddress()" is null at com.px.java17.Demo.main(Demo.java:13)

JDK21新特性

虚拟线程

将虚拟线程(Virtual Threads)引入 Java 平台。虚拟线程是轻量级线程,可以显著减少编写、维护和观察高吞吐量并发应用程序的工作量。

轻量级线程管理:虚拟线程不需要底层操作系统线程的支持,因此可以创建数千甚至数万个虚拟线程而不会消耗大量的内存和资源。这使得应用程序可以更高效地管理大量并发任务。
更快的线程创建和销毁:传统的 Java 线程创建和销毁通常涉及昂贵的操作系统调用,而虚拟线程的创建和销毁成本更低,因此可以更快速地启动和停止线程。
更好的资源利用:由于虚拟线程可以更轻松地伸缩,因此它们有助于更好地利用现有的系统资源,以处理大规模的并发请求。
避免死锁和资源争夺:虚拟线程的管理方式可以减少线程之间的竞争和资源争夺,从而降低了死锁和性能问题的风险。
简化并发编程:虚拟线程的引入使得编写并发程序变得更加容易,开发人员可以专注于业务逻辑而不必过多关注线程管理和同步。

public class Test01 {
    public static void main(String[] args) {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            IntStream.range(0, 10000).forEach(i -> executor.submit(() -> {
                Thread.sleep(Duration.ofSeconds(1));
                return i;
            }));
        }
    }
}

 序列化集合

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

Sequenced Collections 引入了三个新接口:

  • SequencedCollection
  • SequencedMap
  • SequencedSet

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

在 JDK 21 之前,检索 Java 中集合的第一个和最后一个元素涉及不同的方法和途径,具体取决于集合类型,非常麻烦。

访问位置ListDequeSortedSet
第一个元素list.get(0)deque.getFirst()set.first()
最后一个元素list.get(list.size()-1)deque.getLast()set.last()

但在 JDK 21 之后,对于List, Deque, Set这些有序的集合,访问第一个和最后一个元素方法变得统一起来:

第一个元素:collection.getFirst()
最后一个元素:collection.getLast()

类似的还有在两端添加或删除元素,都提供了共同的方法。

字符串模板

字符串模板是一个预览功能,即处于试验阶段,提供了一种更简洁、更直观的方式来动态构建字符串。通过使用占位符${},我们可以将变量的值直接嵌入到字符串中,而不需要手动处理。在运行时,Java 编译器会将这些占位符替换为实际的变量值。并且,表达式支持局部变量、静态/非静态字段甚至方法、计算结果等特性。总体而言就是加强了字符串的处理,不用像之前那样进行加号拼接,这里不做过多介绍。

分代 ZGC

 JDK 21 引入了分代 ZGC,这是一种新的垃圾收集器,旨在提高大型堆内存的性能和可扩展性。分代 ZGC 利用分代内存布局和分代收集算法,可将垃圾收集的负担分散到不同的代中,从而减少垃圾收集的停顿时间。

分代 ZGC 可以显著减少垃圾回收过程中的停顿时间,并提高应用程序的响应性能。这对于大型 Java 应用程序和高并发场景下的性能优化非常有价值。

                        
参考:

https://blog.csdn.net/f641385712/article/details/124732654

https://blog.csdn.net/qyj19920704/article/details/133297170

https://zhuanlan.zhihu.com/p/681718421

https://blog.csdn.net/njpkhuan/article/details/133177862

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值