Java9-17新特性

news2024/12/23 6:35:05

文章目录

  • 一、简介
  • 二、新特性
    • 接口私有方法(JDK9)
    • String存储结构的变化(JDK9)
    • 快速创建只读集合(JDK9、10)
    • 文本块(JDK13、14、15)
    • 更直观的 NullPointerException 提示(JDK14)
    • 密封类(JDK15、16、17)
    • instanceof的模式匹配(JDK14、15、16)
    • switch增强(JDK12、13、17)
    • 垃圾收回相关优化(JDK9-17)
      • JDK9
      • JDK10
      • JDK11
      • JDK12
      • JDK13
      • JDK14
      • JDK15
      • JDK16
  • 三、总结

一、简介

由于 SpringBoot 3 最低支持的 JDK 版本是 17 了,加上 JDK 17 是一个 LTS 版本(Long-Term Support,长期稳定可靠的版本),所以还是有必要学习下 JDK 9 - JDK17 的新特性的。写这篇文章帮助自己记忆,也方便后续查阅。

关于 JDK 各版本新特性可查看网址:https://openjdk.org/

二、新特性

下面是我认为比较重要的一些新特性,有些感觉平时不会用的语法糖就不讲了,有兴趣的可以自己去了解了解

接口私有方法(JDK9)

JEP 213: Milling Project Coin

在讲 JDK 9 新特性 —— 接口私有方法之前,我们先了解下在之前的 JDK 版本中接口的变化。

在 JDK 8 之前,我们接口里只存在常量抽象方法

public interface MyInterface {

    /**
     * 常量(默认就是public abstract final修饰的)
     */
    String CONSTANT = "常量";

    /**
     * 抽象方法(默认就是public abstract修饰的)
     */
    void abstractMethod();
}

在 JDK 8 版本里,增加了默认方法静态方法

默认方法可以定义方法的默认实现,使用 default 关键字修饰

public interface MyInterface {

    /**
     * 默认方法
     */
    default void defaultMethod() {
        System.out.println("这是默认方法");
    }
}

public class MyClass implements MyInterface{

    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.defaultMethod();
    }
}

运行结果:

这是默认方法

因为实现类可以不重写接口中的默认方法,所以可以往现存接口中添加新的方法,不用强制那些已经实现了该接口的类也同时实现这个新加的方法,非常棒!

此外还可以在接口里定义静态方法,使用 static 关键字修饰

public interface MyInterface {

    /**
     * 静态方法
     */
    static void staticMethod() {
        System.out.println("这是静态方法");
    }
}

public class MyTest{

    public static void main(String[] args) {
        MyInterface.staticMethod();
    }
}

运行结果:

这是静态方法

有的同学可能已经发现问题了,如果我多个默认方法用到了同一段代码,岂不是要写很多重复代码,于是 JDK 9 在接口里增加了私有方法,可以将相同的代码提取到私有方法里

public interface MyInterface {

    /**
     * 默认方法
     */
    default void defaultMethod() {
        System.out.println("这是默认方法");
        privateMethod();
    }

    /**
     * 默认方法2
     */
    default void defaultMethod2() {
        System.out.println("这是默认方法2");
        privateMethod();
    }

    /**
     * 私有方法
     */
    private void privateMethod() {
        System.out.println("这是私有方法");
    }
}

public class MyClass implements MyInterface{

    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.defaultMethod();
        myClass.defaultMethod2();
    }
}

运行结果:

这是默认方法
这是私有方法
这是默认方法2
这是私有方法

String存储结构的变化(JDK9)

JEP 254: Compact Strings

String 的存储结构,由 char[] 改成了 byte[],并且增加了一个 coder 属性来表示使用的字符编码

JDK 9 之前

image-20230821154138106

JDK 9 之后

image-20230821154208233

为什么要这么改呢,我们看下文档里是怎么说的

image-20230821154323311

