JDK17新特性,代码使用,作用详细讲解

时间:2024-10-23 08:42:52

目录

1.密封类和密封接口

        作用

        好处

        1. 密封类

        2. 密封接口

        3. 非密封类

        4.  抽象密封类 

2.模式匹配for instanceof

    JDK17前的jdk版本

    新JDK17 

   特性与优点

   使用示例

   注意事项

   作用

3.文本块

 作用

 好处

 代码实例

1. 基本语法:

2.换行和缩进:

3.包含引号:

4.换行符的自动处理:

5.使用表达式:

4.外部内存访问 API(Foreign Function & Memory API)

    作用

    好处

    示例:

         1. 分配和使用堆外内存

2. 外部函数调用(调用本地 C 函数)

5.新的 macOS 渲染器

    作用:

    好处:

6. 对 macOS/AArch64 的支持

    作用:

    好处:

7.防止特定的 JNI 方法链接

    作用

    好处:

8. 其他重要更新


 

1.密封类和密封接口

        作用

                密封类和密封接口允许开发者限制哪些类可以扩展或实现特定的类或接口,从而控制类型层次结构的完整性。

        好处

                提高代码的安全性和可维护性。

                使类型的意图更加明确,便于理解和使用。

        1. 密封类

                 密封类使用 sealed 关键字进行声明,并且使用 permits 列出允许的子类。

// 声明一个密封类 Shape,允许 Circle 和 Rectangle 作为子类
public sealed class Shape permits Circle, Rectangle {
    // 类体
}

// Circle 类继承自 Shape
public final class Circle extends Shape {
    @Override
    public String toString() {
        return "Circle";
    }
}

// Rectangle 类继承自 Shape
public final class Rectangle extends Shape {
    @Override
    public String toString() {
        return "Rectangle";
    }
}

        2. 密封接口

                  密封接口的实现方式与密封类类似,使用 sealed 关键字和 permits 列出允许的实现类。

                   

// 声明一个密封接口 Drawable,允许 Circle 和 Square 实现
public sealed interface Drawable permits Circle, Square {
    void draw();
}

// Circle 类实现 Drawable 接口
public final class Circle implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing a Circle");
    }
}

// Square 类实现 Drawable 接口
public final class Square implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing a Square");
    }
}

        3. 非密封类

                  如果希望某个密封类的子类不受密封限制,可以使用 non-sealed 关键字。

// 声明一个密封类 Shape,允许 Circle 和其他非密封类
public sealed class Shape permits Circle, NonSealedShape {
    // 类体
}

// Circle 类继承自 Shape
public final class Circle extends Shape {
    @Override
    public String toString() {
        return "Circle";
    }
}

// 允许其他类继承的非密封类
public non-sealed class NonSealedShape extends Shape {
    @Override
    public String toString() {
        return "NonSealedShape";
    }
}

// 允许其他类继承的类
public class Triangle extends NonSealedShape {
    @Override
    public String toString() {
        return "Triangle";
    }
}

        4.  抽象密封类 

                 密封类也可以是抽象的,这样可以定义一些抽象方法,让子类实现这些方法。

                    

public sealed abstract class Shape permits Circle, Rectangle {
    public abstract double area();
}

public final class Circle extends Shape {
    private final double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

public final class Rectangle extends Shape {
    private final double width;
    private final double height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public double area() {
        return width * height;
    }
}

                

2.模式匹配for instanceof

    JDK17前的jdk版本

         在以前的 Java 版本中,使用 instanceof 检查一个对象的类型时,通常需要使用两步,

 使用 instanceof 检查对象的类型。强制类型转换为目标类型

       

if (obj instanceof String) {
    String str = (String) obj;  // 需要进行强制类型转换
    System.out.println(str.length());
}

    新JDK17 

      在 JDK 17 中,你可以直接在 instanceof 中进行模式匹配,这样就不需要显式地进行类型转换了。语法上,instanceof 现在可以在同一行中进行类型检查和声明:

    

if (obj instanceof String str) {  // 直接声明并转换
    System.out.println(str.length()); // 可以直接使用 str,无需强制转换
}

   特性与优点

        简化代码:减少了代码的冗余,使代码更加简洁易读。

        类型安全:消除了强制类型转换可能导致的 ClassCastException。

        可读性:让意图更加明确,代码的逻辑更加清晰。

   使用示例

        下面是一个具体的例子,展示如何使用模式匹配来处理不同类型的对象。

         

public class PatternMatchingExample {
    public static void printLength(Object obj) {
        if (obj instanceof String str) {  // 使用模式匹配
            System.out.println("String length: " + str.length());
        } else if (obj instanceof List<?> list) {
            System.out.println("List size: " + list.size());
        } else {
            System.out.println("Unknown type");
        }
    }

