赞
踩
Java 17 是一个长期支持(LTS)版本,于2021年9月14日发布,带来了14个新功能,其中包括文本块、switch表达式、record关键字、sealed classes密封类等语法特性,以及增强的伪随机数生成器、使用新的 macOS 渲染库等性能改进。
最近看到一篇文章,说java 17的用户采用率在一年内增长了430%,但我目前用的都是Java8,所以就顺便了解了Java8过度到Java17需要了解哪些新特性。粗略筛查后主要有以下几个:
模式匹配是一种测试对象是否具有特定结构的方法,如果匹配成功,还可以从对象中提取数据。在Java中,我们可以使用instanceof操作符和switch语句来进行模式匹配。例如:
// 使用instanceof操作符进行模式匹配
if (obj instanceof String s) {
// 如果obj是String类型,就把它赋值给s变量
System.out.println(s.length());
}
// 使用switch语句进行模式匹配
switch (obj) {
case Integer i -> System.out.println(i + 1); // 如果obj是Integer类型,就把它赋值给i变量
case String s -> System.out.println(s.length()); // 如果obj是String类型,就把它赋值给s变量
default -> System.out.println("Unknown type"); // 其他情况
}
模式匹配可以让代码更简洁、更易读、更安全,因为我们不需要强制类型转换或空指针检查。模式匹配还可以与密封类和记录结合使用,以实现更强大的功能。
文本块是一种多行字符串字面量,它可以用三个双引号来定义,而不需要拼接或转义。文本块可以保持字符串的格式,方便编写HTML、JSON、SQL等内容。例如:
// 使用文本块定义一个HTML字符串 String html = """ <html> <body> <p>Hello, world</p> </body> </html> """; // 使用文本块定义一个JSON字符串 String json = """ { "name": "Alice", "age": 25 } """; // 使用文本块定义一个SQL字符串 String sql = """ SELECT * FROM users WHERE name = 'Bob' """;
文本块的结果类型仍然是java.lang.String,只是提供了一种更方便的书写方式。文本块中的缩进和换行符会被编译器处理,以得到合适的输出。文本块中还可以使用转义序列和格式化方法,以实现更灵活的控制。
记录是一种特殊的类,它可以作为不可变数据的透明载体,比普通类更简洁。记录可以看作是具有名字的元组。记录可以自动生成构造器、访问器、equals、hashCode、toString等方法,减少样板代码。记录的特点有以下几个:
记录是一种特殊的类,它只包含不可变的数据。
记录可以自动生成构造器、访问器、equals、hashCode、toString等方法,减少样板代码。
记录的声明方式如下:
record Point(int x, int y) {} // 定义一个记录类Point,包含两个整型字段x和y
记录类的使用方式如下:
Point p1 = new Point(1, 2); // 创建一个Point对象p1
Point p2 = new Point(1, 2); // 创建另一个Point对象p2
System.out.println(p1.x()); // 访问p1的x字段,输出1
System.out.println(p1.equals(p2)); // 比较p1和p2是否相等,输出true
System.out.println(p1.toString()); // 输出p1的字符串表示,输出Point[x=1, y=2]
记录类可以继承接口,也可以重写默认的方法,还可以添加静态成员和嵌套类。
记录类主要用于表示简单的数据载体,例如领域对象或数据传输对象。
记录类还支持以下特性:
紧凑构造器:紧凑构造器是一种没有参数列表和返回类型的构造器,它可以用于对记录组件进行验证或转换,或者执行其他逻辑。例如:
record Point(int x, int y) {
Point {
if (x < 0 || y < 0) {
throw new IllegalArgumentException("Negative coordinates not allowed");
}
}
}
派生记录:派生记录是一种使用with关键字从已有的记录对象创建一个新的记录对象,并修改部分组件值的方法。例如:
record Point(int x, int y) {}
Point p1 = new Point(1, 2); // 创建一个Point对象p1
Point p2 = p1.withX(3); // 创建一个派生记录p2,它的x值为3,y值与p1相同
System.out.println(p2); // 输出Point[x=3, y=2]
密封类是一种限制某个类或接口的子类或实现类的数量和类型的方法。密封类可以提高可维护性和安全性,以及支持模式匹配。密封类的声明方式如下:
// 使用sealed关键字声明一个密封类Shape,它只能被Circle和Rectangle继承 public sealed class Shape permits Circle, Rectangle {} // 使用final关键字声明一个最终类Circle,它继承自Shape public final class Circle extends Shape { private final double radius; public Circle(double radius) { this.radius = radius; } public double getRadius() { return radius; } } // 使用non-sealed关键字声明一个非密封类Rectangle,它继承自Shape,但可以被其他类继承 public non-sealed class Rectangle extends Shape { private final double length; private final double width; public Rectangle(double length, double width) { this.length = length; this.width = width; } public double getLength() { return length; } public double getWidth() { return width; } }
密封类的使用方式如下:
// 创建一个Shape对象s,它是一个Circle对象
Shape s = new Circle(1.0);
// 使用switch语句进行模式匹配,根据s的实际类型执行不同的操作
switch (s) {
case Circle c -> System.out.println("Circle with radius " + c.getRadius());
case Rectangle r -> System.out.println("Rectangle with length " + r.getLength() + " and width " + r.getWidth());
}
密封类可以继承接口,也可以实现接口,还可以嵌套在其他类或接口中。密封类主要用于表示有限的、固定的、已知的类型层次结构,例如代数数据类型或状态机。
局部变量类型推断是一种让编译器根据初始化表达式推断变量类型的方法,这样我们就不需要显式地写出变量类型。局部变量类型推断可以使用var关键字来实现,它可以用在局部变量声明中,例如:
// 使用var关键字声明一个局部变量name,它的类型由编译器推断为String
var name = "Alice";
// 使用var关键字声明一个局部变量list,它的类型由编译器推断为List<String>
var list = List.of("a", "b", "c");
局部变量类型推断可以减少重复的类型信息,提高可读性。它还可以在lambda表达式的参数中使用var关键字,以便添加注解或显式指定泛型类型,例如:
// 使用var关键字声明一个lambda表达式的参数s,并添加@NonNull注解
Function<String, Integer> f = (@NonNull var s) -> s.length();
// 使用var关键字声明一个lambda表达式的参数t,并显式指定泛型类型为List<String>
Consumer<List<String>> c = (var t) -> System.out.println(t.size());
局部变量类型推断只能用于局部变量,不能用于成员变量、方法参数、返回类型等。它也不能用于没有初始化表达式的变量,或者初始化表达式为null的变量。它也不会改变Java的静态类型系统,只是提供了一种更简洁的书写方式。
这些特性分别引入了Epsilon、ZGC和Shenandoah垃圾收集器,它们都是实验性的,目的是为了提高应用程序的性能和吞吐量。Epsilon是一个无操作的垃圾收集器,它只分配内存,不回收内存。ZGC和Shenandoah是两个低延迟的垃圾收集器,它们都使用并发标记-整理算法,可以处理大内存(TB级别)的情况。
-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
源: 与必应的对话, 2023/5/9
(1) Java 10 Local Variable Type Inference - Oracle. https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference.
(2) Java 10 LocalVariable Type-Inference | Baeldung. https://www.baeldung.com/java-10-local-variable-type-inference.
(3) Local Variable Type Inference or LVTI in Java 10 - GeeksForGeeks. https://www.geeksforgeeks.org/local-variable-type-inference-or-lvti-in-java-10/.
(4) Java 10 - Local Variable Type Inference - TutorialsPoint. https://www.tutorialspoint.com/java10/java10_local_variable_type_inference.htm.
(5) Java 10 Local variables Type Inference tutorials with examples. https://www.cloudhadoop.com/java10-local-variables-type-inference/.
-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC
从Java 8换成Java 17,并不能简单的升级,还需要考虑到下面这些容性问题:
总之,从Java 8换成Java 17,并不是一个简单的过程,需要仔细分析和测试你的项目,以及使用的第三方依赖。后面实践后再来分享,如果有好的文章推荐也请在评论区留言,谢谢。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。