其他
从Java 6到Java 21的重要变动
https://juejin.cn/post/7379431208429584393
改进的 JIT 编译器:增强了 Java 程序的性能。 脚本语言支持:集成了对脚本语言的支持,特别是 JavaScript(通过 Rhino 引擎)。 Java 编译 API:提供了一组 API 用于编译 Java 源文件。 对 Web 服务的增强:包括对 JAX-WS 2.0, JAXB 2.0 的支持。 改进的 Swing:引入了桌面外观(SystemTray API)、桌面集成(Desktop API)和对 Windows Vista 的更好支持。 Pluggable Annotation Processing API:提供了一个新的 API 用于注解处理。 增强的监控和管理:增加了对 JMX 和 JVM 的增强监控和管理能力。 垃圾收集改进:包括并发标记扫描垃圾收集器(CMS)的改进。
语言增强(Project Coin):
Switch 支持字符串:switch 语句可以使用字符串。 多捕获块:可以在一个 catch 块中捕获多个异常。 Try-with-resources 语句:自动管理资源关闭。 钻石操作符:推断泛型类型以简化代码。 二进制字面量:使用前缀 0b 或 0B 表示二进制字面量。 下划线分隔符:数字字面量中可以使用下划线分隔符以提高可读性,例如 1_000_000。
Lambda 表达式:支持函数式编程。 函数式接口:使用 @FunctionalInterface 注解。 Stream API:处理集合的序列化操作。 默认方法:接口可以包含默认实现的方法。 静态方法:接口可以包含静态方法。 Optional 类:避免空指针异常的容器类。 新的日期和时间 API:包括 LocalDate,LocalTime,LocalDateTime,ZonedDateTime 等。 Nashorn JavaScript 引擎:更快的 JavaScript 引擎替代 Rhino。 重复注解:支持在同一位置重复使用注解。
模块系统:提供更好的封装性和依赖管理。 JShell:交互式 Java REPL 工具。 改进的 Javadoc:包括搜索功能和 HTML5 支持。 多版本 JAR:支持在一个 JAR 文件中包含多个版本的类文件。 增强的 Stream API:添加了 takeWhile,dropWhile,iterate 方法。 工厂方法:用于创建不可变集合的快捷方法,如 List.of(),Set.of(),Map.of()。
局部变量类型推断:使用 var 关键字。 应用数据类共享(AppCDS):改进的类加载性能。 并行 Full GC for G1:G1 垃圾收集器的 Full GC 并行化。 Root Certificates:默认包含根证书,简化 SSL 连接。
只能在局部变量声明中使用,如方法内的局部变量、增强的 for 循环变量、try-with-resources 语句中的变量。 语法示例:
for (var item : list) {
System.out.println(item);
}
只能在初始化时推断类型,必须在声明时赋值。 不能用于类成员变量、方法参数或返回类型。
无法改变变量的类型,推断类型是编译时确定的,不能使用 var 关键字来声明未初始化的变量。 var 不能用于 lambda 表达式和方法引用的参数。
主要目的是简化代码的编写,减少样板代码,提高代码的可读性,同时保持 Java 的静态类型系统。
val 表示不可变变量,var 表示可变变量。Kotlin 可以在更多场景中使用类型推断,包括类成员变量、方法参数和返回类型。 语法示例:
for (item in list) {
println(item)
}
可以在很多地方使用类型推断,包括局部变量、类属性、函数返回类型等。 不要求在声明时初始化,可以在函数参数、返回类型和类属性中使用类型推断。
Kotlin 的类型推断更为广泛和灵活,可以根据上下文推断类型。 支持更复杂的类型推断,例如 lambda 表达式和返回类型推断。
提供更简洁的语法,提高开发效率,减少样板代码,同时保持 Kotlin 的静态类型系统。
Java 10:类型推断只能用于局部变量声明,且必须在声明时初始化。它不能用于类成员变量、方法参数和返回类型。 Kotlin:类型推断的应用范围更广,几乎可以在任何地方使用类型推断,包括类成员变量、方法参数和返回类型。
Java 10:使用 var 关键字来表示局部变量的类型推断。 Kotlin:使用 val 和 var 来分别表示不可变和可变变量,并在更多场景中使用类型推断。
两者皆有:Java 和 Kotlin 都保持了静态类型系统,通过类型推断来简化代码,同时保持类型安全。
Java 10:局部变量类型推断主要是为了减少样板代码,限制较多,使用范围较窄。 Kotlin:更加灵活和广泛的类型推断,允许在更多上下文中使用,并且支持更复杂的类型推断逻辑。
Java 10 示例
public static void main(String[] args) {
var list = new ArrayList<String>();
list.add("Java");
for (var item : list) {
System.out.println(item);
}
}
}
val list = ArrayList<String>()
list.add("Kotlin")
for (item in list) {
println(item)
}
}
Java 10 的局部变量类型推断和 Kotlin 的类型推断都旨在简化代码编写,提高开发效率,但 Kotlin 的类型推断更为广泛和灵活。Java 的局部变量类型推断则更为保守和有限,主要聚焦于局部变量声明,确保不改变 Java 语言的静态类型特性和向后兼容性。
新的字符串方法:isBlank,lines,strip,stripLeading,stripTrailing,repeat。 运行 Java 文件:使用 java 命令直接运行 .java 文件。 局部变量语法的 lambda 参数:lambda 参数支持 var。 HttpClient:新的 HttpClient API 用于 HTTP/2 和 WebSocket 支持。 ZGC(Z Garbage Collector):低延迟垃圾收集器。
System.out.println(str.isBlank()); // 输出 true
str.lines().forEach(System.out::println);
// 输出:
// Hello
// World
// Java
System.out.println(str.strip()); // 输出 "Hello World"
System.out.println(str.stripLeading()); // 输出 "Hello World"
System.out.println(str.stripTrailing()); // 输出 "Hello World"
System.out.println(str.repeat(3)); // 输出 "Java Java Java "
增强的 switch 语句(预览): switch 语句可以返回值,并简化语法。 JVM 常量 API:新的 API 用于描述常量池中的常量。 G1 垃圾收集器改进:改进的暂停时间。
public static void main(String[] args) {
int day = 3;
String dayString = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
default -> throw new IllegalArgumentException("Invalid day of the week: " + day);
};
System.out.println("Today is " + dayString);
}
}
使用 -> 替代了 case 关键字后的冒号。 语句块中的最后一个表达式会作为整个 switch 语句的结果返回。 可以使用 yield 关键字来显式返回值,但这是可选的,如果没有 yield,则会隐式地返回语句块的最后一个表达式的值。
文本块(预览):多行字符串文字。 动态 CDS 档案:改进的类数据共享。 ZGC 改进:支持解除未使用的内存。
Switch 表达式:switch 语句的新语法已正式发布。 记录类型(预览):简化数据载体类的定义。 模式匹配(预览):instanceof 操作符的模式匹配。
public static void main(String[] args) {
Object obj = "Hello, world!";
if (obj instanceof String str) {
System.out.println("obj 是一个字符串: " + str);
// 在这里可以直接使用 str 变量,它已经被声明为 String 类型
int length = str.length();
System.out.println("字符串长度为:" + length);
} else {
System.out.println("obj 不是一个字符串");
}
}
}
重点是判断类型后不用强转,之前我们使用时是需要强转的。
文本块:多行字符串文字成为正式功能。 隐藏类:用于框架的动态类生成。 ZGC 改进:ZGC 的多项性能改进。 Sealed 类(预览): 控制哪个类可以继承某个类。
// Shape 类的定义
}
public final class Circle extends Shape {
// Circle 类的定义
}
public final class Rectangle extends Shape {
// Rectangle 类的定义
}
public final class Triangle extends Shape {
// Triangle 类的定义
}
通过使用 Sealed 类,可以更加精确地控制继承关系,防止不合理的类继承和扩展,从而提高代码的安全性和可维护性。需要注意的是,Sealed 类是一个预览功能,可能会在未来的版本中发生变化,因此在实际项目中使用时需要谨慎考虑,并且可能需要等到它成为稳定特性后才能广泛应用。
记录类型:记录类型成为正式功能。 强封闭 JDK:更严格的封装 JDK 内部 API。 模式匹配(instanceof):instanceof 模式匹配成为正式功能。
Sealed 类:控制哪个类可以继承某个类成为正式功能。 增强的 switch 语句:switch 表达式成为正式功能。 新 JEP 集合:包括改进的伪随机数生成器、增强的 Foreign Function & Memory API、上下文自适应 G1 和 ZGC 等。
UTF-8 默认字符集:默认字符集改为 UTF-8。 简单的 Web 服务器:方便测试和开发的小型 Web 服务器。 代码段的 Javadoc:在 Javadoc 中嵌入代码段。
虚拟线程(预览):更轻量级的线程实现,改进并发性能。 结构化并发(预览):简化并发任务管理。 外部函数和内存 API(预览):更好的本地代码调用支持。 模式匹配:增强的模式匹配功能。
记录模式(预览):用于解构记录的模式匹配。 模式匹配 for switch(第三个预览):继续改进和完善 switch 语句的模式匹配。 外部函数和内存 API(第二个预览):继续改进和完善。
public class Main {
public static void main(String[] args) {
Point point = new Point(10, 20);
if (point instanceof Point p) {
System.out.println("x = " + p.x() + ", y = " + p.y());
}
}
}
记录模式使得在 Java 中更方便地处理记录类型的数据,可以通过模式匹配的方式轻松地解构记录,并访问其中的字段。
虚拟线程:作为正式功能发布,更轻量级的线程实现。 结构化并发:作为正式功能发布,简化并发任务管理。 记录模式:作为正式功能发布,用于解构记录的模式匹配。 模式匹配 for switch:作为正式功能发布,增强 switch 语句的模式匹配。 外部函数和内存 API:作为正式功能发布,更好的本地代码调用支持。 字符串插值:通过直接在字符串中插入变量和表达式,简化字符串操作。
虚拟线程是 Java 21 中的一项正式功能,它是一种更轻量级的线程实现,旨在提高并发性能和资源利用率。虚拟线程是通过 Executors.newVirtualThreadExecutor() 方法创建的,可以与传统的线程一起使用,但是更轻量级。
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
for (int i = 0; i < 10; i++) {
executor.submit(() -> {
System.out.println("Hello from virtual thread: " + Thread.currentThread());
});
}
executor.shutdown();
}
}
结构化并发是 Java 21 中的一项正式功能,它旨在简化并发任务的管理。通过结构化并发,可以更轻松地管理并发任务的执行和结果处理,提高代码的可读性和可维护性。
public class Main {
public static void main(String[] args) {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("Running in parallel");
});
future.thenRun(() -> {
System.out.println("After completion");
}).join();
}
}
记录模式是 Java 21 中的一项正式功能,它用于解构记录的模式匹配。记录模式使得在模式匹配中可以更方便地访问记录中的字段,并根据记录的结构进行匹配和解构。
public class Main {
public static void main(String[] args) {
Point point = new Point(10, 20);
if (point instanceof Point p) {
System.out.println("x = " + p.x() + ", y = " + p.y());
}
}
}
模式匹配 for switch 是 Java 21 中的一项正式功能,它增强了 switch 语句的模式匹配能力,使得在 switch 语句中可以更方便地进行模式匹配操作。
public static void main(String[] args) {
Object obj = "Hello";
switch (obj) {
case String s -> System.out.println("String: " + s);
case Integer i -> System.out.println("Integer: " + i);
default -> System.out.println("Unknown type");
}
}
}
外部函数和内存 API 是 Java 21 中的一项正式功能,它提供了更好的本地代码调用支持,使得在 Java 中更容易地调用本地代码并处理本地内存。
import static jdk.incubator.foreign.CLinker.*;
public class Main {
public static void main(String[] args) throws Exception {
MemorySegment segment = CLinker.toCString("Hello, world!");
try (var scope = ResourceScope.newConfinedScope()) {
var printfFn = CLinker.getInstance().lookup("printf",
FunctionDescriptor.ofVoid(CLinker.C_POINTER),
FunctionDescriptor.ofVoid(CLinker.C_POINTER)
);
printfFn.invokeExact(scope, "%s%n", segment);
}
}
}
字符串插值是 Java 21 中的一项正式功能,它通过直接在字符串中插入变量和表达式,简化了字符串操作,提高了代码的可读性和可维护性。
public static void main(String[] args) {
String name = "Alice";
int age = 30;
String message = String.format("Hello, my name is %s and I am %d years old.", name, age);
System.out.println(message);
}
}