Java 9 - 18 各版本新特性介绍

     【视频中第7个视频语法改进,4分16秒 dropWhile有误,注意!!!】

【 Java 9 - 18 各个版本新特性总结,B站视频介绍】https://www.bilibili.com/video/BV1PT411P7Wn?vd_source=5a3a58ca0e99223ffb58cddf2f3a7282

一、模块化引入

        模块是 Java 9 中新增的一个组件,可以简单理解为是package的上级容器,是多个package的集合,一个jar可以有多个module,一个module可以有多个package。从代码结构上看:jar > module > package > class, interface

Java 9 - 18 各版本新特性介绍_第1张图片

        Java 9 的模块通过 requires 和 exports 关键字,对自身所依赖(requires)的模块和自身暴露(exports)出去的内容(package)进行了声明。本模块只能使用其他模块暴露(exports)出来的内容(package),其他模块也只能使用本模块暴露(exports)出去的内容(package)。

Java 9 - 18 各版本新特性介绍_第2张图片

二、String 底层存储结构变化

        对字符串采用更节省空间的内部表达,以提高字符串的内部表示中使用代替编码。

        在 Java8 中String的是实现是将字符存储在一个char类型的数组中,而char类型是由两个字节组成。但是Java官方人员根据上万个应用程序的heap dump信息进行了分析,大多数String对象仅包含Latin-1字符。此类字符只需要一个字节的存储空间,因此String对象内部char中的一半空间其实是未使用的。并且字符串都是用String Pool 来存储的,String Pool 通常使用了 JVM 的 heap 内存空间,Heap 内存空间又是 JVM 垃圾清理程序活动的地方。这样做不仅仅可以提高内存空间的使用率并且还能减少JVM垃圾清理的工作量。

        简单来讲就是:Java8 之前 String 的底层结构类型都是 char[] ,在 Java9 替换成 byte[] 这样就能更节省空间和提高性能。

        之所以替换是因为 之前一直是最小单位是一个char,用到两个byte,但是 Java8 是基于latin1的,而这个latin1编码可以用一个byte标识,所以当你数据明明可以用到一个byte的时候,我们用到了一个最小单位chat两个byte,就多出了一个byte的空间。所以Java9 在这一方面进行了更新,现在的Java9 是基于ISO/latin1/Utf-16  ,latin1和ISO用一个byte标识,UTF-16用两个byte标识,Java9 会自动识别用哪个编码,当数据用到1byte,就会使用iSO或者latin1 ,当空间数据满足2byte的时候,自动使用utf-16,节省了很多空间。

        同理,StringBuilder StringBuffer也更换了底层数据结构。

三、多版本兼容Jar

        多版本JAR(MR JAR)可能包含同一类的多个变体,每个变体都针对特定的Java版本。 在运行时,类的正确变体将被自动加载,这取决于所使用的Java版本。这允许库作者在早期利用新的Java版本,同时保持与旧版本的兼容性。

应用场景:

        比如某个架构师开发了一个工具类MyUtils,该工具类里面使用了jdk9的新特性,这时候该 具在推广的时候会遇到很大的阻力,因为很多用户还没有升级jdk版本,JDK9推出了多版本兼用jar的特性就允许该架构师编写一个同类名的工具MyUtils,并在该工具类中不使用jdk9的新特性,然后两个同类名的类一起打包成为一个jar,提供给用户去使用,这时候即可根据用户当前使用的jdk版本而选择不同的 工具类了。

util.jar
│ MyUtils.class

└─META-INF
   │ MANIFEST.MF
   │
   └─versions
 └─9
  MyUtils.clas

简言之:

        该jar包在java 8中可以执行最上层的MyUtils.class,在Java 9中自动选择执行目录9下的 MyUtils.class。