大致的意思就是,原本的存储方式 char 是占2个字节(16位),实际应用程序中字符串又是使用最多的,而大多数的字符串只包含 Latin-1 字符,这个字符只需要1个字节的存储空间,而这种字符串相当于有一半的空间是浪费的。

改版之后,使用byte[],并增加了 coder 属性,这个 coder 有两个可能的值

image-20230821155423373

  • 0:表示字符串对象使用 Latin-1 编码(即只包含 ASCII 字符)
  • 1:表示字符串对象使用 UTF-16 编码(即可以包含任意 Unicode 字符)

对于每个字符串,会先判断它是不是只有 Latin-1 字符。如果是,就按照1字节的规格进行分配内存。如果不是,就按照2字节的规格进行分配。

这样改的话,内存的使用率就提升了,GC的次数会相应的减少。

快速创建只读集合(JDK9、10)

JEP 269: Convenience Factory Methods for Collections

从 JDK 9 开始,集合(List/ Set/ Map)都添加了 of (JDK9添加)和 copyOf (JDK10添加)方法,用来创建不可变的集合

public class MyTest {

    public static void main(String[] args) {
        List<String> list = List.of("Java", "Spring", "SpringBoot");
        System.out.println(list);

        Set<String> set = Set.of("Java", "Spring", "SpringBoot");
        System.out.println(set);

        Map<Integer, String> map = Map.of(1, "Java", 2, "Spring", 3, "SpringBoot");
        System.out.println(map);

        List<String> listCopy = List.copyOf(list);
        System.out.println(listCopy);

        Set<String> setCopy = Set.copyOf(set);
        System.out.println(setCopy);

        Map<Integer, String> mapCopy = Map.copyOf(map);
        System.out.println(mapCopy);
    }
}

运行结果:

[Java, Spring, SpringBoot]
[Spring, SpringBoot, Java]
{3=SpringBoot, 1=Java, 2=Spring}
[Java, Spring, SpringBoot]
[Spring, SpringBoot, Java]
{3=SpringBoot, 1=Java, 2=Spring}

JDK 的这个优化想法是不错的,但其实我们日常开发用到只读集合的场景并不多,但是可以按照这个思路,写一个快速创建可变集合的工具类

文本块(JDK13、14、15)

JEP 355: Text Blocks (Preview)

JEP 368: Text Blocks (Second Preview)

JEP 378: Text Blocks

JDK 13 开始预览,JDK 14 二次预览,JDK 15 成为正式版本

目的是简化多行字符串的创建和处理,在旧的 JDK 版本中,我们要创建一个多行字符串,需要用到转义字符和串联操作符来连接多个字符串,例如我们需要创建这样的字符串:

{
“name”: “张三”,
“age”: 18
}

之前我们的写法是这样的:

String text = "{\n" +
                "  \"name\": \"张三\",\n" +
                "  \"age\": 18\n" +
                "}";

