JDK17初体验

从刚工作时使用的JDK8到现在的JDK17,Java的版本一直在飞速迭代,每个版本都会引入一些新特性和优化改进,比如模块化系统、var类型推断、switch表达式增强、record类、instanceof增强、Sealed类/接口、新的GC等,下面就让我们来体验一下这些新特性吧。

==对于某些不太好测试的特性,这里就忽略了,如模块化系统、ZGC等==

var类型推断

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public static void main(String[] args) {
    var greeting = "Hello, JDK17";
    var num1 = 10;
    long num2 = 1000L;
    var sum = num1 + num2;
    var result = sum % 2 != 0;

    System.out.println("greeting: " + greeting);
    System.out.println("" + num1 + " + " + num2 + " = " + sum);
    System.out.println("result: " + result);
    }
  • 输出

    1
    2
    3
    greeting: HELLO, JDK17
    10 + 1000 = 1010
    result: false
  • class文件

    可以看到,var只是一种语法糖,编译时会自动转成对应的类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static void main(String[] args) {
    String greeting = "Hello, JDK17";
    int num1 = 10;
    long num2 = 1000L;
    long sum = (long)num1 + num2;
    boolean result = sum % 2L != 0L;
    System.out.println("greeting: " + (String)greeting.transform(String::toUpperCase));
    System.out.println("" + num1 + " + " + num2 + " = " + sum);
    System.out.println("result: " + result);
    }

Http请求客户端

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static void main(String[] args) throws IOException, InterruptedException {
    HttpClient httpClient = HttpClient.newHttpClient();
    HttpRequest httpRequest = HttpRequest
    .newBuilder()
    .uri(URI.create("http://localhost:9090/user/get/202000"))
    .build();
    HttpResponse<String> httpResponse = httpClient
    .send(httpRequest, HttpResponse.BodyHandlers.ofString());
    System.out.println("response: " + httpResponse.body());
    }
  • 输出

    1
    response: {"data":{"id":1001,"userNo":"10010","nickname":"codecho","mobilePhone":"18755667788","createTime":"2023-03-08 12:04:20","updateTime":"2023-03-08 12:04:20"},"success":true}

switch表达式增强

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public static void main(String[] args) {
    int month = 4;
    System.out.println("month: " + month + ", season: " + getSeason(4));
    }

    public static String getSeason(int month) {
    String season = switch (month) {
    case 3, 4, 5 -> "Spring";
    case 6, 7, 8 -> "Summer";
    case 9, 10, 11 -> "Autumn";
    case 12, 1, 2 -> {
    System.out.println("month: " + month);
    yield "Winter";
    }
    default -> "illegal month!";
    };

    return season;
    }
  • 输出

    1
    month: 4, season: Spring
  • class文件

    可以看到,switch增强也是语法糖,和普通的switch没什么区别

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    public static void main(String[] args) {
    int month = 4;
    System.out.println("month: " + month + ", season: " + getSeason(4));
    }

    public static String getSeason(int month) {
    String var10000;
    switch (month) {
    case 1:
    case 2:
    case 12:
    System.out.println("month: " + month);
    var10000 = "Winter";
    break;
    case 3:
    case 4:
    case 5:
    var10000 = "Spring";
    break;
    case 6:
    case 7:
    case 8:
    var10000 = "Summer";
    break;
    case 9:
    case 10:
    case 11:
    var10000 = "Autumn";
    break;
    default:
    var10000 = "illegal month!";
    }

    String season = var10000;
    return season;
    }

文本块

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public static void main(String[] args) {

    var text = """
    {
    "name": "codecho",
    "age": 28,
    "gender": "male"
    }
    """;
    System.out.println("text block: ");
    System.out.println(text);
    }
  • 输出

    1
    2
    3
    4
    5
    6
    text block: 
    {
    "name": "codecho",
    "age": 28,
    "gender": "male"
    }
  • class文件

    实际还是使用的转换符

    1
    2
    3
    4
    5
    public static void main(String[] args) {
    String text = "{\n \"name\": \"codecho\",\n \"age\": 28,\n \"gender\": \"male\"\n}\n";
    System.out.println("text block: ");
    System.out.println(text);
    }

record类

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    public record Boy(String name, int age) {

    }

    public static void main(String[] args) {
    Boy boy = new Boy("Gary", 12);
    System.out.println("the boy's name is " + boy.name() + ", he is " + boy.age() + " years old");
    }
  • 输出

    1
    the boy's name is Gary, he is 12 years old
  • 反编译class文件

    实际继承了Record类(==注意:当前类是final的,不可继承==),编译器自动添加了各个属性方法,和equals、hashCode、toString方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public abstract class Record {

    protected Record() {}

    @Override
    public abstract boolean equals(Object obj);

    @Override
    public abstract int hashCode();

    @Override
    public abstract String toString();
    }

instanceof增强

  • 增强前

    1
    2
    3
    4
    5
    6
    7
    public static void main(String[] args) {
    Object o = "instanceof";
    if (o instanceof String) {
    String str = (String) o;
    System.out.println("str: " + str);
    }
    }
  • 增强后

    1
    2
    3
    4
    5
    6
    public static void main(String[] args) {
    Object o = "instanceof";
    if (o instanceof String str) {
    System.out.println("str: " + str);
    }
    }

sealed密封类/接口

  • 代码

    • permit:指定可以继承的类/接口
    • sealed`:密封类/接口
    • no-sealed:非密封类/接口
    • final:不可被继承类/接口
    • 子类继承被sealed标记的超类后,同样要求指定密封性,使用sealedno-sealedfinal其中之一指定
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // MotoVehicle只能由Bus、Car继承
    public sealed class MotoVehicle permits Bus, Car {

    }

    // Bus不能再被继承
    public final class Bus extends MotoVehicle {

    }

    // Car非密封,可以被继承
    public non-sealed class Car extends MotoVehicle {

    }

    // Suv继承Car
    public class Suv extends Car {

    }
  • 作用

    使用密封类/接口可以更好地限制类/接口的继承范围,提高代码的安全性和可维护性。