四、接口私有方法

        当我们在一个接口里写多个默认方法或者静态方法的时候,可能会遇到程序重复的问题。我们可以把这些重复的程序提取出来,创建一个新的方法,用private进行修饰,这样就创造了一个只有接口可以调用 的私有方法。

    public interface UserDao {
        default void methodA(){
            System.out.println("methodA...");
            System.out.println("A....");
            System.out.println("B....");
            System.out.println("C....");

        }

        default void methodB(){
            System.out.println("methodB...");
            System.out.println("A....");
            System.out.println("B....");
            System.out.println("C....");
        }
    } 

        以上代码的methodA与methodB存在着代码冗余问题,我们可以把这部分公共的方法抽取成私有的方法提供给接口内部去使用。

    public interface UserDao {
        default void methodA(){
            System.out.println("methodA...");
            commons();
        }

        default void methodB(){
            System.out.println("methodB...");
            commons();
        }

        //定一个私有的方法,把重复部分的代码抽离出来。然后在methodA与methodB方法内部去调用。
        //私有方法只能在本类中调用,这里包括接口的实现类也不能调用。
        private void commons(){
            System.out.println("A....");
            System.out.println("B....");
            System.out.println("C....");

        }

五、JShell工具 

        针对于Java9来说,相当于cmd工具,可以和cmd一样,直接写方法等等,不过我认为只是适用于初学者做一些最简单的运算和写一些方法。

Java 9 - 18 各版本新特性介绍_第3张图片

六、try-with-resources 增强 

         动机:try-with-resources 声明在 JDK 9 已得到改进。如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量

        介绍 :try-with-resources 是 JDK 7 中一个新的异常处理机制,它能够很容易地关闭在 try-catch语句块中使用的资源。所谓的资源(resource)是指在程序完成后,必须关闭的对象。try-with-resources 语句确保了每个资源在语句结束时关闭。所有实现了 java.lang.AutoCloseable 接口(其中,它包括实现了 java.io.Closeable 的所有对象),可以使用作为资源。
  • java7之前 try的使用

        这里主要突出必须对资源(比如说IO流)进行显式关闭。
Java 9 - 18 各版本新特性介绍_第4张图片
  •  java8 中try的新用法

         这里突出,资源不需要在进行显式关闭,只需要将资源的实例化对象放在try后面的括号中,使用结束后便会自动关闭。

Java 9 - 18 各版本新特性介绍_第5张图片

  • java9 中try的变化

       可在try后面的括号中放入已经实例化过的对象。但是需要注意的是:这里所说的实例化对象默认被final修饰,所以在try中不能再对其进行修改,否则会报错;再者,try后面的()可以放入多个实例化对象,对象之间用分号隔开。

Java 9 - 18 各版本新特性介绍_第6张图片

七、语法改进(下划线使用限制)

        Java8 之前 String _ ="hello"; 这样的标识符可以用,但在Java9中进行了限制使用。

八、Stream、Optional 增强,集合增强

1.在原有Stream API 新添加了4个方法,takeWhile、dropWhile、ofNullable、iterate(新重载方法)

  • Stream.takeWhile(Predicate)

        在进行Stream流的管道数据处理的时候,提供的Predicate条件返回false之后,将跳过剩余的数据元素直接返回。

        String[] fruits = {"apple", "banana", "orange", "mango", "peach"};
        Stream stream = Arrays.stream(fruits).takeWhile(s -> !"orange".equals(s));
        stream.forEach(System.out::println);

 输出:

apple
banana

注意:

        对于无序Stream,如果存在多个与提供的Predicate匹配的元素(多个orange),则此操作返回值是不确定的。这种方法看上去和Java 8中的Stream.filter()很相似,但是它们的不同之处在filter()方法只是跳过了不匹配的元素,然后继续进行处理。然而takeWhile()方法在存在匹配项之后会跳过所有剩余的元素,有点像continue和break的区别

  • Stream.dropWhile(Predicate)

   提供的Predicate条件在管道流中返回false之后,此元素后面的所有数据元素作为返回值返回

        String[] fruits = {"apple", "banana", "orange", "mango", "orange",  "peach"};
        Stream stream = Arrays.stream(fruits).dropWhile(s -> !"orange".equals(s));
        stream.forEach(System.out::println);

输出:

orange
mango
orange
peach 

  • Stream Stream.iterate(T,Predicate,UnaryOperator)

        一旦Predicate条件返回false,此方法将返回一个顺序流,该顺序流将停止迭代操作。T为初始值,迭代操作由UnaryOperator来提供。

        Stream iterate = Stream.iterate("-",
                s -> s.length() < 5, //Predicate条件
                s -> s + "-"); //迭代操作
        iterate.forEach(System.out::println);

输出:

-
--
---
----

  • Stream Stream.ofNullable(T)

        此方法返回一个包含单个元素的顺序Stream。如果提供的元素为null,则此方法返回空Stream。当我们要将非空单个元素附加到流时,此方法很有用

        String nullableItem = "peach";
        Stream stream = Stream.of("apple", "banana", "orange");
        Stream stream2 = Stream.concat(stream, Stream.ofNullable(nullableItem));
        stream2.forEach(System.out::println);

输出:

apple
banana
orange
peach 

2.Optional的增强与优化

  •  ifPresentOrElse(Consumer,Runnable)
  • Optional.or(Supplier)
  • Optional.stream()

3.collection集合类的增强与优化 

  • 提供Of()方法创建集合
  • Arrays增强mismatch()和equals()方法

九、局部变量推导

        引入了其他语言中很常见的“var”,其表现形式也类似于JavaScript的中的"var",只要编译器可以推断此种类型,你就不再需要专门声明一个局部变量的类型。

十、简化启动单个源文件的方法

    //编译
    javac Javastack.java
    //运行
    java Javastack

        在我们的认知里面,要运行一个Java源代码必须先编译,再运行,两步执行动作。而在未来的Java11版本中,通过一个java命令就直接搞定了。

        java test.java文件即可, 包含了之前的javac, java命令

一个命令编译运行源代码的注意点:

  • 执行源文件中的第一个类, 第一个类必须包含主方法。
  • 并且不可以使用其它源文件中的自定义类, 本文件中的自定义类是可以使用的。

 十一、改进NullPointerException

        Java 14中改进了NullPointerException,可以帮助开发人员快速准确定位到是哪个值空值了。

十二、文字块

        Java 17提供了文字块,优化注释和代码编写并提高可读性。

改进前:

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

Java 17新特性:文本块 | 程序猿DD

\n"+
    "  

didispace.com

\n"+
    "\n"+
    "

改进后:

String html = """
   
   
     

Java 17新特性:文本块 | 程序猿DD


     

didispace.com


   
     

十三、instanceof模式匹配

  Java 16中提供的新特性instanceof增强,主要用来判断某个对象是不是某个类的实例。从而减少冗余代码。

Java 9 - 18 各版本新特性介绍_第7张图片

十四、record不可修改的透明数据类

        以前我们定义类都是用class关键词,但从Java 16开始,我们将多一个关键词record,它也可以用来定义类。record关键词的引入,主要是为了提供一种更为简洁、紧凑的final类的定义方式。

十五、封闭类

        Java 17推出的新特性Sealed Classes经历了2个Preview版本(JDK 15中的JEP 360、JDK 16中的JEP 397),最终定稿于JDK 17中的JEP 409。Sealed Classes有两种主流翻译:密封类、封闭类。

sealed:修饰类/接口,用来描述这个类/接口为密封类/接口
non-sealed:修饰类/接口,用来描述这个类/接口为非密封类/接口
permits:用在extends和implements之后,指定可以继承或实现的类

/**
 * 利用关键词sealed来声明密封类 Animal
 * 用permits表示只有Pig,Dog,Birds类可以继承Animal
 */
public sealed class Animal  permits Pig,Dog,Birds{
}

/**
 *每个被允许的子类都需要使用修饰符来描述如何往下传递密封行为
 * 声明为 final 来禁止继续继承。
 */
public final class Pig extends Animal{
}

/**
 * 每个被允许的子类都需要使用修饰符来描述如何往下传递密封行为
 * 声明为 sealed 以同样的方式来限制继承。
 */
public sealed class Birds extends Animal permits Sparrow{
}

/**
 * 每个被允许的子类都需要使用修饰符来描述如何往下传递密封行为。
 * 声明为 non-sealed 来恢复为开放继承。
 */
public non-sealed class Dog extends Animal{
}

 十六、升级switch表达式

        从Java 12开始,switch语句升级为更简洁的表达式语法,去除了break并提供了新的yield。

改进前:

public static void main(String[] args) {
    int level = new Random().nextInt(4);
    String str = "";
    switch(level){
        case 1:
            str = "优";
            break;
        case 2:
            str = "良";
            break;
        case 3:
            str = "差";
            break;
        default:
            str = "不及格";
            break;
    }
}

改进后:

public static void main(String[] args) {
    int level = new Random().nextInt(4);
    var str = "";
    switch(level){
        case 1 -> str = "优";
        case 2 -> str = "良";
        case 3 -> str = "差";
        default-> str = "不及格";
    }
}
yield的使用:

public static void main(String[] args) {
    int level = new Random().nextInt(4);
    String str = switch(level){
        case 1,3 -> {
            System.out.println("ssss");
            yield "优";
        }
        case 2 -> {
            int a = 0;
            yield "优";
        }
        default-> {
            int b = 1;
            System.out.println("ssss");
            yield "优";
        }
    };

}

十七、简单的web服务器 jwebserver

        Java 18推出的一个比较独立的全新功能点。我们可以通过命令行工具来启动一个提供静态资源访问的迷你Web服务器。

十八、其他特性

        待补充...

参考:

         Java9新特性、Java10新特性、Java11新特性

你可能感兴趣的:(Java后端技术栈知识体系整理,java,开发语言,mybatis)