而用文本块,我们只需要以三个双引号 """ 开始和结束,中间的内容就是字符串的具体内容,如下:

String text2 = """
                {
                  "name": "张三",
                  "age": 18
                }
                """;

更直观的 NullPointerException 提示(JDK14)

JEP 358: Helpful NullPointerExceptions

空指针异常是日常开发中非常常见的异常,但是有个问题,我们不知道具体什么对象是空的,尤其在一行代码上出现多个对象可能为空时,只能通过 debug 代码才能看出来

而 JDK 14 解决了这个问题,优化了 NullPointerException 的提示,可以一眼就看出哪个对象是空的

文档中举的例子还是比较直观的

image-20230822144848690

优化后的提示是类似这样的:

Exception in thread "main" java.lang.NullPointerException: 
        Cannot assign field "i" because "a" is null
    at Prog.main(Prog.java:5)

密封类(JDK15、16、17)

JEP 360: Sealed Classes (Preview)

JEP 397: Sealed Classes (Second Preview)

JEP 409: Sealed Classes

JDK 15 开始预览,JDK 16 二次预览,JDK 17 成为正式版本

在 JAVA 里我们可以通过继承来扩展现有类或者实现接口。这种扩展的灵活性使得类的行为变得难以预测,可能导致不必要的错误或安全漏洞

所以就出现了密封类,密封类可以用来限制子类的范围,增强代码的安全性和可维护性

使用 sealed 关键字在类或者接口前进行修饰,使用 permits 关键字来指定可以继承的类

子类也必须用 sealednon-sealedfinal 中的一种关键字修饰

  • sealed:用于声明密封类,只允许有限的子类继承。
  • non-sealed:用于声明普通类,可以被任何类所继承。
  • final:用于声明最终类,禁止继承。
public sealed class Animal permits Dog, Cat {
}

public final class Dog extends Animal {
}

public final class Cat extends Animal {
}

由于父类是密封类,指定了继承类是 Dog、Cat,这时候如果我写一个 Bird 类继承 Animal 就会报错

instanceof的模式匹配(JDK14、15、16)

JEP 305: Pattern Matching for instanceof (Preview)

JEP 375: Pattern Matching for instanceof (Second Preview)

JEP 394: Pattern Matching for instanceof

instanceof的模式匹配从 JDK 14 开始预览,JDK 15 二次预览,JDK 16 成为正式版本

简化了 instanceof 的书写方式

在 JDK 14 之前,我们需要先判断类型,再做向下转型

if (obj instanceof String) {
    String s = (String) obj;
    // use s
}

而 JDK 14 之后,可以将判断和转型合并成一步

if (obj instanceof String s) {
    // can use s here
}

另外,因为 instanceof 的新变量作用域只在if语句里,如果后面接 && (与操作)可以继续使用instanceof 的变量,如下:

if (obj instanceof String s && s.length() > 5) {.. s.contains(..) ..}

但是由于短路操作,所以后面接||(或操作)就不能使用 instanceof 的变量,因为有可能 instanceof 不满足新变量未定义,如下:

if (obj instanceof String s || s.length() > 5) {.. s.contains(..) ..}

image-20230822160906358

switch增强(JDK12、13、17)

JEP 325: Switch Expressions (Preview)

JEP 354: Switch Expressions (Second Preview)

JEP 361: Switch Expressions

JEP 406: Pattern Matching for switch (Preview)

  • 在 JDK 7 版本之前 switch 语句只能使用整数(byte、short、int)和字符类型(char)作为表达式,并且只支持单个 case 分支,没有 break 会穿透到下一个 case。
  • 在 JDK 7 版本里,增加了支持字符串类型(String)和枚举类型(enum)。
  • 在 JDK 12 版本里,增加了 switch 表达式,用箭头(->)代替冒号(:)
  • 在 JDK 13 版本里,增加了 yield 关键字
  • 在 JDK 17 版本里,支持 switch 类型,简化原本 instanceof 的写法,并且支持 case null,对于枚举类和密封类会进行完整性校验,从而不用写 default 分支

在 JDK 12 之前,我们是这么写的

public static void main(String[] args) {

    int month = 1;
    switch (month) {
        case 1, 2, 3, 4, 5, 6:
            System.out.println("上半年");
            break;
        case 7, 8, 9, 10, 11, 12:
            System.out.println("下半年");
            break;
        default:
            System.out.println("不存在的月份");
            break;
    }
}

为了防止穿透,我们必须要写上 break,而在 JDK 12 之后,用 switch 表达式写,可以省略 break

public static void main(String[] args) {

    int month = 1;
    switch (month) {
        case 1, 2, 3, 4, 5, 6 -> System.out.println("上半年");
        case 7, 8, 9, 10, 11, 12 -> System.out.println("下半年");
        default -> System.out.println("不存在的月份");
    }
}

如果有返回值,可以这么写

public static void main(String[] args) {

    int month = 1;
    String text = switch (month) {
        case 1, 2, 3, 4, 5, 6 -> "上半年";
        case 7, 8, 9, 10, 11, 12 -> "下半年";
        default -> "";
    };
    System.out.println(text);
}

在 JDK 13版本之后,我们也可以使用 yield 关键字来设置返回值

public static void main(String[] args) {

    int month = 1;
    String text = switch (month) {
        case 1, 2, 3, 4, 5, 6:
            yield "上半年";
        case 7, 8, 9, 10, 11, 12:
            yield "下半年";
        default:
            yield "";
    };
    System.out.println(text);
}

在 JDK 17 版本之后,对于一个 Object 向下转型时,可以摆脱 instanceof + cast 了

之前的写法

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;
}

JDK 17 之后

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();
    };
}

另外支持 case null

static void test(Object o) {
    switch (o) {
        case null     -> System.out.println("null!");
        case String s -> System.out.println("String");
        default       -> System.out.println("Something else");
    }
}

对于枚举类和密封类会进行完整性校验,从而不用写 default 分支

sealed interface S permits A, B, C {}
final class A implements S {}
final class B implements S {}
record C(int i) implements S {}  // Implicitly final

static void switchStatementComplete(S s) {
    switch (s) {    // Error - incomplete; missing clause for permitted class B!
        case A a :
            System.out.println("A");
            break;
        case C c :
            System.out.println("C");
            break;
    };
}

如果少写一个 B 的情况,编译期会报错

image-20230822141212160

枚举也是同样的道理

垃圾收回相关优化(JDK9-17)

JDK9

  • 将G1设置为默认垃圾回收器:JEP 248: Make G1 the Default Garbage Collector

JDK10

  • 废弃 CMS 垃圾回收器:JEP 291: Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector
  • 引入G1垃圾回收器的并行Full GC功能:JEP 307: Parallel Full GC for G1

JDK11

  • 革命性的 ZGC 登场:JEP 333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental)

JDK12

  • 引入 Shenandoah GC,低暂停时间的垃圾回收器:JEP 189: Shenandoah: A Low-Pause-Time Garbage Collector (Experimental)

  • G1可以在收集的过程中中止:JEP 344: Abortable Mixed Collections for G1

  • G1自动返回未用堆内存给操作系统:JEP 346: Promptly Return Unused Committed Memory from G1

JDK13

  • ZGC 将未使用的堆内存返回到操作系统:JEP 351: ZGC: Uncommit Unused Memory (Experimental)

JDK14

  • 通过实现 NUMA 感知内存分配,提高大型机器上的G1性能:JEP 345: NUMA-Aware Memory Allocation for G1
  • 删除 CMS 垃圾回收器:JEP 363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector
  • 将 ZGC 垃圾收集器移植到 macOS:JEP 364: ZGC on macOS (Experimental)
  • 将 ZGC 垃圾收集器移植到 Windows:JEP 365: ZGC on Windows (Experimental)
  • 废弃 ParallelScavenge + SerialOld GC 的组合:JEP 366: Deprecate the ParallelScavenge + SerialOld GC Combination

JDK15

  • ZGC 正式上线:JEP 377: ZGC: A Scalable Low-Latency Garbage Collector (Production)
  • Shenandoah GC 正式上线:JEP 379: Shenandoah: A Low-Pause-Time Garbage Collector (Production)

JDK16

  • ZGC 支持并发栈处理:JEP 376: ZGC: Concurrent Thread-Stack Processing

三、总结

JDK 9-17 增加了许多新的特性,对我们的日常开发有很大帮助,JDK 11推出的 ZGC 是一款性能比 G1 还要好的垃圾回收器,JDK 17 也是史上最快的 Java 版本。

Spring Boot 3.0 的最低支持版本已经提升到 JDK 17,并且不再向下兼容 JDK 8,开发者从 JDK 8 转移到 JDK 17 将是大势所趋,我们不能畏惧新的东西,保持学习的姿态,通过阅读文档和实践,不断的进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/950336.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

exe软件监控看门狗使用说明

作为物联网数据采集解决方案专业提供商,数采物联网 小编daq-iot在这里做以下内容介绍,并诚挚的欢迎大家讨论和交流。 1.软件概述 本软件功能用途&#xff1a;监控电脑或服务器exe程序运行&#xff0c;在exe程序由于异常或其他原因退出后&#xff0c;自动启动exe程序&#xff0…

goroutine的一点东西

前面的两篇&#xff0c;从相对比较简单的锁的内容入手(也是干货满满)&#xff0c;开始了go的系列。这篇开始&#xff0c;进入更核心的内容。我们知道&#xff0c;go应该是第一门在语言层面支持协程的编程语言(可能是我孤陋寡闻)&#xff0c;goroutine也完全算的上是go的门面。g…

文件属性查看和修改学习

这个是链接&#xff0c;相当于快捷方式&#xff0c;指向usr/bin这个目录&#xff0c;链接到这个目录

NRF52832一主多从ble_app_multilink_central

下载官方SDK后打开路径&#xff1a;nRF5SDK153059ac345\nRF5_SDK_15.3.0_59ac345\examples\ble_central\ble_app_multilink_central\pca10040\s132\arm5_no_packs 下的工程文件&#xff0c;确定把log开启 编译后下载完程序(要下载协议栈&#xff0c;这里用6.1.1的)&#xff0c…

FPGA原理与结构——时钟IP核原理学习

一、前言 在之前的文章中&#xff0c;我们介绍了FPGA的时钟结构 FPGA原理与结构——时钟资源https://blog.csdn.net/apple_53311083/article/details/132307564?spm1001.2014.3001.5502 在本文中我们将学习xilinx系列的FPGA所提供的时钟IP核&#xff0c;来帮助我们进一…

实现带头双向循环链表

&#x1f308;带头双向循环链表 描述&#xff1a;一个节点内包含两个指针&#xff0c;一个指向上一个节点&#xff0c;另一个指向下一个节点。哨兵位指向的下一个节点为头节点&#xff0c;哨兵位的上一个指向尾节点。 结构优势&#xff1a;高效率找尾节点&#xff1b;高效率插入…

RabbitMQ工作模式-主题模式

主题模式 官方文档参考&#xff1a;https://www.rabbitmq.com/tutorials/tutorial-five-python.html 使用topic类型的交换器&#xff0c;队列绑定到交换器、bingingKey时使用通配符&#xff0c;交换器将消息路由转发到具体队列时&#xff0c;会根据消息routingKey模糊匹配&am…

[学习笔记] fhq Treap 平衡树

fhq Treap 也叫无旋Treap &#xff08;好像&#xff1f;我也不知道&#xff09; 反正我带旋 Treap 是不会滴&#xff0c;其他的平衡树也不会&#xff08;但是会平板电视&#xff09; fhq Treap 好写&#xff0c;码量小&#xff0c;缺点是常数比较大 定义 二叉搜索树 二叉搜…

为什么说模电难学?因为它至少是这27个基础知识的排列组合!

1、基尔1、基尔霍夫定理的内容是什么&#xff1f; 基尔霍夫电流定律&#xff1a;在电路任一节点&#xff0c;流入、流出该节点电流的代数和为零。 基尔霍夫电压定律&#xff1a;在电路中的任一闭合电路&#xff0c;电压的代数和为零。 2、戴维南定理 一个含独立源、线性电阻…

在抖音开店卖货的流程是什么?最全解答如下,建议新手认真看完!

我是王路飞。 同样是在抖音卖货&#xff0c;为何如今大多数人都是选择在抖音开店&#xff0c;而不再是选择做账号、开直播了呢&#xff1f; 原因很简单&#xff0c;因为门槛和变现方式。 相比短视频和直播带货的起号、变现难度越来越大&#xff0c;低门槛的抖音小店显然更适…

Origin热图的做法

1.数据准备 2.绘制-选择带标签热图 3.图表调整 右边标签- 下方标签-复制格式&#xff0c;再到左边或者右边选择 粘贴所有 图中的标签及颜色 直接双击在属性框更改 主框的其他特征在属性框选择 色阶的控制 直接选择色阶的属性框

Endnote中查看一个文献的分组的具体方法——以Endnote X8为例

Endnote中查看一个文献的分组的具体方法——以Endnote X8为例 一、问题 当Endnote中使用分类方法对文献进行分组管理后&#xff0c;有时需要重新调整该文献的分组&#xff0c;则需要找到这个文献在哪个分组中。本文阐述怎样寻找一个文献的分组的位置信息。 二、解决方法 1.选…

Spooling的原理

脱机技术 程序猿先用纸带机把自己的程序数据输入到磁带中&#xff0c;这个输入的过程是由一台专门的外围控制机实现的。之后CPU直接从快速的磁带中读取想要的这些输入数据。输出也类似。 假脱机技术&#xff08;Spooling技术&#xff09; 即用软件的方式来模拟脱机技术。要…

Kubernetes技术--k8s核心技术Controller控制器

1.Controller概述 Controller是在集群上管理和运行容器的对象。是一个实际存在的对象。 2.pod和Controller之间的关系 pod通过controller实现应用的运维,包括伸缩、滚动升级等操作。 这里pod和controller通过label标签来建立关系。如下所示: 3.Deployment控制器应用场景 -1:…

RabbitMQ工作模式-发布订阅模式

Publish/Subscribe&#xff08;发布订阅模式&#xff09; 官方文档&#xff1a; https://www.rabbitmq.com/tutorials/tutorial-three-python.html 使用fanout类型类型的交换器&#xff0c;routingKey忽略。每个消费者定义生成一个队列关绑定到同一个Exchange&#xff0c;每个…

win10底部任务栏开机后长时间未响应的解决办法

https://blog.csdn.net/hj960511/article/details/128746025?share_tokenAA088876-4477-44B8-B978-5C7C7726D552&tt_fromcopy_link&utm_sourcecopy_link&utm_mediumtoutiao_ios&utm_campaignclient_share win10底部任务栏开机后长时间未响应的解决办法-CSDN博…

亚马逊云科技re:Inforce大会:为企业提供端到端的安全防护能力

2023年&#xff0c;生成式AI带来了无数的创新&#xff0c;并将会在行业应用中产生更多的新能力、新场景。与此同时&#xff0c;关于生成式AI的风险管控成为各方关注焦点&#xff0c;数据隐私、合规保护、防欺诈等&#xff0c;已成为生成式AI时代的安全合规的新话题。 随着云上业…

(一)SpringBoot 整合WebSocket 前端 uniapp 访问

第一次使用WebSocket&#xff0c;所以最需要一个及其简单的例子&#xff0c;跑通之后&#xff0c;增加自己对该技术的理解。&#xff08;技术基础介绍就免掉了&#xff0c;后面再补&#xff09; 案例逻辑&#xff1a;目前只有一个用户&#xff0c;而且是一个用户给服务器发送数…

linux系统中详解u-boot之网络移植与调试

​今天给大家讲一讲如何完善u-boot网络部分的移植和调试。 一、前章回顾 上一章&#xff0c;已经讲过如何讲uboot.2022.10版本移植到我们自己的imx6ull开发板上&#xff0c;但是最后编译下载后网络部分未能正确识别&#xff0c;今天我们就来讲一讲网络部分的调试。 上一篇ub…

静力触探数据智能预处理(2)

静力触探数据智能预处理&#xff08;2&#xff09; 前言 数据处理方式已由手工1.0、计算机辅助2.0到人工智能3.0的趋势发展。现场采集的静力触探数据通常是由仪器厂家开发的数据采集软件保存&#xff0c;将原始数据导入Excel中&#xff0c;数据格式需要花费一定的时间整理&am…