写在前面

从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 以进行删除、增强型伪随机数生成器、恢复始终严格的浮点语义

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