• [Java Base]Java 8 ~ Java17新特性


    资源

    📁 JDK-downloads

    在这里插入图片描述

    内容详情

    Java 9 ~ 11:

    ZGC垃圾回收器

    据说这是JDK11最为瞩目的特性,没有之一,是最重磅的升级,那么ZGC的优势在哪里呢?

    • GC暂停时间不会超过10毫秒
    • 既能处理几百兆的小堆,也能处理几个T的大堆
    • 和G1相比,应用吞吐能力不会下降超过15%
    • 为未来的GC功能和利用colord指针以及Load barriers优化奠定了基础

    ZGC是一个并发、基于region、压缩型的垃圾收集器,只有root扫描阶段会STW(strop the world,停止所有线程),因此ZGC的停顿时间不会随着堆的增长和存活对象的增长而变长。用法:-XX:UnlockExperimentalVMOptions -XX:+UseZGC

    字符串API增强

    // 用来判断字符串是不是空字符"“或者trim()之后(” ")为空字符:
    isBlank()
    //将一个字符串按照行终止符(换行符\n或者回车符\r)进行分割,并将分割为Stream流:
    lines()
    //按照给定的次数重复串联字符串的内容:
    repeat(n)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    集合转对应类型的数组

    之前想集合转对应的数组很麻烦,要么用迭代;要么用Stream流,现在你可以这样:

             List<String> sampleList = Arrays.asList("张三", "java 11");
             // array = {"张三", "java 11"};
             String[] array = sampleList.toArray(String[]::new);
    
    • 1
    • 2
    • 3

    var可以用于修饰Lambda局部变量

    在Java 10中引入的var来进行类型推断。在Java 10中它不能用于修饰Lambda表达式的入参,其实对于一个Lambda表达式来说它入参的类型其实是可以根据上下文推断出来的。拿上面的例子来说,s -> s.startsWith(“j”)中的s肯定是字符串类型,因此在Java 11中var可以用于修饰Lambda局部变量:

       List<String> sampleList = Arrays.asList("张三", "java 11","jack");
            List<String> result = sampleList.stream()
                    // 过滤以j开头的字符串
                    .filter((@NotNull var s) -> s.startsWith("j"))
                    // 同时不包含11的字符串
                    .filter(Predicate.not((@NotNull var s) -> s.contains("11")))
                    .collect(Collectors.toList());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    文件中读写字符串内容更方便

    Java 11中可以更轻松地从文件中读取和写入字符串内容了,我们可以通过Files工具类提供的新的静态方法readString和writeString分别进行读写文件的字符串内容,放在之前老麻烦了,特别是对IO流不熟悉的同学来说。现在简单几行就搞定了:

            String dir= "C://yourDir/hello.txt";
    // 写入文件
            Path path = Files.writeString(Path.of(dir), "hello java 11");
    // 读取文件
                String fileContent = Files.readString(path);
                // hello java 11
            System.err.println(fileContent);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Java 12~17:

    文本块
    switch表达式
    record关键字
    sealed classes密封类
    instanceof模式匹配
    Helpful NullPointerExceptions
    日期周期格式化
    精简数字格式化支持
    Stream.toList()简化

    文本块 (Java17)

    假设有这样一个场景,我们需要做一个工具。用来自动生成项目文档,文档可以通过浏览器查看,所以最后产出物肯定是一堆html文件。为了让这些html文件更容易读,良好的格式肯定要保持,该换行的换行、该缩进的缩进。
    那么,在组织最后内容的时候,你可能就会这样子来写:

    String html = 
        "\n" +
        "\n"+
        "  

    Java 17新特性:文本块 -0xYGC

    \n"
    + "

    didispace.com

    \n"
    + "\n"+ "\n";
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    当然,也许你也会改进一下,用StringBuilder或者StringBuffer来优化,但不论用什么来写,都逃不了一些要转义的内容,比如上面拼接内容时候的换行\n。

    一旦存在大量要转义内容的时候,也就增加了我们编写代码的复杂度。复杂度越高,我们就越容易犯错。所以,在Java 17中增加了一个新特性:文件块(Text Blocks),来帮助我们更便捷的实现多行字符串文字的处理。
    对于上面的字符串内容,Java 17中,我们只需要这样写:

    String html = """
        
        
          

    Java 17新特性:文本块 -0xYGC

    didispace.com

    """
    ;
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    像这种改进还是特别有用的,比如ES的最新客户端支持DSL部分脚本代码运行, Flink 也支持SQL脚本,以及 Sping Data JPA等等

    switch表达式

    Java 17版本中switch表达式将允许switch有返回值,并且可以直接作为结果赋值给一个变量,等等一系列的变化。下面有一个switch例子,依赖于给定的枚举值,执行case操作,故意省略break。

        private static void lowVesion(Fruit fruit) {
            switch (fruit) {
                case APPLE, PEAR:
                    System.out.println("普通水果");
                case MANGO, AVOCADO:
                    System.out.println("进口水果");
                default:
                    System.out.println("未知水果");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    我们调用这个方法传入一个APPLE,会输出以下结果: 普通水果进口水果未知水果
    显然这不是期望的结果,因为我们需要在每个case里添加break防止所有的case都被执行。
    Java17可以通过switch表达式来进行简化。将冒号(:)替换为箭头(->),并且switch表达式默认不会失败,所以不需要break。

        private static void withReturnValue(Fruit fruit) {
            String text = switch (fruit) {
                case APPLE, PEAR -> "普通水果";
                case MANGO, AVOCADO -> "进口水果";
                default -> "未知水果";
            };
            System.out.println(text);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    也可以直接省略赋值动作直接打印。

        private static void withReturnValue(Fruit fruit) {
            System.out.println(switch (fruit) {
                case APPLE, PEAR -> "普通水果";
                case MANGO, AVOCADO -> "进口水果";
                default -> "未知水果";
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果你想在case里想做不止一件事,比如在返回之前先进行一些计算或者打印操作,可以通过大括号来作为case块,最后的返回值使用关键字yield进行返回。

        private static void withYield(Fruit fruit) {
            String text = switch (fruit) {
                case APPLE, PEAR -> {
                    System.out.println("给的水果是: " + fruit);
                    yield "普通水果";
                } case MANGO, AVOCADO -> "进口水果";
                default -> "未知水果";
            }; System.out.println(text);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Records关键字(Java14 添加)

    record用于创建不可变的数据类。在这之前如果你需要创建一个存放数据的类,通常需要先创建一个Class,然后生成构造方法、getter、setter、hashCode、equals和toString等这些方法,或者使用Lombok来简化这些操作。

    通过对类做这样的声明,编译器可以通过自动创建所有方法并让所有字段参与hashCode()等方法。这是JDK 14中的一个预览特性。
    使用record关键字可以定义一个记录:

        record Person (String firstName, String lastName) {}
    
    • 1

    假设有一些场景我们只需要对Person的name和age属性进行打印,在有record之后将会变得非常容易。

    PersonRecord p1Record = new PersonRecord(p1.getName(), p1.getAge());
    PersonRecord p2Record = new PersonRecord(p2.getName(), p2.getAge());
    System.out.println(p1Record);
    System.out.println(p2Record);
    
    • 1
    • 2
    • 3
    • 4

    record 解决了使用类作为数据包装器的一个常见问题。纯数据类从几行代码显著地简化为一行代码。(详见: Java 14 发布了,不使用”class”也能定义类了?还顺手要干掉Lombok! )

    封闭类 (Java15)

    在Java 15之前,Java认为"代码重用"始终是一个终极目标,所以,一个类和接口都可以被任意的类实现或继承。但是,在很多场景中,这样做是容易造成错误的,而且也不符合物理世界的真实规律。

    例如,假设一个业务领域只适用于汽车和卡车,而不适用于摩托车。在Java中创建Vehicle抽象类时,应该只允许Car和Truck类扩展它。通过这种方式,我们希望确保在域内不会出现误用Vehicle抽象类的情况。为了解决类似的问题,在Java 15中引入了一个新的特性——密闭。
    想要定义一个密闭接口,可以将sealed修饰符应用到接口的声明中。然后,permit子句指定允许实现密闭接口的类:

        public sealed interface Service permits Car, Truck {     }
    
    • 1

    通过密闭特性,我们定义出来的Vehicle类只能被Car和Truck继承。

    Sping Boot 3.0 已经最低要Java 17了,
    2022-06-28 发布的 Jenkins 2.357 和即将发布的 9 月 LTS 版本开始,Jenkins 最低需要 Java 11
    Kafka3.0弃用Java 8

    日期周期格式化

    在Java 17中添加了一个新的模式B,用于格式化DateTime,它根据Unicode标准指示一天时间段。使用默认的英语语言环境,打印一天的几个时刻:

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("B");
    System.out.println(dtf.format(LocalTime.of(8, 0)));
    System.out.println(dtf.format(LocalTime.of(13, 0)));
    System.out.println(dtf.format(LocalTime.of(20, 0)));
    System.out.println(dtf.format(LocalTime.of(23, 0)));
    System.out.println(dtf.format(LocalTime.of(0, 0)));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 输出结果:
      in the morningin the afternoonin the eveningat nightmidnight
      如果是中文语言环境,则输出结果为:
      上午下午晚上晚上午夜

    精简数字格式化支持

    在NumberFormat中添加了一个工厂方法,可以根据Unicode标准以紧凑的、人类可读的形式格式化数字。

    NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.ENGLISH, NumberFormat.Style.SHORT);
    System.out.println(fmt.format(1000));
    System.out.println(fmt.format(100000));
    System.out.println(fmt.format(1000000));
    
    • 1
    • 2
    • 3
    • 4

    输出格式为:1K100K1M
    当然还有其他格式:比如Long类型线显示成数值可以为:1 thousand100 thousand1 million

    Java 18~19:

    JDK 18

    🔗 JDK 18 新特性官网
    在这里插入图片描述

    🔗 Java 18 新特性

    JDK 19

    🔗 Java 19 正式发布,改善多线程、并发编程难度

    参考资料 & 致谢

    [1] Java 17 新特性:文本块

  • 相关阅读:
    运行springboot时提示:源值 7 已过时,将在未来版本中删除,并且提示java.time not exist, LocaDateTime类找不到。
    【VMware vSphere】使用RVTools中的PowerShell脚本创建导出vSphere环境信息的自动化任务。
    设计模式---装饰者模式
    python 格式化字符串的方法
    PS不能完成命令,因为没有足够内存(RAM)
    适合中小企业的项目管理系统有哪些?
    JavaScript-Vue基础语法-创建-组件-路由
    反射 - 枚举 - Lambda表达式
    2022千元无线蓝牙耳机,音质超高的千元蓝牙耳机品牌
    Google Earth Engine ——
  • 原文地址:https://blog.csdn.net/YangCheney/article/details/126037021