JDK9~17新特性

JDK9

JShell

也就是交互式编程,通过命令行实时编程显示结果,就像scala,python等一样。

实际上方便的做Java教学。

唤起

直接在终端输入

1
> jshell

image-20240928190607995

逻辑

在jshell命令行中,输入的代码默认其实就是在main方法里面的代码。命令行执行过的代码有顺序关系,前面可以定义变量,后面可以读取使用。可以不用输入分号。

image-20240928190842771

模块化开发

之前学过ES6,其中就包括模块化开发。几个关键字import,export,就可以体现模块化开发的意义。

向外部暴露一些接口,而大部分的供内部使用隐藏起来。这就是模块化开发。

模块所处的位置是,包接口的外层。

image-20240928192035020

之前的开发

在这之前,不同的模块之间的相互引用是通过添加依赖的方式,就像maven的依赖管理一样,将别的模块导入。

这样实际上依赖模块的所有class都暴露的了出来。

如果添加模块管理文件

在jdk9之后,可以给模块根目录下(也就是src目录下)添加名为module-info.java的文件,就表明这个模块启用模块化管理功能,别的同样启用这个功能的模块就会根据文件重定义的接口规则去发现规定中的接口,不在文件中定义的class不会被发现。

module-info.java的语法

像ES6一样的,需要export导出和import导入,但是import已经被包使用了,所以模块只能使用requires 关键字来表示需要导入。

(注意java中的关键字是exports和requires,都是加s的,也就是说,可以通过逗号隔开来一次导出导入很多个)

导出

导入

JDK10

var局部变量推导

这个关键字在javascript,以及众多弱类型语言中使用的很多了。

使用要求

  1. 必须能推导出实际类型(装在该变量中的值,需要能通过getClass()获取类或者是基本数据类型。如果是null值就无法得到类型)
  2. 只能应用于局部变量(实际上就是局部变量表中slot的重用)

JDK11

单文件程序

还记得刚学习Java的时候,老师教我们使用命令行运行Java文件,都是教我们先使用javac编译java文件,然后使用java xxx来运行。当时我们发现直接通过java xxx.java就可以运行了,为什么老师没提呢?之前都不求甚解,以为是老师忘记了。现在才知道。

在JDK11之前,确实是需要先编译再运行。

后面JDK11支持了单文件程序,也就是使用java xxx.java 命令的时候,会直接认为这个文件是个单文件程序,不依赖于其他文件,所以这样我们就可以直接编译这个文件然后直接运行即可。

所以如果这个文件中import了其他文件的类,那么是会报错的,因为java无法识别到那些类。

shebang脚本

实际上shebang是音译#!符号而来。

自来于Unix系统,#!两个符合组合在一起放在文件开头,被解释为用用后面路径的程序来解释运行这个文件。和魔数的作用差不多,不过魔数是隐式的,难以修改。而这个#!确实可以显式的添加修改编辑。

如果我们点击运行这个文件,那么就会直接去运行#!后面的程序,把文件作为参数交给程序运行。

image-20240928205009578

之前Java不支持这个#!就是因为当unix系统解释了文件,运行了#!后面指定的运行程序之间,java虚拟机并不能识别该文件中的#!,认为是非法。而现在他知道这个直接忽略这一行,后续当做java文件编译运行即可。

(所以#!这个功能只能在unix、linux运行,当然在windows中可以使用linux脚本程序来执行,典型的就是git,git会包含git-bash这样的脚本程序)

需要给要有运行的java程序给一个运行参数 –source 11 指定运行特性版本就可以不管文件的后缀名

另外需要先给文件加一个可执行权限 chmod +x

JDK14

文本块

记得python中的多行字符串,直接三引号‘’‘引起来就行了。而java却不行。必须使用换行符\n

jdk14吸取了这种语法,现在可以使用“”“ 三个双引号来包括多行字符串。这种可读性更高。

instanceof增强

之前的instanceof的原理实际上就是两个,如果对象为null直接返回false,然后进行强转如果不报ClassCastException就可以,否则就是false。

在使用instanceof的时候,往往当为true我们需要将原来的对象,手动强转成instanceof 判断的类型,例如:

1
2
3
4
5
Object a = "Hello World";
if( a instanceof String){
String b = (String) a;
...use b...
}

所以增强语法就是可以直接顺带声明一个局部变量

1
2
3
4
5
Object a = "Hello World";
if( a instanceof String b){
//String b = (String) a;
...use b...
}

如果instanceof判断为true就会自动创建并赋值给这个局部变量。

空指针提示

在这之前,空指针只有到运行时,发现null指针,才会爆出NullPointerException,并且只会显示错误行代码,而不会提示Null指针对象。

指出了错误代码的行数

而新特性会直接提示空指针变量。

JDK16

record类

record是数据的意思,也是记录的意思。这个类就是用来记录数据的,就像接口interface是用来记录行为的类。

在之前,我们需要的数据类,我们通常叫做vo,po,dto,do之类的,用于存储和传递数据

我们一般需要给这些数据类,加上getter,setter方法,toString equles toHash重写

record类闭合这个有点区别,record类初始化之后,数值不能修改。

语法

1
2
3
4
5
6
7
8
9
10
11
public record ClassName(参数列表){

}
//直接给个参数列表,当做唯一public构造函数,然后只能访问,不能修改
例如:
public record TestData(String name, String password){

}
使用:
TestData data = new TestData(“name”,“123456”);
String name = data.name();

JDK17新特性

sealed类 ,中文意思:密封的

用来解决父类无法管理子类的具体实现的问题,子类的实现很可能是错误的逻辑。

所以这里的解决方法就是父类知道继承他的子类有哪些,这些子类就是被父类认可的正确重写的子类。

sealed类,显式的管理继承。(如果一个类被声明为sealed,那么可以显式的知道这个类被那些类继承)

语法

  1. 如果声明了sealed,至少需要一个子类。
  2. 继承的子类必须是final,或者sealed,或者non-sealed之一(non-sealed就是打破sealed规则)
  3. 父类sealed类,使用permits关键字指明允许继承的子类。
1
2
3
4
5
6
7
8
9
public sealed class Parent permits ChildA,ChiledB{
...
}
public final class ChildA extends Parent{
...
}
public non-sealed class ChiledB extends Parent{
...
}

switch增强

实际上就基于switch case 是通过instanceof进行判断的,在jdk14中instanceof已经得到了增强,那么switch利用其也可以增强。

1
2
3
4
5
6
7
8
9
Object name = "name";
switch(name){
case String str -> System.out.println(str);
case Integer i ->{
System.out.println(i);
//break; 在jdk14后,可以使用-> lambda表达式,这种写法自动break在执行完lambda表达式之后。
}
default -> System.out.println("default");
}

将对象,case 类型,并自动赋值给局部变量。


JDK9~17新特性
https://wainyz.online/wainyz/2024/09/28/JDK9~17新特性/
作者
wainyz
发布于
2024年9月28日
许可协议