文章目录
写在前面
从jdk8升级到jdk17,会遇到哪些问题?
1、JDK17的安装与java环境变量
首先从官网上下载一个JDK17的包,windows系统可能有这两种包(压缩包和安装包)
https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html
这里我们以压缩包为例,下载完直接解压,放到一个非中文路径下(复制这个路径)
接下有两种使用JDK17的方式:
1.1、第一种:把jdk1.8更换为jdk17
接下来找到系统环境变量,把JAVA_HOME变成JDK17的路径
1.2、第二种jdk1.8与jdk17并存
如果你只是想尝尝鲜,那么不建议你把环境变量改为jdk17。你只需解压jdk17后,在对应的编码工具里面添加jdk17,例如这里,我在idea中添加JDK17
2、SpringBoot 3.0尝鲜
SpringBoot 3.0最低使用jdk17、maven3.5
2.1、pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0-M4</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>springboot3-mavenDemo</description>
<properties>
<!--Jdk版本要求17以上-->
<java.version>17</java.version>
</properties>
<dependencies>
<!--引入spring-boot-starter-web,支持web开发-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!--spring boot maven插件,支持maven的全流程命令以及程序运行-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<!--由于目前3.0还是处于里程碑版本,等到正式release版本,此配置不需要-->
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
2.2、启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
有这两个文件你就可以尝试启动了
2.3、idea中可能需要你配置的内容
1、设置中的ava编译器
2、项目结构中的设置
3、新特性
本文提到的新特性主要侧重于代码结构与API上
3.1、java 9 新增
1、module-info.java:该文件必须位于项目的根目录中。该文件用于定义模块需要什么依赖,以及那些包被外部使用。
2、jshell:jshell工具提供了一个交互式命令界面,可以评估声明,语句和表达式,无需编译即可返回执行结果。
3、接口的私有方法
public interface MyInterface {
void normalInterfaceMethod();
default void defaultMethod1(){
privateMethod();
}
default void defaultMethod2(){
privateMethod();
}
//接口的私有方法可以在JDK9中使用
private void privateMethod(){
System.out.println("这是一个接口的私有方法");
}
}
4、资源自动关闭
InputStreamReader reader = new InputStreamReader(System.in);
OutputStreamWriter writer = new OutputStreamWriter(System.out);
//多资源用分号隔开
try (reader;writer) {
//......
} catch (IOException e) {
e.printStackTrace();
}
// reader和writer会自动关闭
5、可以在匿名实现类中重写方法等操作
Set<String> set = new HashSet<>(){
//匿名实现类重写add方法。
@Override
public boolean add(String s) {
System.out.println("执行add方法");
return super.add(s);
}
};
set.add("1");
6、String 存储结构变更
JDK9将String底层存储数据改为byte数组,StringBuffer和StringBuilder也同样做了变更,将以往char数组改为byte数组。
7、使用of方法直接快速创建只读集合
List<String> list = List.of("A", "B", "C");
List<String> copy = List.copyOf(list);
System.out.println(list == copy); // true
List<String> list1 = new ArrayList<String>();
List<String> copy1 = List.copyOf(list1);
System.out.println(list1 == copy1); // false,非of方法创建的copyOf->false
8、增强 Stream API,Stream接口中新增4个方法:dropWhile、takeWhile、ofNullable,为iterate方法新增重载方法。
List<Integer> list = Arrays.asList(45,43,76,87,42,77,90,73,67,88);
list.stream().takeWhile((x) -> x < 80 ).forEach(System.out::println);
// 返回结果
// 45
// 43
// 76
9、改进 Optional 类,主要是新增了三个方法:stream,ifPresentOrElse 和 or 。
List<String> list = List.of("A", "B", "C", "D", "E", "F");
Optional<List<String>> optional = Optional.of(list);
optional.stream().forEach(System.out::println);
10、多分辨率图像 API,在 java.awt.image 包下新增了支持多分辨率图片的API,用于支持多分辨率的图片。
11、支持HTTP2,全新的 HTTP 客户端 API 可以从 jdk.incubator.httpclient 模块中获取。因为在默认情况下,这个模块是不能根据 classpath 获取的,需要使用 add modules 命令选项配置这个模块,将这个模块添加到 classpath中。
12、其他
3.2、java 10 新增
1、可以使用var作为局部变量类型推断标识符,仅适用于局部变量
var str = "ABC"; //根据推断为 字符串类型
var l = 10L;//根据10L 推断long 类型
var flag = true;//根据 true推断 boolean 类型
var flag1 = 1;//这里会推断boolean类型。0表示false 非0表示true
var list = new ArrayList<String>(); // 推断 ArrayList<String>
var stream = list.stream(); // 推断 Stream<String>
//错误的用法
var error;//×
2、其他:将JDK多存储库合并为单存储库、垃圾回收接口、并行Full GC 的G1、应用数据共享、线程局部管控等。
3.3、java 11 新增
1、在Lambda表达式中,可以使用var关键字来标识变量,变量类型由编译器自行推断。
Arrays.asList("Java", "Python", "Ruby")
.forEach((var s) -> {
System.out.println("Hello, " + s);
});
2、字符串加强
// 判断字符串是否为空白
" ".isBlank(); // true
// 去除首尾空格
" Javastack ".strip(); // "Javastack"
// 去除尾部空格
" Javastack ".stripTrailing(); // " Javastack"
// 去除首部空格
" Javastack ".stripLeading(); // "Javastack "
// 复制字符串
"Java".repeat(3);// "JavaJavaJava"
// 行数统计
"A\nB\nC".lines().count(); // 3
3、InputStream 加强,transferTo,可以用来将数据直接传输到 OutputStream
var classLoader = ClassLoader.getSystemClassLoader();
var inputStream = classLoader.getResourceAsStream("javastack.txt");
var javastack = File.createTempFile("javastack2", "txt");
try (var outputStream = new FileOutputStream(javastack)) {
inputStream.transferTo(outputStream);
}
4、HTTP Client API
var request = HttpRequest.newBuilder()
.uri(URI.create("https://javastack.cn"))
.GET()
.build();
var client = HttpClient.newHttpClient();
// 同步
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
// 异步
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
5、对Files类增加了writeString和readString两个静态方法
Files.writeString(
Path.of("./", "tmp.txt"), // 路径
"hello, jdk11 files api", // 内容
StandardCharsets.UTF_8); // 编码
String s = Files.readString(
Paths.get("./tmp.txt"), // 路径
StandardCharsets.UTF_8); // 编码
6、一个文件中可以包含多个public类
7、Shebang文件,Shebang文件是Unix系统中常见的文件,以#!/path/to/executable作为文件的开头第一行,可以作为脚本小程序直接运行一段代码。
#!/g/jdk-11/bin/java --source 11
public class SimpleInterest{
public static void main(String[] args){
if ( args == null || args.length < 3 ){
System.err.println("Three arguments required: principal, rate, period");
System.exit(1);
}
int principal = Integer.parseInt(args[0]);
int rate = Integer.parseInt(args[1]);
int period = Integer.parseInt(args[2]);
double interest = Maths.simpleInterest(principal, rate, period);
System.out.print("Simple Interest is: " + interest);
}
}
public class Maths{
public static double simpleInterest(int principal, int rate, int period){
if ( rate > 100 ){
System.err.println("Rate of interest should be <= 100. But given values is " + rate);
System.exit(1);
}
return ( principal * rate * period * 1.0 ) / 100;
}
}
3.4、java 12 新增
1、Switch扩展了
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
2、String类中新增transform()和indent()
3、Files类中新增mismatch()
4、支持unicode11和压缩数字格式化
var cnf = NumberFormat.getCompactNumberInstance(Locale.CHINA, NumberFormat.Style.SHORT);
System.out.println(cnf.format(1_0000));
System.out.println(cnf.format(1_9200));
System.out.println(cnf.format(1_000_000));
System.out.println(cnf.format(1L<<30));
System.out.println(cnf.format(1L<<40));
System.out.println(cnf.format(1L<<50));
//1万
//2万
//100万
//11亿
//1兆
//1126兆
5、其他:JVM Constants API、默认CDS存档、可中断的G1 Mixed GC等
3.5、java 13 新增
1、NioSocketImpl替换了PlainSocketImpl
public class HelloApp {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8888)) {
boolean running = true;
System.out.println("listened 8888");
while (running) {
Socket clientSocket = serverSocket.accept();
//do something with clientSocket
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2、新的关键字yield用于返回switch语句的内容
// 没有逻辑的返回
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
// 逻辑较多的处理
String result = switch (number) {
case 1, 2:
// 逻辑代码
yield "one or two";
case 3:
// 逻辑代码
yield "three";
case 4, 5, 6:
yield "four or five or six";
default:
yield "unknown";
};
return result;
3、添加了“”“ 长文本内容 ”“”
开头"““之后必须另起一行,另外结尾的””"是否另起一行有不同的效果
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
3.6、java 14 新增
1、类型匹配instanceof增强
Object obj = "kuaidi100";
if(obj instanceof String str){
//直接使用str
}
2、数据载体的类型 record
record默认为final的,成员变量也为final,所以没有set方法。在JDK15中对它进行了继续加强。
public record Kuaidi100Record(@Name("name") int x, int y) {
public static String one;
}
3、其他:移除CMS垃圾收集器、ZGC支持windows,macOS等
3.7、java 15 新增
1、新加入 Edwards-Curve 数字签名算法(EdDSA)实现加密签名。
// example: generate a key pair and sign
KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
KeyPair kp = kpg.generateKeyPair();
// algorithm is pure Ed25519
Signature sig = Signature.getInstance("Ed25519");
sig.initSign(kp.getPrivate());
sig.update(msg);
byte[] s = sig.sign();
// example: use KeyFactory to contruct a public key
KeyFactory kf = KeyFactory.getInstance("EdDSA");
boolean xOdd = ...
BigInteger y = ...
NamedParameterSpec paramSpec = new NamedParameterSpec("Ed25519");
EdECPublicKeySpec pubSpec = new EdECPublicKeySpec(paramSpec, new EdPoint(xOdd, y));
PublicKey pubKey = kf.generatePublic(pubSpec);
2、封闭类sealed,有了这个特性,意味着以后不是你想继承就继承,想实现就实现了,你得经过允许才行。
public abstract sealed class Student
permits ZhangSan, LiSi, ZhaoLiu {
...
}
3、隐藏类
// 一个普通类
public class JEP371HiddenClasses {
public static String hello() {
return "https://www.didispace.com";
}
}
// 隐藏类
String filePath = "JEP371HiddenClasses.class";
byte[] b = Files.readAllBytes(Paths.get(filePath));
log.info(Base64.getEncoder().encodeToString(b));
// 最终打印(这就是个隐藏类)
yv66vgAAAD0AFAoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCAAIAQAZaHR0cHM6Ly93d3cuZGlkaXNwYWNlLmNvbQcACgEALmNvbS9kaWRpc3BhY2UvZGVidWcvamF2YTE1L0pFUDM3MUhpZGRlbkNsYXNzZXMBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAMExjb20vZGlkaXNwYWNlL2RlYnVnL2phdmExNS9KRVAzNzFIaWRkZW5DbGFzc2VzOwEABWhlbGxvAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAYSkVQMzcxSGlkZGVuQ2xhc3Nlcy5qYXZhACEACQACAAAAAAACAAEABQAGAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAAAwANAAAADAABAAAABQAOAA8AAAAJABAAEQABAAsAAAAbAAEAAAAAAAMSB7AAAAABAAwAAAAGAAEAAAAGAAEAEgAAAAIAEw==
// 使用隐藏类
void testHiddenClasses() throws Throwable {
// 1. 加载encode之后的隐藏类
String CLASS_INFO = "yv66vgAAAD0AFAoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCAAIAQAZaHR0cHM6Ly93d3cuZGlkaXNwYWNlLmNvbQcACgEALmNvbS9kaWRpc3BhY2UvZGVidWcvamF2YTE1L0pFUDM3MUhpZGRlbkNsYXNzZXMBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAMExjb20vZGlkaXNwYWNlL2RlYnVnL2phdmExNS9KRVAzNzFIaWRkZW5DbGFzc2VzOwEABWhlbGxvAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAYSkVQMzcxSGlkZGVuQ2xhc3Nlcy5qYXZhACEACQACAAAAAAACAAEABQAGAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAAAwANAAAADAABAAAABQAOAA8AAAAJABAAEQABAAsAAAAbAAEAAAAAAAMSB7AAAAABAAwAAAAGAAEAAAAGAAEAEgAAAAIAEw==";
byte[] classInBytes = getDecoder().decode(CLASS_INFO);
Class<?> proxy = MethodHandles.lookup()
.defineHiddenClass(classInBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE)
.lookupClass();
// 输出类名
log.info(proxy.getName());
// 输出类有哪些函数
for(Method method : proxy.getDeclaredMethods()) {
log.info(method.getName());
}
// 2. 调用hello函数
MethodHandle mh = MethodHandles.lookup().findStatic(proxy, "hello", MethodType.methodType(String.class));
String result = (String) mh.invokeExact();
log.info(result);
}
4、其他
3.8、java 16 新增
1、主要是java10到15中的预览功能转正。
2、其他:可弹性伸缩的元数据区、 新的打包工具jpackage、针对Value-Based类的编译器warning提示、提供向量计算的API、提供操作外部内存的能力等
3.9、java 17 新增
1、正式引入密封类sealed class,限制抽象类的实现;
2、统一日志异步刷新,先将日志写入缓存,然后再异步刷新;
3、其他:特定于上下文的反序列化过滤器、弃用 Applet API 以进行删除、增强型伪随机数生成器、恢复始终严格的浮点语义