特性
JEP 403: Strongly Encapsulate JDK Internals,增强jdk内部元素的保护
大多数开发用不到。升级jdk时,可能因为之前代码用了某些类,导致无法升级。
JEP 394: Pattern Matching for instanceof,instanceof模式匹配(16)
jdk16提供了instanceof-and-cast语法
// Old code
if (o instanceof String) {
String s = (String)o;
... use s ...
}// New code
if (o instanceof String s) {
... use s ...
}
JEP 395: Records(16)
JEP 395: Records
简化模型定义
record Point(int x, int y) { }
对应简化前代码
class Point {
private final int x;
private final int y; Point(int x, int y) {
this.x = x;
this.y = y;
} int x() { return x; }
int y() { return y; } public boolean equals(Object o) {
if (!(o instanceof Point)) return false;
Point other = (Point) o;
return other.x == x && other.y == y;
} public int hashCode() {
return Objects.hash(x, y);
} public String toString() {
return String.format("Point[x=%d, y=%d]", x, y);
}
}
JEP 409: Sealed Classes(17)
密封的类或接口,在父类定义中限制了具体实现类,也就是除了这里列出的实现类外,其他类无法继承或实现该抽象类或接口。
JEP 409: Sealed Classes
JEP 361: Switch Expressions(14)
JEP 361: Switch Expressions
使用->代替:,且不需要写break。
使用switch表达式之前:
int numLetters;
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
break;
case TUESDAY:
numLetters = 7;
break;
case THURSDAY:
case SATURDAY:
numLetters = 8;
break;
case WEDNESDAY:
numLetters = 9;
break;
default:
throw new IllegalStateException("Wat: " + day);
}
使用switch表达式:
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
JEP 378: Text Blocks(15)
文本块,例如"""长文本""",省略了拼接代码。
String html = "<html>\n" +" <body>\n" +" <p>Hello, world</p>\n" +" </body>\n" +"</html>\n";
String html = """<html><body><p>Hello, world</p></body></html>""";
JEP 358: Helpful NullPointerExceptions(14)
NPE异常描述中输出具体哪个对象是null
JEP 406: Pattern Matching for switch,switch模式匹配
JEP 406: Pattern Matching for switch (Preview)
不知道入参具体类型,需要进行分辨并输出类型。
利用jdk16的特性:
static String formatter(Object o) {
String formatted = "unknown";
if (o instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (o instanceof Long l) {
formatted = String.format("long %d", l);
} else if (o instanceof Double d) {
formatted = String.format("double %f", d);
} else if (o instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
利用jdk17的switch模式匹配特性:
static String formatterPatternSwitch(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 -> o.toString();
};
}
升级java17遇到的一些问题
由通过反射访问受限的JDK内部类或字段导致
Unable to make field private final byte[] java.lang.String.value accessible: module java.base does not "opens java.lang" to unnamed module @7c3fdb62
原因:在Java 17中,模块系统(JPMS)变得更加严格,某些内部API和反射访问被限制。这导致了 InaccessibleObjectException 异常,因为你的代码或依赖库试图通过反射访问受限的JDK内部类或字段。
解决方案
1.避免使用反射访问受限的JDK内部类或字段:
a.尽量避免直接通过反射访问JDK内部实现。查找替代方案,使用标准Java API来实现相同的功能。
2.更新依赖库:
a.检查并更新所有第三方库,以确保它们兼容Java 17。许多流行的库已经发布了兼容Java 17的新版本。
3.使用--add-opens选项(临时解决方案):
a.如果你无法立即修改代码,可以暂时通过添加JVM参数来开放特定模块和包的访问权限,但这只是临时解决方案,不推荐长期使用。
使用--add-opens选项
你可以在运行应用程序时添加以下JVM参数:(亲测有效,有几个包出异常,就加几个)
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED --add-opens java.base/java.util.concurrent=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED
java 17 编译失败 java: 程序包 sun.reflect.generics.reflectiveObjects 不可见
(程序包 sun.reflect.generics.reflectiveObjects 已在模块 java.base 中声明, 但该模块未将它导出到未命名模块)
原因:
在Java 17中,模块系统(JPMS)变得更加严格,某些内部API(如sun.reflect.generics.reflectiveObjects)已经被限制访问。这导致了“程序包不可见”的错误,因为你的代码或依赖库试图通过反射访问受限的JDK内部类或字段。
解决方案
1.避免使用内部API:
a.尽量避免使用sun.*包下的类和接口,因为它们是JDK的内部实现,不保证向后兼容性。
b.查找替代方案,使用标准Java API来实现相同的功能。
2.更新依赖库:
a.如果你正在使用第三方库,并且这些库依赖于内部API,请检查是否有更新版本。许多流行的库已经发布了兼容Java 17的新版本。
3.迁移到标准API:
a.如果你自己编写了代码并且依赖于这些内部API,请考虑迁移到标准Java API。例如,如果需要反射功能,可以使用java.lang.reflect包中的类。
4.临时解决方案:使用--add-exports选项:
a.如果你无法立即修改代码,可以暂时通过添加JVM参数来开放特定模块和包的访问权限,但这只是临时解决方案,不推荐长期使用。
使用--add-exports选项
你可以在运行应用程序时添加以下JVM参数:
--add-exports java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED
为了编译能通过,需要如下配置
xml
<build>
<plugins>
<!-- For compiling -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<fork>true</fork>
<compilerArgs>
<arg>--add-exports</arg>
<arg>java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED</arg>
</compilerArgs>
</configuration>
</plugin> </plugins>
</build>
由javaSE不再包含javaEE的API导致
java17 java: 程序包javax.jws不存在 java: 程序包javax.xml.ws不存在
原因:
在Java 17中,javax.jws包已经被移除。这个包属于Java EE(现为Jakarta EE)的一部分,而Java SE从Java 11开始就不再包含这些API。因此,如果你的项目依赖于这些API,你需要采取一些措施来解决这个问题。
解决方案
1.添加相关依赖:
a.如果你需要使用javax.jws包,可以通过添加相应的Maven或Gradle依赖来引入这些API。
2.迁移到Jakarta EE:
a.Java EE已经迁移到Jakarta EE,你可以考虑将代码迁移到对应的Jakarta API
<dependency><groupId>javax.jws</groupId><artifactId>javax.jws-api</artifactId><version>1.1</version></dependency><dependency><groupId>javax.jws</groupId><artifactId>javax.jws-api</artifactId><version>1.1</version></dependency>