    public static void main(String[] args) {
        printLength("Hello, World!");  // 输出: String length: 13
        printLength(Arrays.asList(1, 2, 3));  // 输出: List size: 3
        printLength(42);  // 输出: Unknown type
    }
}

   注意事项

       Scope:在 if 语句块内,模式匹配引入的变量(如上例中的 str 和 list)是有效的,并且在这个作用域内可以直接使用。

      多重条件:你可以在 instanceof 语句中结合其他条件,保持简洁的代码风格。

   作用

         模式匹配 for instanceof 使得 Java 代码更加简洁、安全和易于理解。

3.文本块

 作用

    提供了一种更加简洁的方式来定义多行字符串,尤其适用于 JSON、XML 等格式的字符串。

 好处

    增强了字符串的可读性。

    减少了转义字符的使用,简化了字符串的书写。

 代码实例

         1. 基本语法

             文本块使用三个双引号(""")来定义,支持多行字符串,自动处理换行和缩进。

              

String textBlock = """
    This is a text block.
    It can span multiple lines.
    """;

         2.换行和缩进

              文本块会保留换行符,并且会自动去掉前导空白(也称为“缩进”),使得排版更加整洁。

               

String html = """
    <html>
        <body>
            <h1>Hello, World!</h1>
        </body>
    </html>
    """;

         3.包含引号:

             可以使用 """ 定义的文本块包含双引号,而无需转义。

             

String json = """
    {
        "name": "ChatGPT",
        "version": "1.0"
    }
    """;

         4.换行符的自动处理

            文本块中的每一行都自动添加换行符,避免了使用 \n 的麻烦。

             

String poem = """
    The woods are lovely, dark and deep,
    But I have promises to keep,
    And miles to go before I sleep.
    """;

         5.使用表达式

             文本块可以与其他字符串连接使用,甚至可以包含插值表达式(需与字符串连接运算符一起使用)。

          

String name = "ChatGPT";
String greeting = """
    Hello, %s!
    Welcome to the world of Java Text Blocks.
    """.formatted(name);

4.外部内存访问 API(Foreign Function & Memory API)

    作用

         允许 Java 程序直接访问本地代码和外部内存。

    好处

          提高了与本地库交互的效率。

          提供了更好的安全性和可控性,避免了直接使用指针带来的问题。

    示例:

             1. 分配和使用堆外内存

                        Java 17 引入了 MemorySegment 类,用来表示一块堆外内存。你可以通过它分配、访问和释放内存。

               

import jdk.incubator.foreign.*;

public class ForeignMemoryExample {
    public static void main(String[] args) {
        // 分配 100 字节的堆外内存
        try (MemorySegment segment = MemorySegment.allocateNative(100)) {
            // 获取内存地址
            MemoryAddress address = segment.baseAddress();

            // 在内存中写入数据
            segment.set(JAVA_INT, 0, 42);

            // 从内存中读取数据
            int value = segment.get(JAVA_INT, 0);
            System.out.println("Value read from foreign memory: " + value);
        }
    }
}

                        在这个示例中,我们使用 MemorySegment.allocateNative 方法分配了 100 字节的堆外内存,并使用 segment.setsegment.get 来进行内存的写入和读取。

             2. 外部函数调用(调用本地 C 函数)

                     使用外部内存 API,你可以通过 CLinker 来加载和调用本地代码中的 C 函数。

                    

import jdk.incubator.foreign.*;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class ForeignFunctionExample {
    public static void main(String[] args) throws Throwable {
        // 获取 C 库中的 printf 函数
        SymbolLookup lookup = CLinker.systemLookup();
        MethodHandle printf = lookup.lookup("printf")
            .orElseThrow(() -> new RuntimeException("printf not found"));

        // 调用 printf 函数
        printf.invokeExact("Hello, %s!\n", "World");
    }
}

                在这个例子中,我们通过 CLinker.systemLookup() 获取系统中可用的本地函数符号,并通过 lookup.lookup() 查找本地函数(这里是 printf)。然后,我们使用 MethodHandle 调用该函数。

5.新的 macOS 渲染器

    作用:

           改进了 AWT 渲染器,增强了在 macOS 上的图形和文本显示。

    好处:

         提高了 macOS 上的用户体验。

         更好的兼容性和性能。

6. 对 macOS/AArch64 的支持

    作用:

      增加了对 Apple Silicon(ARM 架构)的支持。

    好处:

        提高了在 Apple M1 等新设备上的性能。

        拓宽了 Java 应用的部署环境。

7.防止特定的 JNI 方法链接

    作用

            增强了对 Java Native Interface 的安全控制,防止不安全的 JNI 方法链接。

    好处:

           提高了 Java 应用程序的安全性。

            降低了潜在的安全风险。

8. 其他重要更新

        JEP 391:对 java.lang.invoke.MethodHandles 的增强。

        JEP 384:引入新的 API 用于简化多种 Java 功能的实现。

        JEP 390:允许使用 switch 表达式来进行更灵活的条件匹配。