1. 类型推断
在Java 10中,提供了本地变量类型推断的功能,可以通过var声明变量:
var a = "123";
var b = 123;
System.out.println(a + b);
本地变量类型推断将引入“var”关键字,而不需要显式的规范变量的类型。
其实,所谓的本地变量类型推断,也是Java 10提供给开发者的语法糖。
虽然我们在代码中使用var进行了定义,但是对于虚拟机来说他是不认识这个var的,在java文件编译成class文件的过程中,会进行解糖,使用变量真正的类型来替代var。
2. Switch 增强
在JDK 12中引入了Switch表达式作为预览特性。并在Java 13中修改了这个特性,引入了yield语句,用于返回值。而在之后的Java 14中,这一功能正式作为标准功能提供出来。
- 引入了Switch表达式。
- 引入了yield语句,用于返回值。
- switch支持null。
- switch支持对enum和sealed Classes完整性校验,对于enum或sealed Classes已约定范围,编译器会进行完整性校验,如果已覆盖所有可能取值,则不再需要default分支。
- 支持连写case。
public class SwitchTest {
/**
* 支持lambda表达式
*
* @param a
*/
public static void test1(String a) {
switch (a) {
case "a" -> System.out.println("i guess it is a ~");
default -> System.out.println("default");
}
}
/**
* 支持yield返回值
*
* @param a
*/
public static void test2(String a) {
String result = switch (a) {
case "a" -> {
yield "i guess it is a ~";
}
// 这里也可以直接省略yield
default -> "default";
};
System.out.println("test2:" + result);
}
enum Type {
TYPE_A, TYPE_B, TYPE_C;
}
/**
* 使用枚举测试
* 如果已覆盖所有可能取值,则不再需要default分支
*
* @param type
* @return
*/
public static String test3(Type type) {
return switch (type) {
case TYPE_A -> "TYPE_A";
case TYPE_B -> "TYPE_B";
case TYPE_C -> "TYPE_C";
};
}
sealed interface ITest permits TestA, TestB {
}
static final class TestA implements ITest {
}
static final class TestB implements ITest {
}
/**
* 使用密封类测试
* 如果已覆盖所有可能取值,则不再需要default分支
*
* @param test
* @return
*/
public static String test4(ITest test) {
return switch (test) {
case TestA testA -> "TestA";
case TestB testB -> "TestB";
};
}
/**
* null测试
*
* @param s
* @return
*/
public static String test5(String s) {
return switch (s) {
case null -> "null";
case "a" -> "a";
default -> "default";
};
}
/**
* 支持连写case
*
* @param s
* @return
*/
public static String test6(String s) {
return switch (s) {
case "a", "b", "c" -> "abc";
case "d" -> "d";
default -> "default";
};
}
public static void main(String[] args) {
test1("a");
test1("b");
test2("a");
test2("b");
System.out.println("test3:" + test3(Type.TYPE_A));
System.out.println("test4:" + test4(new TestA()));
System.out.println("test5:" + test5(null));
System.out.println("test6:" + test6("a"));
}
}
3. Text Blocks
Java 13中提供了一个Text Blocks的预览特性,并且在Java 14中提供了第二个版本的预览。
text block,文本块,是一个多行字符串文字,它避免了对大多数转义序列的需要,以可预测的方式自动格式化字符串,并在需要时让开发人员控制格式。
以最后的"""
作为缩进的依据。
public static void main(String[] args) {
String str = """
asdasdqwdqwdqw
123123
asdasd
""";
System.out.println(str);
String str2 = """
asdasdqwdqwdqw
123123
asdasd
""";
System.out.println(str2);
}
4. Records
Java 14 中便包含了一个新特性:EP 359: Records,
Records的目标是扩展Java语言语法,Records为声明类提供了一种紧凑的语法,用于创建一种类中是“字段,只是字段,除了字段什么都没有”的类。
record
中的所有字段都是final的,只能在初始化的时候设置。
public class RecordTest {
record UserRecord(String name, Integer age) {
UserRecord {
}
}
public static void main(String[] args) {
UserRecord userRecord = new UserRecord("rabb", 18);
}
}
5. 封闭类
在JDK17中添加了密封类。密封的类和接口限制了哪些其他类或接口可以拓展或实现它们。密封类这个新的特性在JDK15和JDK16中作为预览功能。现在在JDK17中作为正式的功能,它与JDK16相比没有任何变化。
sealed
关键字用来表示这个类是一个密封类,然后permits
表示可以继承该类的子类
子类的必须是以下三种类型:
final
类型- 也是密封类类型(sealed)
- 非密封类类型(non-sealed)
除了通过关键字permits
来指定外,也可以直接将密封类允许的子类可以直接写到密封类的源文件中,当以这种方式声明时,密封类可以省略许可子句(permits),Java编译器会从源文件中的声明推断出允许的子类。
public class SealedTest {
/**
* 密封类
*/
abstract sealed class Subject permits SubjectA, SubjectB {
}
/**
* 子类非密封类
*/
non-sealed class SubjectA extends Subject {
}
/**
* 子类也是密封类
*/
sealed class SubjectB extends Subject permits SubjectC {
}
/**
* 子类为final类,不可被继承
*/
final class SubjectC extends SubjectB {
}
}
6. instanceof 模式匹配
模式匹配可以帮我们减少繁琐的条件状态提取。在进行条件状态提取时,我们问一个与某个对象有关的问题(比如“你是 Foo 吗”),如果答案是肯定的,我们就从对象中提取状态:“if (x instanceof Integer i) { … }”,其中 i 是绑定变量。
public class InstanceTest {
public static void main(String[] args) {
test(1);
test("1");
test(1L);
System.out.println(test2(1));
System.out.println(test2("1"));
System.out.println(test2(1L));
System.out.println(test2(1f));
}
public static void test(Object object) {
if (object instanceof String str) {
System.out.println("String:" + str);
} else if (object instanceof Integer integer) {
System.out.println("Integer:" + integer);
} else {
System.out.println("unknown");
}
}
public static String test2(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 -> "unknown";
};
}
}
7. 模块化开发
模块化在jdk9中加入,模块化的好处就是开发者可以根据需要引用某个依赖的指定部分,而不是引入这个依赖的全部。以此达到减少体积以及提高编效率的目的。
可以使用module-info.java
文件来导出或者引入一个模块。
module test {
exports xyz.lazyrabbit.jdk17.module;
requires java.net.http;
}
8. 接口的私有方法
在JDK17中,允许interface中携带private方法,这个private方法允许被自身default修饰的方法调用。
public class InterfaceTest {
interface ITest {
default void test() {
System.out.println(test2());
}
private String test2() {
return "test2";
}
}
}
9. JShell引擎
Java Shell 工具(简称:JShell)是一个用于学习Java编程语言和构建Java代码原型的交互式工具。JShell是一个Read-Evaluate-Print循环(REPL),它在语法、声明和表达式输入时即对它们进行计算,并立即显示其结果。该 JShell 工具通过命令行来运行。
如果你的设备中安装了JDK9即以上的版本,可以在终端中输入jshell
,进入JShell
,并编写脚本进行测试,同时按tab键可以调出候补提示。
10. 其他语法增强
Stream
新增takeWhile
方法类似与filter
,区别在于takeWhile
会在遇到不符合的条件时舍弃后边的所有元素,相对应的还有dropWhile
方法Stream
新增ofNullable
方法List
、Map
新增of
方法,可以快速构造集合- 通过
Files
类快速读写 String
增加判空方法isBlack
方法和isEmpty
- …
List<Integer> integers = List.of(1, 2, 3, 4, 5, 6, 7, 1);
System.out.printf("" + integers.stream().takeWhile(integer -> integer < 4).count());
System.out.printf("" + Stream.ofNullable(null).count());
String s = "123abd";
System.out.println(s.isBlank());
System.out.println(s.isEmpty());
Files.writeString(
Path.of("./", "tmp.txt"), // 路径
"hello, jdk11 files api", // 内容
StandardCharsets.UTF_8); // 编码
String txt = Files.readString(
Paths.get("./tmp.txt"), // 路径
StandardCharsets.UTF_8); // 编码
System.out.println(txt);
11. 直接打包成可执行程序
支持将Java程序打包为对应平台的可执行程序
- linux: deb和rpm
- mac: pkg和dmg
- windows: msi和exe
假如我们在lib目录下有一个jar包组成的应用,并且main.jar包含main方法,则可以使用下面的语句产生对应平台的可执行程序
jpackage --name myapp --input lib --main-jar main.jar
如果main.jar的MANIFEST.MF没有指定main函数,则需要在命令行中指定
jpackage --name myapp --input lib --main-jar main.jar --main-class myapp.Main
12. GC优化
JDK9
设置G1为JVM默认垃圾收集器JDK10
并行Full GC,来优化G1的延迟JDK11
新增ZGC垃圾收集器JDK12
新增Shenandoah GC垃圾回收算法JDK12
G1收集器的优化,将GC的垃圾分为强制部分和可选部分,强制部分会被回收,可选部分可能不会被回收,提高GC的效率JDK13
ZGC优化,释放内存还给操作系统JDK16
ZGC性能优化