前言:最近写项目用到了Spring3.0,JDK8不行了,一看原来JDK现已更新到了22了,下面是我总结的一些新特性 详细能够参阅:openjdk.org/projects/jd…

一 JDK8 新特性

1.1 Lambda 表达式

Lambda表达式是Java 8引进的一个重要特性,它答应以更简练的办法编写匿名函数,Lambda表达式能够看作是一种轻量级的函数式编程的语法表明 Lambda表达式的根本语法如下:

(parameter1, parameter2, ..., parameterN) -> {
  // 办法体
}

Lambda表达式包含以下几个部分:

  • 参数列表:包含在圆括号内,能够是零个或多个参数。
  • 箭头操作符:由箭头符号 “->” 表明,用于分隔参数列表和办法体。
  • 办法体:包含在花括号内,完结详细的操作逻辑。

Lambda表达式的首要用途是简化代码,特别是在运用函数式接口时十分便利。函数式接口是只包含一个笼统办法的接口,Lambda表达式能够与函数式接口@FunctionalInterface一同运用,然后完结函数式编程的作用。

JDK8-JDK17新特性总结

package lambda;
​
/**
 * @description: 运用 lambda 表达式创立线程
 * @author: shu
 * @createDate: 2023/6/30 9:49
 * @version: 1.0
 */
public class Thread01 {
  public static void main(String[] args) {
    // 1.1 运用匿名内部类
    new Thread(new Runnable() {
      @Override
      public void run() {
        System.out.println("Hello World! 1.1");
       }
     }).start();
​
    // 1.2 运用 lambda 表达式
    new Thread(() -> System.out.println("Hello World! 1.2 ")).start();
​
    // 1.3 运用 lambda 表达式和类型推导
    new Thread(() -> {
      System.out.println("Hello World! 1.3");
     }).start();
   }
}
​

Lambda表达式能够更简练地表明匿名函数,避免了传统的匿名内部类的冗余代码,进步了代码的可读性和可维护性。它是Java 8引进的一个强壮特性,广泛运用于函数式编程和Java 8以后的各种API中。

1.2 新的日期API

JDK 8引进了一个新的日期和时刻API,名为java.time,它供给了愈加灵敏和易于运用的日期和时刻处理功用。该API在规划上遵从了不行变性和线程安全性的原则,而且供给了许多便利的办法来处理日期、时刻、时刻距离和时区等。 下面是java.time包中一些首要的类和接口:

  1. LocalDate:表明日期,例如:年、月、日。
  2. LocalTime:表明时刻,例如:时、分、秒。
  3. LocalDateTime:表明日期和时刻,结合了LocalDateLocalTime
  4. ZonedDateTime:表明带时区的日期和时刻。
  5. Instant:表明时刻戳,准确到纳秒等级。
  6. Duration:表明时刻距离,例如:小时、分钟、秒。
  7. Period:表明日期距离,例如:年、月、日。
  8. DateTimeFormatter:用于日期和时刻的格局化和解析。
  9. ZoneId:表明时区。
  10. ZoneOffset:表明时区偏移量。

这些类供给了一系列办法来履行日期和时刻的核算、格局化、解析和比较等操作。而且,java.time包还供给了对日历体系的支撑,包含对ISO-8601日历体系的全面支撑。 以下是一个简略的示例,展现了怎么运用新的日期API创立和操作日期和时刻:

package lambda;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
/**
 * @description: 新的日期和时刻 API 示例
 * @author: shu
 * @createDate: 2023/6/30 10:15
 * @version: 1.0
 */
public class DateDemo01 {
    public static void main(String[] args) {
        // 创立日期
        LocalDate date = LocalDate.now();
        System.out.println("Today's date: " + date);
        // 创立时刻
        LocalTime time = LocalTime.now();
        System.out.println("Current time: " + time);
        // 创立日期和时刻
        LocalDateTime dateTime = LocalDateTime.now();
        System.out.println("Current date and time: " + dateTime);
        // 格局化日期和时刻
        String formattedDateTime = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println("Formatted date and time: " + formattedDateTime);
        // 履行日期的核算操作
        LocalDate tomorrow = date.plusDays(1);
        System.out.println("Tomorrow's date: " + tomorrow);
        // 履行时刻的比较操作
        boolean isBefore = time.isBefore(LocalTime.NOON);
        System.out.println("Is current time before noon? " + isBefore);
    }
}

1.3 运用Optional

JDK 8引进了一个新的类,名为Optional,用于处理在处理或许为null的值时出现的NullPointerException(空指针反常)问题。Optional类的规划方针是鼓舞更好的编程实践,明晰表明一个值或许为空,并鼓舞开发人员在运用这些或许为空的值时进行显式的处理。 Optional类是一个容器方针,能够包含一个非空的值或许没有值。它供给了一系列办法来处理包含值和没有值的状况,例如:获取值、判别是否有值、获取默许值、履行操作等。 下面是Optional类的一些常用办法:

  1. of():创立一个包含非空值的Optional方针。
  2. empty():创立一个空的Optional方针。
  3. ofNullable():依据指定的值创立一个Optional方针,答应值为null。
  4. isPresent():判别Optional方针是否包含值。
  5. get():获取Optional方针中的值,假如没有值,则抛出NoSuchElementException反常。
  6. orElse():获取Optional方针中的值,假如没有值,则回来默许值。
  7. orElseGet():获取Optional方针中的值,假如没有值,则经过供给的Supplier函数生成一个默许值。
  8. orElseThrow():获取Optional方针中的值,假如没有值,则经过供给的Supplier函数抛出指定的反常。
  9. map():对Optional方针中的值进行转化,并回来一个新的Optional方针。
  10. flatMap():对Optional方针中的值进行转化,并回来一个新的Optional方针,该办法答应转化函数回来一个Optional方针。

以下是一个简略的示例,展现了怎么运用Optional类来处理或许为空的值:

import java.util.Optional;
/**
 * @description: Optional 示例
 * @author: shu
 * @createDate: 2023/6/30 10:20
 * @version: 1.0
 */
public class OptionalDemo {
    public static void main(String[] args) {
        String value = "Hello";
        // 创立一个包含非空值的Optional方针
        Optional<String> optional = Optional.of(value);
        // 判别Optional方针是否包含值
        if (optional.isPresent()) {
            // 获取Optional方针中的值
            String result = optional.get();
            System.out.println("Value: " + result);
        }
        // 获取Optional方针中的值,假如没有值,则回来默许值
        String defaultValue = optional.orElse("Default Value");
        System.out.println("Default Value: " + defaultValue);
        // 对Optional方针中的值进行转化
        Optional<String> transformed = optional.map(String::toUpperCase);
        if (transformed.isPresent()) {
            System.out.println("Transformed Value: " + transformed.get());
        }
    }
}

在上面的示例中,咱们创立了一个包含非空值的Optional方针,并运用isPresent()get()办法来判别和获取值。然后,咱们运用orElse()办法来获取值或回来默许值,以及运用map()办法对值进行转化。 Optional类能够在代码中供给愈加安全和明晰的处理空值的办法。但是,它并不适用于一切的场景,需求依据实际状况来判别是否运用Optional。请留意,过度运用Optional或许会导致代码冗余,因而需求权衡运用的利弊。

1.4 运用Base64

在JDK 8中,Java供给了对Base64编码和解码的支撑,经过java.util.Base64类来完结。Base64是一种用于将二进制数据编码为文本的编码办法,常用于在网络传输中或存储数据时将二进制数据表明为可打印字符 下面是一些根本的运用示例:

  1. 编码为Base64字符串:
import java.util.Base64;
/**
 * @description: 编码示例
 * @author: shu
 * @createDate: 2023/7/1 9:23
 * @version: 1.0
 */
public class EncodedDemo {
    public static void main(String[] args) {
        // 原始数据
        String originalData = "Hello, World!";
        // 编码为Base64字符串
        String encodedData = Base64.getEncoder().encodeToString(originalData.getBytes());
        System.out.println("Encoded data: " + encodedData);
    }
}
  1. 解码Base64字符串:
import java.util.Base64;
/**
 * @description: 解码示例
 * @author: shu
 * @createDate: 2023/7/1 9:24
 * @version: 1.0
 */
public class DecodeDemo {
    public static void main(String[] args) {
        // Base64字符串
        String encodedData = "SGVsbG8sIFdvcmxkIQ==";
        // 解码为原始数据
        byte[] decodedData = Base64.getDecoder().decode(encodedData);
        System.out.println("Decoded data: " + new String(decodedData));
    }
}

在上述示例中,咱们运用Base64.getEncoder()办法获取一个Base64.Encoder方针,并调用其encodeToString()办法将原始数据编码为Base64字符串。相同,咱们运用Base64.getDecoder()办法获取一个Base64.Decoder方针,并调用其decode()办法解码Base64字符串为原始数据。 java.util.Base64类还供给了其他一些办法,例如:

  • Base64.getEncoder().encodeToString(byte[] src):将字节数组编码为Base64字符串。
  • Base64.getDecoder().decode(String src):将Base64字符串解码为字节数组。
  • Base64.getMimeEncoder().encodeToString(byte[] src):将字节数组编码为MIME类型的Base64字符串。
  • Base64.getMimeDecoder().decode(String src):将MIME类型的Base64字符串解码为字节数组。
  • Base64.getUrlEncoder().encodeToString(byte[] src):将字节数组编码为URL安全的Base64字符串。
  • Base64.getUrlDecoder().decode(String src):将URL安全的Base64字符串解码为字节数组。

这些办法能够依据不同的需求挑选运用。 需求留意的是,Base64编码是不加密的,仅用于编码和解码数据,假如需求加密和解密数据,请运用加密算法,如AES、RSA等。

1.5 接口的默许办法和静态办法

JDK 8引进了接口的默许办法和静态办法,这使得在接口中增加新功用变得愈加灵敏。

  1. 默许办法(Default Methods): 默许办法答应在接口中界说具有默许完结的办法。这使得在不损坏现有完结类的状况下,能够向现有接口增加新的办法。

以下是默许办法的示例:

public interface MyInterface {
    // 笼统办法
    void abstractMethod();
    // 默许办法
    default void defaultMethod() {
        System.out.println("This is a default method.");
    }
}
public class MyClass implements MyInterface {
    @Override
    public void abstractMethod() {
        System.out.println("Implementing abstractMethod() in MyClass.");
    }
}
/**
 * @description:
 * @author: shu
 * @createDate: 2023/7/1 9:29
 * @version: 1.0
 */
public class DefaultMethodsDemo {
    public static void main(String[] args) {
        MyClass obj = new MyClass();
        obj.abstractMethod();
        obj.defaultMethod();
    }
}

在上述示例中,MyInterface接口中界说了一个笼统办法abstractMethod()和一个默许办法defaultMethod()MyClass类完结了MyInterface接口,并供给了对笼统办法的详细完结。此外,MyClass类能够承继默许办法defaultMethod()的默许完结。

  1. 静态办法(Static Methods): 静态办法是接口中的另一种类型的办法,它与特定的接口关联,而且只能经过接口称号来调用。

以下是静态办法的示例:

public interface MyInterface {
    // 笼统办法
    void abstractMethod();
    // 静态办法
    static void staticMethod() {
        System.out.println("This is a static method.");
    }
}
public class MyClass implements MyInterface {
    @Override
    public void abstractMethod() {
        System.out.println("Implementing abstractMethod() in MyClass.");
    }
}
public class Main {
    public static void main(String[] args) {
        MyClass obj = new MyClass();
        obj.abstractMethod();
        MyInterface.staticMethod();
    }
}

在上述示例中,MyInterface接口中界说了一个笼统办法abstractMethod()和一个静态办法staticMethod()MyClass类完结了MyInterface接口,并供给了对笼统办法的详细完结。staticMethod()能够经过接口称号直接调用。 经过默许办法和静态办法,接口的功用能够愈加灵敏地扩展,而无需损坏已有的完结类。这在JDK 8之前是不或许的。

1.6 办法引证格局

在JDK 8中,引进了办法引证(Method Reference)的概念,用于简化函数式接口(Functional Interface)的完结。办法引证答应您直接引证现有办法作为Lambda表达式的代替,使代码愈加简练和易读。在JDK 8中,有四种不同的办法引证格局:

  1. 静态办法引证(Static Method Reference):格局为类名::静态办法名。例如,Integer::parseInt表明引证Integer类的静态办法parseInt。
  2. 实例办法引证(Instance Method Reference):格局为方针::实例办法名。例如,System.out::println表明引证System.out方针的println办法。
  3. 方针办法引证(Object Method Reference):格局为类名::实例办法名。这种引证适用于无参实例办法。例如,String::length表明引证String类的length办法。
  4. 结构办法引证(Constructor Method Reference):格局为类名::new。例如,ArrayList::new表明引证ArrayList类的结构办法。

在运用办法引证时,要依据接口的笼统办法的参数个数和回来类型挑选恰当的办法引证格局。 以下是一个简略的示例,展现了这些办法引证格局的运用:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
 * @description: 办法引证示例
 * @author: shu
 * @createDate: 2023/7/1 9:32
 * @version: 1.0
 */
public class MethodReferenceDemo {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        // 静态办法引证
        names.forEach(System.out::println);
        // 实例办法引证
        names.forEach(String::toUpperCase);
        // 方针办法引证
        names.forEach(String::length);
        // 结构办法引证
        List<Integer> lengths = names.stream()
                .map(Integer::new)
                .collect(Collectors.toList());
    }
}

1.7 Stream类

JDK中的Stream类是Java 8引进的一个新概念,用于处理调集和数组等数据源的元素序列。Stream类供给了一种流式操作的办法,能够用于对数据进行过滤、映射、排序、聚合等各种操作,然后愈加便利和高效地处理数据。 下面是一些Stream类的首要特色和用法:

  1. 流的创立:能够经过调集、数组、I/O通道等多种办法创立流。例如,经过Collection.stream()办法能够从调集创立一个流,经过Arrays.stream()办法能够从数组创立一个流。
  2. 中心操作:Stream类供给了一系列中心操作办法,用于对流进行转化、过滤、映射等操作,这些操作会回来一个新的Stream方针。常见的中心操作办法包含filter()map()sorted()等。
  3. 终端操作:Stream类也供给了一系列终端操作办法,用于对流进行最终的处理,回来一个成果或发生一个副作用。常见的终端操作办法包含forEach()collect()reduce()等。
  4. 慵懒求值:Stream类的中心操作是慵懒求值的,即在调用终端操作之前,中心操作并不会当即履行。这种办法能够优化功用,只对需求处理的元素进行操作。
  5. 并行处理:Stream类能够支撑并行处理,即在处理大量数据时,能够将操作并行化以进步处理速度。经过parallel()办法能够将流通化为并行流。

下面是一个简略的示例,展现了Stream类的运用:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
 * @description:
 * @author: shu
 * @createDate: 2023/7/1 9:36
 * @version: 1.0
 */
public class StreamDemo {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Dave", "Eve");
        // 过滤长度大于3的元素
        names.stream()
                .filter(name -> name.length() > 3)
                .forEach(System.out::println);
        // 转化为大写并排序
        List<String> uppercaseNames = names.stream()
                .map(String::toUpperCase)
                .sorted()
                .collect(Collectors.toList());
        // 求长度之和
        int totalLength = names.stream()
                .mapToInt(String::length)
                .sum();
    }
}

详细参阅我前面写的文章

1.8 注解相关的改动

在JDK 8中,注解相关的改动首要会集在两个方面:重复注解(Repeatable Annotations)和可运用的类型(Type Annotations)。

  1. 重复注解(Repeatable Annotations):在JDK 8之前,每个注解在一个元素上只能运用一次。而在JDK 8中,引进了重复注解的概念,答应在同一个元素上屡次运用相同的注解。为了支撑重复注解,新增了两个元注解(Meta-Annotations):@Repeatable和@Retention。 @Repeatable注解用于注解声明,指定了注解的容器注解,该容器注解答应在同一个元素上屡次运用相同的注解。 @Retention注解用于指定注解的生命周期,它能够运用于注解声明和容器注解。常用的生命周期包含@Retention(RetentionPolicy.SOURCE)、@Retention(RetentionPolicy.CLASS)和@Retention(RetentionPolicy.RUNTIME)。 经过运用重复注解,能够更灵敏地在同一个元素上运用多个相同的注解,而不需求创立额定的容器注解。
  2. 可运用的类型(Type Annotations):在JDK 8之前,注解首要运用于类、办法、字段等元素的声明上。而在JDK 8中,引进了可运用的类型,使得注解能够运用于更多的方位,包含类型的运用上。 可运用的类型注解经过在类型前面增加注解,来对类型运用进行束缚和符号。例如,能够在变量声明、办法参数、泛型类型参数等方位运用注解。 可运用的类型注解供给了更丰富的语义,能够协助编译器和静态剖析东西查看类型运用的合法性,并供给更准确的类型查看和束缚。

这些改动使得注解在JDK 8中变得愈加灵敏和强壮,能够更好地运用于代码的描述、剖析和束缚。重复注解和可运用的类型为开发人员供给了更多的挑选和扩展性,使得注解在Java言语中的运用愈加广泛和多样化。

1.9 支撑并行(parallel)数组

在JDK 8中,引进了对并行数组操作的支撑。这个功用由Arrays类和新的ParallelSorter接口供给 Arrays类中新增了一些用于并行操作数组的办法,其间最突出的是parallelSort()办法。该办法用于对数组进行并行排序,能够显着进步排序的功用。与传统的sort()办法比较,parallelSort()办法会将数组区分为多个小块,并在多个线程上并行进行排序。 以下是一个示例代码,展现了parallelSort()办法的运用:

import java.util.Arrays;
/**
 * @description:
 * @author: shu
 * @createDate: 2023/7/1 9:39
 * @version: 1.0
 */
public class ParallelArrayDemo {
    public static void main(String[] args) {
        int[] numbers = {5, 2, 8, 1, 9, 3, 7, 6, 4};
        // 并行排序数组
        Arrays.parallelSort(numbers);
        // 打印排序成果
        for (int number : numbers) {
            System.out.println(number);
        }
    }
}

在上面的示例中,咱们运用parallelSort()办法对整型数组进行并行排序,然后遍历数组打印排序成果。 需求留意的是,并行数组操作适用于一些能够被区分为独立块的操作,如排序、查找等。关于一些需求依靠前后元素联系的操作,或许不适合运用并行数组操作。 并行数组操作能够充分运用多核处理器的优势,进步处理大规模数据时的功用。但在运用并行操作时,也需求留意合理区分使命和数据的负载均衡,以避免线程竞赛和功率下降。

1.10 对并发类(Concurrency)的扩展

在JDK 8中,对并发类(Concurrency)进行了一些扩展,以供给更强壮、更灵敏的并发编程才能。以下是几个首要的扩展:

  1. CompletableFuture类:CompletableFuture类是一个完结了CompletableFuture接口的异步核算类,用于处理异步使命的成果。它供给了一系列办法,能够经过回调、组合和转化等办法处理异步使命的完结成果。CompletableFuture类使得异步编程愈加便利和直观。
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
/**
 * @description: CompletableFuture并发编程示例
 * @author: shu
 * @createDate: 2023/7/1 9:45
 * @version: 1.0
 */
public class ConcurrencyDemo {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
        // 运用CompletableFuture进行异步核算
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            // 模仿耗时操作
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 42;
        });
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            // 模仿耗时操作
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 100;
        });
        // 运用CompletableFuture处理异步核算成果
        CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(future1, future2);
        combinedFuture.thenRun(() -> {
            int result1 = future1.join();
            int result2 = future2.join();
            map.put("result1", result1);
            map.put("result2", result2);
            System.out.println("Results: " + map);
        });
        // 等候一切使命完结
        combinedFuture.join();
    }
}
  1. LongAdder和DoubleAdder类:LongAdder和DoubleAdder类是对AtomicLong和AtomicDouble的改善。它们供给了更高的并发功用,在高并发场景下更适合运用。LongAdder和DoubleAdder类经过分解内部计数器,将更新操作涣散到多个变量上,以削减竞赛和锁争用。
import java.util.concurrent.atomic.DoubleAdder;
import java.util.concurrent.atomic.LongAdder;
/**
 * @description:
 * @author: shu
 * @createDate: 2023/7/1 9:51
 * @version: 1.0
 */
public class AdderDemo {
    public static void main(String[] args) {
        LongAdder longAdder = new LongAdder();
        DoubleAdder doubleAdder = new DoubleAdder();
        // 多线程并发增加值
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                longAdder.increment();
                doubleAdder.add(0.5);
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                longAdder.increment();
                doubleAdder.add(0.5);
            }
        });
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 输出成果
        System.out.println("LongAdder Result: " + longAdder.sum());
        System.out.println("DoubleAdder Result: " + doubleAdder.sum());
    }
}
  1. StampedLock类:StampedLock类是一种达观读写锁,用于优化读多写少的场景。与传统的读写锁比较,StampedLock类引进了达观读办法,避免了获取锁的开支,供给更好的并发功用。
import java.util.concurrent.locks.StampedLock;
/**
 * @description:
 * @author: shu
 * @createDate: 2023/7/1 9:52
 * @version: 1.0
 */
public class StampedLockDemo {
    private double x, y;
    private final StampedLock lock = new StampedLock();
    public void move(double deltaX, double deltaY) {
        long stamp = lock.writeLock();
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            lock.unlockWrite(stamp);
        }
    }
    public double distanceFromOrigin() {
        long stamp = lock.tryOptimisticRead();
        double currentX = x;
        double currentY = y;
        if (!lock.validate(stamp)) {
            stamp = lock.readLock();
            try {
                currentX = x;
                currentY = y;
            } finally {
                lock.unlockRead(stamp);
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }
    public static void main(String[] args) {
        StampedLockDemo example = new StampedLockDemo();
        example.move(3, 4);
        double distance = example.distanceFromOrigin();
        System.out.println("Distance from origin: " + distance);
    }
}
  1. ConcurrentHashMap类的改善:ConcurrentHashMap类在JDK 8中进行了一些改善,供给了更好的并发功用和扩展性。改善包含分段锁(Segmented Locking)机制的优化和内部数据结构的改善,以削减竞赛和进步并发功用。
import java.util.concurrent.ConcurrentHashMap;
/**
 * @description:
 * @author: shu
 * @createDate: 2023/7/1 9:54
 * @version: 1.0
 */
public class ConcurrentHashMapDemo {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
        // 多线程并发操作map
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                map.put("A" + i, i);
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                map.put("B" + i, i);
            }
        });
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 输出map的巨细和内容
        System.out.println("Map size: " + map.size());
        System.out.println("Map content: " + map);
    }
}

这些扩展供给了更多并发编程的东西和挑选,使得在并发场景下编写高效、牢靠的代码愈加简略。开发人员能够依据详细需求挑选适宜的并发类,以进步运用程序的功用和可弹性性。

二 JDK9 新特性

2.1 模块化

JDK 9 引进了一个重要的特性,即模块化体系(Module System),也称为 Java 渠道模块体系(Java Platform Module System,JPMS)。该特性的方针是改善 Java 渠道的可弹性性、安全性和功用。 模块化体系的首要思维是将 Java 渠道分解为一系列模块,每个模块都有自己的封装和依靠联系。这些模块能够被组合在一同,以构建更大的运用程序或库。 下面是一些 JDK 9 模块化的要害概念:

  1. 模块(Module):模块是一个独立的单元,它由一组相关的包和类组成,而且具有明晰的鸿沟。模块能够指定它所依靠的其他模块,而且能够明晰地声明它对外部国际供给的公共 API。
  2. 模块化源代码(Module Source Code):在 JDK 9 中,源代码被安排为一组模块。每个模块都有自己的目录结构,其间包含模块界说文件 module-info.java,用于声明模块的称号、依靠联系和导出的包等信息。
  3. 模块途径(Module Path):模块途径是一组目录或 JAR 文件的调集,用于加载和链接模块。与传统的类途径不同,模块途径答应显式地指定模块之间的依靠联系。
  4. 模块化 JAR 文件(Modular JAR File):在 JDK 9 中,能够运用新的 JAR 文件格局来创立模块化的 JAR 文件。这些 JAR 文件包含模块界说文件以及其他模块所需的类和资源。
  5. 模块化指令(Module-Related Commands):JDK 9 引进了一些新的指令,用于处理模块化体系。例如,jdeps 指令用于剖析模块之间的依靠联系,jlink 指令用于构建自界说运转时镜像。

模块化体系带来了许多好处,包含:

  • 更好的可维护性:模块的鸿沟明晰,易于了解和维护。
  • 更好的可扩展性:模块之间的依靠联系更明晰,使得运用程序和库的组合愈加灵敏。
  • 更好的功用:模块化体系能够进行更准确的依靠剖析和懒加载,然后进步运用程序的发动时刻和运转时功用。
  • 更好的安全性:模块能够明晰声明它们的对外部国际的公共 API,然后供给更细粒度的拜访操控。

需求留意的是,虽然 JDK 9 引进了模块化体系,但并不是一切的 Java 库和运用程序都需求当即迁移到模块化体系。在 JDK 9 中,依然能够运用传统的类途径来运转非模块化的代码。但是,模块化体系为那些需求更好的可弹性性和安全性的项目供给了一个强壮的东西。

事例一

来个事例:首要在模块化中和需求再跟目录下界说module-info.java,里边上面你需求导入或许露出的模块

/**
 * @description:
 * @author: shu
 * @createDate: 2023/6/30 11:20
 * @version: 1.0
 */
module Model {
    // TODO: 2023/6/30 导入咱们需求的模块
    requires cn.hutool;
    // TODO: 2023/6/30 导出咱们需求的模块
    exports  com.shu.model;
}

JDK8-JDK17新特性总结
咱们调用办法,假如没有导入模块你会发现没有发现该类

import cn.hutool.core.convert.Convert;
/**
 * @description:
 * @author: shu
 * @createDate: 2023/6/30 11:21
 * @version: 1.0
 */
public class Test01 {
    public static void main(String[] args) {
        int a = 1;
        //aStr为"1"
        String aStr = Convert.toStr(a);
        long[] b = {1,2,3,4,5};
        //bStr为:"[1, 2, 3, 4, 5]"
        String bStr = Convert.toStr(b);
    }
}

JDK8-JDK17新特性总结
JDK8-JDK17新特性总结

事例二

当一个事例来阐明 JDK 9 的模块化体系怎么作业。 假设咱们正在开发一个简略的图书办理运用程序,它由几个模块组成:bookmanagement.corebookmanagement.uibookmanagement.data。其间,bookmanagement.core 模块供给核心业务逻辑,bookmanagement.ui 模块供给用户界面,bookmanagement.data 模块供给数据拜访功用。 每个模块都有自己的目录结构,而且包含一个模块界说文件 module-info.java。 首要,让咱们看一下 bookmanagement.core 模块的 module-info.java 文件:

module bookmanagement.core {
    // 需求的模块
    requires bookmanagement.data;
    // 露出的模块
    exports com.example.bookmanagement.core;
}

在这个文件中,咱们声明晰 bookmanagement.core 模块的称号,而且指定了它依靠于 bookmanagement.data 模块。咱们还经过 exports 要害字明晰声明晰 com.example.bookmanagement.core 包对外的公共 API。 接下来,咱们来看一下 bookmanagement.ui 模块的 module-info.java 文件:

module bookmanagement.ui {
    requires bookmanagement.core;
    exports com.example.bookmanagement.ui;
    // 运用那个接口
    uses com.example.bookmanagement.core.BookService;
}

在这个文件中,咱们声明晰 bookmanagement.ui 模块的称号,而且指定了它依靠于 bookmanagement.core 模块。咱们经过 exports 要害字声明晰 com.example.bookmanagement.ui 包对外的公共 API,而且运用 uses 要害字声明晰它运用了 com.example.bookmanagement.core.BookService 接口。 最终,咱们来看一下 bookmanagement.data 模块的 module-info.java 文件:

module bookmanagement.data {
    exports com.example.bookmanagement.data;
    provides com.example.bookmanagement.core.BookService
    with com.example.bookmanagement.data.DefaultBookService;
}

在这个文件中,咱们声明晰 bookmanagement.data 模块的称号,而且经过 exports 要害字声明晰 com.example.bookmanagement.data 包对外的公共 API。咱们还运用 provides 要害字声明晰 com.example.bookmanagement.core.BookService 接口的完结类为 com.example.bookmanagement.data.DefaultBookService。 经过这些模块界说文件,咱们明晰了每个模块的称号、依靠联系和对外的公共 API。现在,咱们能够运用 JDK 9 供给的指令进行编译、打包和运转。 例如,咱们能够运用以下指令编译 bookmanagement.core 模块:

javac -d out/bookmanagement.core src/bookmanagement.core/module-info.java src/bookmanagement.core/com/example/bookmanagement/core/*.java

然后,咱们能够运用 jar 指令将 bookmanagement.core 模块打包为一个模块化 JAR 文件:

jar --create --file=bookmanagement.core.jar --module-version=1.0 -C out/bookmanagement.core .

相似地,咱们能够编译和打包 bookmanagement.uibookmanagement.data 模块。 最终,咱们能够运用 java 指令来运转咱们的运用程序,指定模块途径和主模块:

java --module-path bookmanagement.core.jar;bookmanagement.ui.jar;bookmanagement.data.jar --module bookmanagement.ui/com.example.bookmanagement.ui.Main

这样,咱们就能够经过模块化体系构建和运转咱们的图书办理运用程序。模块化体系协助咱们办理模块之间的依靠联系,保证模块的封装性和对外公共 API 的可控性。它供给了更好的可维护性、可扩展性和安全性。

2.2 JShell

JDK 9 引进了一个名为 jshell 的交互式指令行东西,它供给了一个便利的办法来进行 Java 代码的实时交互式探究和试验。jshell 答应您在不需求编写完好的 Java 类或运用程序的状况下,直接在指令行中编写和履行代码片段。 以下是一些要害特性和用法阐明:

  1. 交互式编程:jshell 供给了一个交互式的指令行环境,您能够直接在指令行中输入和履行 Java 代码。您能够逐行输入代码片段,并当即查看成果。
  2. 即时反馈:每次您输入一行代码,jshell 都会当即履行并显示成果。这样能够快速验证代码并取得实时反馈,无需编译和运转完好的 Java 程序。
  3. 主动补全:jshell 供给了主动补全功用,能够协助您快速输入代码和办法名。按下 Tab 键能够主动补全指令、类、办法等。
  4. 历史记载:jshell 会记载您在交互式会话中输入的代码,并答应您在以后的会话中检索和重复运用之前的代码。
  5. 反常处理:jshell 具有内置的反常处理机制,能够捕获并显示代码中的反常。它会供给有关反常的详细信息,以协助您调试和修正问题。
  6. 界说变量和办法:您能够在 jshell 中界说变量和办法,并在后续代码片段中运用它们。这使得您能够逐渐构建杂乱的逻辑和功用。
  7. 多行输入:jshell 支撑多行输入,您能够运用换行符(“)将一段代码分成多行。

要发动 jshell,您能够在指令行中输入 jshell 指令。然后,您能够开端输入 Java 代码并当即查看成果。以下是一个简略的示例会话:

$ jshell
|  Welcome to JShell -- Version 9
|  For an introduction type: /help intro
jshell> int x = 10;
x ==> 10
jshell> int y = 20;
y ==> 20
jshell> int sum = x + y;
sum ==> 30
jshell> System.out.println("The sum is: " + sum);
The sum is: 30

在这个示例中,咱们界说了两个变量 xy,并核算它们的和。然后,咱们运用 System.out.println 办法打印成果,jshell 关于快速测验代码片段、尝试新功用或进行教育和演示十分有用,它供给了一个轻量级且快捷的办法来进行 Java 代码的交互式探究和验证。

2.3 改善 Javadoc

Javadoc 东西能够生成 Java 文档, Java 9 的 javadoc 的输出现在契合兼容 HTML5 规范。

2.4 多版别兼容JAR

多版别兼容 JAR 是 JDK 9 中引进的一个功用,它答应您创立仅在特定版其他 Java 环境中运转的库程序,并经过运用 --release 参数来指定编译版别。 在 JDK 9 之前,运用旧版其他 JDK 编译的 JAR 文件在较新的 Java 环境中或许会遇到兼容性问题。经过多版别兼容 JAR,您能够运用较新的 JDK 编译您的库程序,并指定兼容的方针 Java 版别,以保证在该版别及更高版其他 Java 环境中运转。 以下是运用 --release 参数创立多版别兼容 JAR 的进程:

  1. 编写您的库程序代码,并运用恰当的 JDK 版别进行编译。假设您正在运用 JDK 11 编译您的库程序。
  2. 运用以下指令创立多版别兼容 JAR 文件:
javac --release <target-version> -d <output-directory> <source-files>

其间:

  • <target-version> 是您希望兼容的方针 Java 版别。例如,假如您希望兼容 Java 8,能够将 <target-version> 设置为 8
  • <output-directory> 是输出目录,用于存放编译生成的类文件。
  • <source-files> 是您的源代码文件或源代码目录。

例如,要创立一个兼容 Java 8 的 JAR 文件,您能够运转以下指令:

javac --release 8 -d output mylibrary/*.java

这将运用 JDK 11 编译您的库程序,并生成与 Java 8 兼容的类文件。

  1. 运用以下指令创立 JAR 文件:

其间:

  • <jar-file> 是要创立的 JAR 文件的称号。
  • <input-directory> 是包含编译生成的类文件的目录。

例如,要创立名为 mylibrary.jar 的 JAR 文件,您能够运转以下指令:

jar --create --file mylibrary.jar -C output .

这将创立一个包含编译生成的类文件的 JAR 文件,现在,您能够将生成的多版别兼容 JAR 文件供给给其他开发人员,以便他们能够在特定的 Java 环境中运用您的库程序。 需求留意的是,运用多版别兼容 JAR 并不会主动供给对较新 Java 版其他新功用和改善的支撑。它仅保证您的库程序能够在指定的方针 Java 版别及更高版其他环境中运转,但不会运用较新版其他言语特性。因而,您需求依据您的方针 Java 版其他要求进行相应的编码和功用挑选。

2.5 调集工厂办法

在 Java 9 中,为调集结构引进了一组新的工厂办法,使创立和初始化调集方针愈加简练和便利。这些工厂办法归于 java.util 包中的 ListSetMap 接口,用于创立不行变的调集方针。 下面是 Java 9 中引进的调集工厂办法的示例用法:

  1. List.of() 办法用于创立不行变的列表方针。例如:
List<String> fruits = List.of("Apple", "Banana", "Orange");

在这个示例中,咱们运用 List.of() 办法创立一个包含三个元素的不行变列表。

  1. Set.of() 办法用于创立不行变的调集方针。例如:
Set<Integer> numbers = Set.of(1, 2, 3, 4, 5);

在这个示例中,咱们运用 Set.of() 办法创立一个包含五个元素的不行变调集。

  1. Map.of() 办法用于创立不行变的键值对映射。例如:
Map<String, Integer> studentScores = Map.of("Alice", 95, "Bob", 80, "Charlie", 90);

在这个示例中,咱们运用 Map.of() 办法创立一个包含三对键值对的不行变映射。 这些调集工厂办法的特色是它们创立的调集方针都是不行变的,即无法修正调会集的元素。这种不行变性有助于编写愈加健壮和牢靠的代码,并供给更好的线程安全性。 需求留意的是,这些调集工厂办法创立的调集方针是不行变的,因而不能对其进行增加、删去或修正元素的操作。假如需求对调集进行修正操作,依然能够运用传统的结构函数或其他办法来创立可变的调集方针。 其他,Java 9 中的调集工厂办法还供给了一系列的重载办法,用于处理不同数量的元素。您能够依据自己的需求挑选适合的办法来创立调集方针。

2.6 私有接口办法

Java 9 引进了一项新的特性,即私有接口办法。这意味着接口能够包含私有的办法完结,这些办法只能在接口内部被调用,关于接口的完结类和其他类是不行见的。 私有接口办法能够协助处理以下问题:

  1. 代码重用:经过在接口中界说私有办法,能够在多个默许办法之间同享代码逻辑,避免代码重复。
  2. 代码安排:私有接口办法能够将杂乱的逻辑分解为更小的、可重用的办法,进步代码的可读性和维护性。

下面是一个示例,演示了怎么在接口中界说和运用私有接口办法:

public interface Calculator {
    // 公共的默许办法
    int add(int a, int b);
    default int subtract(int a, int b) {
        return add(a, negate(b));
    }
    default int multiply(int a, int b) {
        return a * b;
    }
    // 私有接口办法
    private int negate(int number) {
        return -number;
    }
}

在上面的示例中,Calculator 接口界说了三个默许办法 add()subtract()multiply(),以及一个私有接口办法 negate()subtract() 办法内部调用了 add()negate() 办法,而 negate() 办法是一个私有接口办法,只能在接口内部被调用。 经过私有接口办法,咱们能够将 negate() 办法作为辅佐办法来同享逻辑,并在多个默许办法中重复运用。 需求留意的是,私有接口办法不能被完结接口的类或其他类直接调用。它们仅用于在接口内部同享代码逻辑,供给更好的代码安排和代码重用。

2.7 该进的进程API

在 Java 9 中,对进程 API 进行了一些改善,以供给更好的操控和办理运用程序的进程。这些改善首要会集在 java.lang.Process 类和相关类的增强。 以下是 Java 9 中进程 API 的一些改善:

  1. ProcessHandle 类:引进了一个新的 ProcessHandle 类,它代表一个本地操作体系进程的句柄。经过 ProcessHandle 类,您能够获取进程的 PID(进程标识符)、父进程的句柄、子进程的句柄以及其他进程相关的信息。
  2. ProcessHandle.Info 类:ProcessHandle 类中的 info() 办法回来一个 ProcessHandle.Info 方针,它供给了有关进程的详细信息,如进程的指令行参数、发动时刻、累计 CPU 时刻等。
  3. ProcessBuilder 类的改善:ProcessBuilder 类用于创立和发动新的进程。在 Java 9 中,ProcessBuilder 类增加了一些新的办法,例如 inheritIO() 办法,它答应子进程承继父进程的规范输入、输出和过错流。还增加了 redirectInput()、redirectOutput() 和 redirectError() 办法,用于重定向子进程的规范输入、输出和过错流。
  4. destroyForcibly() 办法:Process 类中的 destroyForcibly() 办法用于强制停止进程,不管进程是否呼应。这与 destroy() 办法的差异在于,destroy() 办法会尝试优雅地停止进程,而 destroyForcibly() 办法会强制停止进程。

这些改善使得在 Java 中办理和操控进程愈加灵敏和便利。您能够获取和操作正在运转的进程的信息,获取进程的 PID,以及更好地操控子进程的输入、输出和过错流。这些改善为进程办理和监控供给了更多的功用和选项。 请留意,Java 9 中的进程 API 的改善首要会集在进程办理方面,并没有引进相似于进程间通讯的新功用。假如您需求进行进程间通讯,能够运用其他 Java 渠道供给的库,如 java.nio.channels 或第三方库。

/**
 * @description:
 * @author: shu
 * @createDate: 2023/7/1 11:46
 * @version: 1.0
 */
public class ProcessInfoDemo {
    public static void main(String[] args) {
        // 获取当时进程的 ProcessHandle
        ProcessHandle currentProcess = ProcessHandle.current();
        // 获取当时进程的PID
        long pid = currentProcess.pid();
        System.out.println("当时进程的PID:" + pid);
        // 获取当时进程的信息
        ProcessHandle.Info processInfo = currentProcess.info();
        System.out.println("指令行:" + processInfo.command().orElse(""));
        System.out.println("发动时刻:" + processInfo.startInstant().orElse(null));
        System.out.println("累计CPU时刻:" + processInfo.totalCpuDuration().orElse(null));
    }
}

JDK8-JDK17新特性总结

2.8 改善的Stream API

在Java 9中,Stream API得到了一些改善,以供给更多的操作和增强功用。下面是Java 9中改善的一些Stream API功用:

  1. takeWhile()dropWhile() 办法:引进了 takeWhile()dropWhile() 两个新的Stream办法。takeWhile() 办法回来从流的最初开端的接连元素,直到遇到第一个不满意给定条件的元素。dropWhile() 办法回来从流的最初开端跳过满意给定条件的接连元素,直到遇到第一个不满意条件的元素。
  2. ofNullable() 办法:Stream接口中新增了一个 ofNullable() 静态办法,它答应创立一个包含一个非空元素或空的Stream。假如供给的元素是非空的,将创立一个包含该元素的Stream;假如供给的元素为空,则创立一个空的Stream。
  3. iterate() 办法的重载:Stream.iterate() 办法现在支撑一个谓词(Predicate)作为第二个参数。这样,您能够界说在生成迭代元素时应该停止迭代的条件。
  4. Stream 接口中的新办法:Stream 接口中增加了一些新的办法,如 dropWhile()takeWhile()iterate() 的重载版别,以及 forEachOrdered()toArray() 办法的重载版别。

这些改善使得Stream API愈加灵敏和功用更强壮。您能够运用新的办法来处理更多的流操作场景,例如依据条件获取部分元素、创立包含空元素的流等。 以下是一个示例,展现了Java 9中改善的Stream API的一些用法:

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
 * @description:
 * @author: shu
 * @createDate: 2023/7/1 11:52
 * @version: 1.0
 */
public class StreamApiDemo {
    public static void main(String[] args) {
        // takeWhile() 办法示例
        List<Integer> numbers = Stream.of(1, 2, 3, 4, 5, 6)
                .takeWhile(n -> n < 4)
                .collect(Collectors.toList());
        System.out.println("takeWhile 示例:" + numbers); // 输出:[1, 2, 3]
        // dropWhile() 办法示例
        List<Integer> numbers2 = Stream.of(1, 2, 3, 4, 5, 6)
                .dropWhile(n -> n < 4)
                .collect(Collectors.toList());
        System.out.println("dropWhile 示例:" + numbers2); // 输出:[4, 5, 6]
        // ofNullable() 办法示例
        String name = null;
        List<String> names = Stream.ofNullable(name)
                .collect(Collectors.toList());
        System.out.println("ofNullable 示例:" + names); // 输出:[]
        // iterate() 办法的重载示例
        List<Integer> evenNumbers = Stream.iterate(0, n -> n < 10, n -> n + 2)
                .collect(Collectors.toList());
        System.out.println("iterate 重载示例:" + evenNumbers); // 输出:[0, 2, 4, 6, 8]
        //
        //Stream 接口中的新办法示例
        Stream.of("Java", "Python", "C++")
                .forEachOrdered(System.out::println); // 输出:Java Python C++
    }
}

这个示例展现了怎么运用Java 9中改善的Stream API的一些办法,包含takeWhile()dropWhile()ofNullable()iterate()forEachOrdered()等。您能够运转这个示例并调查输出成果,以便更好地了解这些改善的Stream API功用。

JDK8-JDK17新特性总结

2.9 改善的 try-with-resources

在Java 7中引进了try-with-resources句子,用于在代码块结束时主动封闭完结AutoCloseable接口的资源。Java 9对try-with-resources进行了改善,使其愈加便利和灵敏。 Java 9中改善的try-with-resources句子具有以下特色:

  1. 支撑资源的匿名变量:在Java 9之前,try-with-resources句子中的资源有必要是事前声明的变量。在Java 9中,能够在try要害字之后声明资源的匿名变量,并在try句子块中运用。
  2. 资源的功率改善:在Java 9中,假如资源完结了Closeable接口,编译器会生成更高效的字节码,以削减封闭资源的开支。

下面是一个示例,演示了Java 9中改善的try-with-resources句子的用法:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/**
 * @description:
 * @author: shu
 * @createDate: 2023/7/1 16:04
 * @version: 1.0
 */
public class TryWithResourcesDemo {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,咱们运用try-with-resources句子来主动封闭BufferedReader资源。在try要害字之后,咱们创立了一个匿名的BufferedReader方针,并将其包装在FileReader中。在try句子块中,咱们能够运用reader方针读取文件的内容。 当代码块结束时,不管是否发生反常,reader资源都会主动封闭。这样能够保证资源的正确开释,而无需显式调用close()办法。 需求留意的是,try-with-resources句子能够处理多个资源,只需将它们用分号分隔即可。一切的资源都会在代码块结束时主动封闭,按照资源的声明顺序逆序封闭。 经过运用Java 9中改善的try-with-resources句子,您能够更便利地处理资源的开释,并使代码愈加简练和易读。

2.10 改善的 @Deprecated 注解

在Java 9中,@Deprecated注解得到了一些改善,以供给更多的注释功用和准确的描述。以下是Java 9中改善的@Deprecated注解的特色:

  1. forRemoval特色:@Deprecated注解新增了一个forRemoval特色,用于指示该元素是否被计划用于移除。设置forRemoval=true表明该元素将来会被移除,而设置forRemoval=false表明该元素被抛弃但将保存。
  2. since特色:@Deprecated注解中的since特色用于指定元素被抛弃的版别。经过指定since特色,您能够明晰阐明从哪个版别开端该元素被抛弃。
  3. 更多注释阐明:Java 9为@Deprecated注解增加了更多的注释阐明,使得能够供给更详细和准确的描述,以便开发人员了解为什么该元素被抛弃以及引荐运用的代替办法。

下面是一个示例,演示了Java 9中改善的@Deprecated注解的用法:

public class DeprecatedExample {
    @Deprecated(since = "1.5", forRemoval = true)
    public void oldMethod() {
        // 旧的办法完结
    }
    @Deprecated(since = "2.0", forRemoval = false)
    public void deprecatedMethod() {
        // 抛弃的办法完结
    }
    public static void main(String[] args) {
        DeprecatedExample example = new DeprecatedExample();
        // 调用旧的办法,会收到编译器正告
        example.oldMethod();
        // 调用抛弃的办法,不会收到编译器正告
        example.deprecatedMethod();
    }
}

在这个示例中,咱们界说了一个DeprecatedExample类,其间包含了两个办法:oldMethod()deprecatedMethod()。咱们运用改善的@Deprecated注解对这两个办法进行注释。 在oldMethod()办法上,咱们设置了@Deprecated注解的since特色为”1.5″,forRemoval特色为true,表明该办法从版别1.5开端被抛弃,而且将来会被移除。 在deprecatedMethod()办法上,咱们设置了@Deprecated注解的since特色为”2.0″,forRemoval特色为false,表明该办法从版别2.0开端被抛弃,但是会保存。 在main()办法中,咱们实例化DeprecatedExample方针,并分别调用了旧的办法和抛弃的办法。编译器会对调用旧的办法发生正告,而对调用抛弃的办法不会发生正告。 经过运用Java 9中改善的@Deprecated注解,您能够供给更多的注释信息,包含指定抛弃的版别和是否计划 移除,以便开发人员了解抛弃元素的详细状况,并采取恰当的举动。

2.11 钻石操作符

钻石操作符(Diamond Operator)是Java 7中引进的语法糖,用于在实例化泛型类时省掉类型参数的重复声明。Java 9对钻石操作符进行了改善,使其在更多的状况下能够运用。 在Java 9之前,钻石操作符只能用于变量声明的右侧,而且只能省掉类型参数的声明,不能省掉类型参数的详细实例化。例如:

List<String> list = new ArrayList<>(); // 运用钻石操作符,省掉了类型参数的声明

在Java 9中,钻石操作符的适用范围得到了扩展。现在,钻石操作符不只能够用于变量声明的右侧,还能够用于匿名类的实例化、显式的结构函数调用、显式的办法调用等更多的状况。例如:

// 在匿名类的实例化中运用钻石操作符
Map<String, Integer> map = new HashMap<>() {
    // 匿名类的完结
};
// 在显式的结构函数调用中运用钻石操作符
MyClass obj = new MyClass<>();
// 在显式的办法调用中运用钻石操作符
myMethod(new ArrayList<>());

经过在实例化时运用钻石操作符,能够使代码更简练、更易读。编译器会依据上下文揣度出类型参数,并主动进行类型揣度。 需求留意的是,钻石操作符只能用于具有泛型类型的类的实例化。关于原始类型或无类型参数的类,仍需求显式地声明类型参数。 总结来说,Java 9对钻石操作符进行了改善,使其能够在更多的状况下运用,包含变量声明、匿名类的实例化、显式的结构函数调用、显式的办法调用等。这使得代码愈加简练和易读,一起不影响类型安全性。

2.12 改善的 Optional 类

在Java 8中引进的Optional类供给了一种用于处理或许为null的值的封装。Java 9对Optional类进行了一些改善,以供给更多的有用办法和增强功用 下面是Java 9中改善的Optional类的特色:

  1. ifPresentOrElse()办法:新增了ifPresentOrElse()办法,用于在Optional方针有值时履行一个操作,不然履行一个备选操作。这样能够避免运用传统的if-else句子来处理Optional方针的值。
  2. stream()办法:Optional类中新增了stream()办法,用于将Optional方针转化为一个包含单个元素的Stream。假如Optional方针有值,则回来一个包含该值的Stream,不然回来一个空Stream。
  3. or()办法的重载:Optional.or()办法现在支撑Supplier函数接口,用于供给备选值。假如Optional方针为空,则运用Supplier供给的备选值。
  4. ifPresentOrElse()办法的重载:ifPresentOrElse()办法现在支撑两个Consumer函数接口,分别用于处理Optional方针有值时的状况和没有值时的状况。这样能够供给更多的灵敏性和定制化的处理逻辑。

下面是一个示例,演示了Java 9中改善的Optional类的用法:

import java.util.Optional;
/**
 * @description:
 * @author: shu
 * @createDate: 2023/7/1 16:04
 * @version: 1.0
 */
public class OptionalDemo {
    public static void main(String[] args) {
        Optional<String> optionalValue = Optional.of("Hello");
        // 运用ifPresentOrElse()办法履行操作
        optionalValue.ifPresentOrElse(
                value -> System.out.println("Value: " + value),
                () -> System.out.println("No value present")
        );
        // 运用stream()办法将Optional转化为Stream
        optionalValue.stream()
                .forEach(value -> System.out.println("Stream value: " + value));
        // 运用or()办法供给备选值
        Optional<String> emptyOptional = Optional.empty();
        String result = emptyOptional.or(() -> Optional.of("Default Value"))
                .orElse("Fallback Value");
        System.out.println("Result: " + result);
    }
}

在这个示例中,咱们运用Optional类创立了一个包含值的Optional方针。然后,咱们运用改善的办法对Optional方针进行操作。 运用ifPresentOrElse()办法,咱们指定了一个Consumer函数来处理Optional方针有值时的状况,并指定一个备选操作来处理Optional方针为空的状况。 运用stream()办法,咱们将Optional方针转化为一个包含单个元素的Stream,并对每个元素履行操作。 在or()办法示例中,咱们创立了一个空的Optional方针,并运用Supplier函数供给了一个备选值。假如Optional方针为空,则运用备选值。 经过运用Java 9中改善的Optional类,咱们能够更便利地处理Optional方针,供给更多的处理选项,并使代码更简练和可读。这些改善使得Optional类愈加有用和强壮。

三 JDK10 新特性

参阅网站:openjdk.org/projects/jd…

286: Local-Variable Type Inference 局部变量类型揣度
296: Consolidate the JDK Forest into a Single Repository JDK库的兼并
304: Garbage-Collector Interface 一致的废物收回接口
307: Parallel Full GC for G1 为G1供给并行的Full GC
310: Application Class-Data Sharing 运用程序类数据(AppCDS)同享
312: Thread-Local Handshakes ThreadLocal握手交互
313: Remove the Native-Header Generation Tool (javah) 移除JDK中顺便的javah东西
314: Additional Unicode Language-Tag Extensions 运用附加的Unicode言语符号扩展
316: Heap Allocation on Alternative Memory Devices 能将堆内存占用分配给用户指定的备用内存设备
317: Experimental Java-Based JIT Compiler 运用依据Java的JIT编译器
319: Root Certificates 根证书
322: Time-Based Release Versioning 依据时刻的发布版别

3.1 局部变量类型揣度

JDK 10 引进了局部变量类型揣度,经过运用 var 要害字,能够让编译器依据上下文主动揣度局部变量的类型。这个特功用够使代码愈加简练和易读。 下面是一个示例:

var str = "Hello, World!"; // 揣度为 String 类型
var list = new ArrayList<String>(); // 揣度为 ArrayList<String> 类型

在上面的代码中,var 要害字用于声明局部变量 strlist,编译器依据右侧的表达式主动揣度变量的类型为 StringArrayList<String>。 需求留意的是,局部变量类型揣度只能用于局部变量的声明和初始化,不能用于办法的参数、办法的回来类型、类的字段等。而且揣度的类型是在编译时确定的,运转时变量的类型依然是详细的类型,这个特性并不会影响 Java 的静态类型查看。 局部变量类型揣度能够简化代码书写,特别是在运用泛型、匿名类和杂乱类型时能够削减冗余的类型声明。但是,为了坚持代码的可读性和明晰性,主张在运用 var 要害字时依然给变量赋予有意义的称号。 请留意,这个特性是在 JDK 10 中引进的,假如你运用的是更早的 JDK 版别,将无法运用局部变量类型揣度。

3.2 引进并行 Full GC算法

  • G1 是规划来作为一种低延时的废物收回器。G1搜集器还能够进行十分准确地对中止进行操控。从JDK7开端启用G1废物收回器,在JDK9中G1成为默许废物收回战略。截止到ava 9,G1的Full GC选用的是单线程算法。也便是说G1在发生Full GC时会严重影响功用。
  • JDK10又对G1进行了进步,G1 引进并行 Full GC算法,在发生Full GC时能够运用多个线程进行并行收回。能为用户供给更好的体会。

3.3 运用程序类数据同享

运用程序类数据同享(Application Class-Data Sharing)是 JDK 10 引进的一项特性,它旨在改善 Java 运用程序的发动功用和内存占用。 在传统的 Java 运用程序中,每次发动都需求加载和解析大量的类文件,这会耗费较多的时刻和内存资源。运用程序类数据同享经过将类元数据和字节码预先核算和存储在同享的存档文件中,使得多个 Java 进程能够同享这些数据,然后削减了类加载和解析的时刻和内存开支。 详细来说,运用程序类数据同享包含以下进程:

  1. 构建同享的类数据存档(Shared Class-Data Archive,CDS):运用 java -Xshare:dump 指令构建同享的类数据存档。这个指令会发动运用程序,履行一些预热操作,然后生成一个包含类元数据和字节码的存档文件。
  2. 启用运用程序类数据同享:运用 java -Xshare:on 指令启用运用程序类数据同享。在启用后,Java 进程将运用同享的类数据存档,然后削减类加载和解析的时刻和内存占用。

经过运用程序类数据同享,能够显着缩短 Java 运用程序的发动时刻和削减内存占用,特别关于较大的运用程序或需求频频发动的场景更为有用。 需求留意的是,运用程序类数据同享仅适用于具有相同类途径和相同类加载器结构的 Java 进程。因而,它首要适用于服务器端的 Java 运用程序,而关于客户端或桌面运用程序或许不太适用。 此外,运用程序类数据同享是 JDK 中的商业特性(Commercial Feature),只在 Oracle JDK 和 Oracle OpenJDK 中可用。在其他发行版或代替的 JDK 完结中,或许没有该特性或有所不同的完结办法。

3.4 线程本地握手

  • Safepoint是Hotspot JVM中一种让运用程序一切线程停止的机制。为了要做一些十分之安全的事情,需求让一切线程都停下来它才好做。比方菜市场,人来人往,有人遽然要清点人数,这时候,最好便是咱们都原地不动,这样也好统计。Safepoint起到的便是这样一个作用。
  • JVM会设置一个全局的状况值。运用线程去调查这个值,一旦发现JVM把此值设置为了“咱们都停下来”。此刻每个运用线程就会得到这个告诉,然后各自挑选一个point(点)停了下来。这个点就叫Safepoint。待一切的运用线程都停下来了。
  • JVM就开端做一些安全等级十分高的事情了,比方下面这些事情:废物收拾暂停。类的热更新。偏向锁的撤销。各种debug操作。
  • 但是,让一切线程都到就近的safepoint停下来本是需求较长的时刻。而且让一切线程都停下来显得有些粗暴。为此Java10就引进了一种能够不必stop all threads的办法,便是Thread Local Handshake(线程本地握手)。该新特性的作用线程本地握手是在 JVM 内部相当低等级的更改,修正安全点机制,答应在不运转全局虚拟机安全点的状况下完结线程回调,使得部分回调操作只需求停掉单个线程,而不是停止一切线程。

3.5 JDK库的兼并

JDK 10 引进了一项名为 “JDK 库的兼并”(Consolidate the JDK Forest into a Single Repository)的重要特性。在此之前,JDK 的源代码散布在多个 Mercurial 代码库房中,而 JDK 10 将这些代码库房兼并为一个单一的 Git 代码库房。 JDK 库的兼并旨在简化 JDK 开发和维护进程,进步开发功率和代码办理的一致性。这项特性将 JDK 代码库从 Mercurial 迁移到 Git,并将一切相关代码兼并到一个一致的 Git 库房中,以便更便利地进行代码的版别操控、分支办理和协作开发。 经过将 JDK 代码库兼并为一个 Git 库房,开发者能够更轻松地浏览和查找 JDK 的源代码,一起更简略参加 JDK 的开发和贡献。此外,这也为社区供给了更便利的办法来提交过错报告、贡献补丁和参加 JDK 开发的评论。 JDK 库的兼并是 JDK 10 中一个重要的根底设施变更,关于 JDK 的开发者和维护者来说具有重要的影响。这项特性的引进标志着 JDK 开发进程中的一项重要改善,并为未来的 JDK 版别供给了更灵敏和高效的开发根底。 请留意,以上信息依据 JDK 10 的版别。在更高版其他 JDK 中,或许会有一些改变和进一步的改善。主张查阅官方文档或相关资源以获取最新的信息和详细的阐明。

3.6 试验型的废物收回接口

JDK 10 的首要特性之一是引进了一种试验性的废物收回器接口,称为 “GC 接口”(GC Interface)。该接口的方针是供给一种规范化的办法,使得开发者能够更便利地完结自界说的废物收回器。 GC 接口答应开发者依据 JDK 的废物收回结构构建自界说的废物收回器。经过完结 GC 接口,开发者能够插入自己的废物收回算法和战略,并与 JDK 的其他部分进行集成。 但是,需求留意的是,GC 接口在 JDK 10 中依然是一个试验性的功用,而且不主张在生产环境中运用。这个接口或许在未来的 JDK 版别中进行改善或改变,或许或许被更安稳的代替方案所代替。

3.7 移除JDK中顺便的javah东西

这个东西现已被 javac 中的高档功用所代替,这些功用是在 JDK 8(JDK-7150368)中增加的。此功用供给了在编译 Java 源代码时编写本机头文件的才能,然后消除了对独自东西的需求。

3.8 备⽤内存设备上的堆分配

Java 的堆内存一般是分配在主内存中的,并由 JVM 进行办理。备用内存设备(如 SSD、NVMe 等)一般用于存储持久化数据或作为辅佐存储设备,而不是用于直接的堆内存分配。 但是,关于大型数据处理、高功用核算等特定场景,能够运用一些特殊的技能和东西,例如运用内存映射文件(Memory-mapped Files)将部分堆内存映射到备用存储设备上,以扩展可用的堆内存空间。这种办法能够供给更大的内存容量,但需求慎重考虑功用和数据拜访的开支。

3.9 依据 Java 的试验性 JIT 编译器

Java 10 引进了一个试验性的 JIT(Just-In-Time)编译器,称为 Graal 编译器。Graal 编译器是依据 Java 完结的,它供给了一种代替 HotSpot JIT 编译器的挑选。 Graal 编译器具有以下一些特色和优势:

  1. 高功用:Graal 编译器经过优化和即时编译技能供给了更好的功用表现,特别在特定类型的作业负载上或许比 HotSpot JIT 编译器更快。
  2. 低推迟:Graal 编译器的即时编译才能能够削减运用程序的中止时刻,然后供给更低的推迟和更高的呼应性。
  3. 兼容性:Graal 编译器与现有的 Java 代码和库兼容,并支撑在现有的 JVM 环境中运用。

需求留意的是,虽然 Graal 编译器在功用和推迟方面或许带来优势,但它依然是一个试验性的特性,而且在某些状况下或许与特定的代码或库不兼容。此外,Graal 编译器在编译速度和内存耗费方面或许会有一些权衡,详细取决于运用程序的特色和装备。 为了启用 Graal 编译器,您能够在 JDK 10+ 的发动参数中增加 -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler。这将激活 Graal 编译器并运用它来编译 Java 代码。

3.10 根证书

JDK 10 中的根证书库与之前的版别相似,依然包含在 JDK 装置目录下的 “jre/lib/security” 目录中的 “cacerts” 文件中。 根证书库(cacerts)中包含了一系列受信赖的根证书,用于验证 SSL/TLS 衔接和其他安全通讯。这些根证书由各种受信赖的证书颁布组织(CA)签发,包含常见的公共 CA 如 VeriSign、Thawte、DigiCert 等。 在 JDK 10 中,根证书库或许会有更新,以反映最新的根证书颁布组织和信赖链。因为根证书库的安全性至关重要,因而 Oracle 公司会定期更新 JDK 发布版别中的根证书库,以保证其间包含最新的根证书。 能够运用 JDK 供给的 “keytool” 东西来履行与根证书库相关的操作,例如查看证书、增加新的根证书、删去根证书等。这能够用于办理 JDK 10 中的根证书库,并保证其与最新的证书颁布组织坚持同步。 需求留意的是,根证书库的办理需求慎重操作,保证只信赖牢靠和受信赖的证书颁布组织,并避免操纵根证书库以避免安全危险。

四 JDK11 新特性

参阅官网:openjdk.org/projects/jd…

181: Nest-Based Access Control
181: 依据嵌套的拜访操控
309: Dynamic Class-File Constants
309: 动态类文件常数
315: Improve Aarch64 Intrinsics
315: 改善 Aarch64内部结构
318: Epsilon: A No-Op Garbage Collector
318: Epsilon: 一个不行操作的废物搜集器
320: Remove the Java EE and CORBA Modules
320: 删去 JavaEE  CORBA 模块
321: HTTP Client (Standard)
321: HTTP 客户端(规范)
323: Local-Variable Syntax for Lambda Parameters
323: Lambda 参数的局部变量语法
324: Key Agreement with Curve25519 and Curve448
324:  Curve25519和 Curve448的要害协议
327: Unicode 10
328: Flight Recorder
328: 飞翔记载器
329: ChaCha20 and Poly1305 Cryptographic Algorithms
329: ChaCha20和 Poly1305密码算法
330: Launch Single-File Source-Code Programs
330: 发动单文件源代码程序
331: Low-Overhead Heap Profiling
331: 低开支堆剖析
332: Transport Layer Security (TLS) 1.3
332: 传输层安全(TLS)1.3
333: ZGC: A Scalable Low-Latency Garbage Collector
   (Experimental)
333: ZGC: 一个可弹性的低推迟废物搜集器(试验)
335: Deprecate the Nashorn JavaScript Engine
335: 抛弃 Nashorn JavaScript 引擎
336:
Deprecate the Pack200 Tools and API抛弃 Pack200东西和 API

4.1 Lambda 参数的局部变量语法

在JDK 11及更高版别中,Lambda表达式的参数能够运用var要害字来声明局部变量。运用var要害字能够让编译器依据上下文揣度参数的类型。以下是Lambda参数的局部变量语法示例:

interface MyInterface {
    void myMethod(String name, int age);
}
public class Main {
    public static void main(String[] args) {
        MyInterface myLambda = (var name, var age) -> {
            System.out.println("Name: " + name);
            System.out.println("Age: " + age);
        };
        myLambda.myMethod("John", 25);
    }
}

在上述示例中,咱们运用Lambda表达式完结了MyInterface接口的myMethod办法。Lambda表达式的参数运用var要害字声明为局部变量。编译器会依据上下文揣度参数的类型。 请留意,Lambda参数的类型揣度只适用于局部变量,而不适用于办法的参数类型、回来类型或字段类型。

4.2 HTTP 客户端(规范)

在JDK 11中,引进了规范的HTTP客户端API,用于发送HTTP恳求和处理呼应。这个API供给了一种原生的办法来进行HTTP通讯,不再需求运用第三方库。以下是一个简略的示例:

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;
public class HttpClientExample {
    public static void main(String[] args) throws Exception {
        // 创立HTTP客户端
        HttpClient httpClient = HttpClient.newHttpClient();
        // 创立HTTP恳求
        HttpRequest httpRequest = HttpRequest.newBuilder()
                .uri(URI.create("https://api.example.com/data"))
                .build();
        // 发送HTTP恳求并异步获取呼应
        CompletableFuture<HttpResponse<String>> future = httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString());
        // 处理呼应
        future.thenAccept(response -> {
            int statusCode = response.statusCode();
            String responseBody = response.body();
            System.out.println("Status code: " + statusCode);
            System.out.println("Response body: " + responseBody);
        });
        // 等候异步恳求完结
        future.join();
    }
}

在上述示例中,咱们首要创立一个HttpClient方针,然后构建一个HttpRequest方针,指定恳求的URI。接下来,运用sendAsync办法发送异步恳求,并指定呼应的处理办法(这儿运用HttpResponse.BodyHandlers.ofString()将呼应体解析为字符串)。 经过CompletableFuturethenAccept办法,咱们能够处理异步恳求完结后的呼应。在回调函数中,咱们获取呼应的状况码和呼应体,并进行相应的处理。 最终,咱们运用future.join()等候异步恳求完结。留意,此处的异步恳求是非阻塞的,能够持续履行其他操作。

4.3 新的 Collection.toArray()

在JDK 11中,Collection接口新增了一个重载的toArray办法,用于将调集转化为数组。该办法的签名如下:

default <T> T[] toArray(IntFunction<T[]> generator)

这个办法承受一个IntFunction<T[]>类型的参数,该参数用于供给一个生成指定类型数组的函数。函数的输入参数是调集的巨细,输出是一个新的数组。 下面是一个示例代码,演示怎么运用JDK 11中的Collection.toArray办法:

import java.util.ArrayList;
import java.util.List;
public class CollectionToArrayExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        list.add("C++");
        // 运用Collection.toArray办法转化为数组
        String[] array = list.toArray(String[]::new);
        // 打印数组元素
        for (String element : array) {
            System.out.println(element);
        }
    }
}

在上述示例中,咱们创立了一个ArrayList方针并向其间增加一些元素。然后,咱们运用toArray办法将ArrayList转化为String类型的数组。留意到,咱们运用了String[]::new作为IntFunction参数,这样就会生成一个与调集巨细相同的新数组。 最终,咱们遍历数组并打印每个元素,这个新的toArray办法简化了调集到数组的转化进程,而且避免了类型转化的麻烦。

4.4 新的字符串办法

JDK 11引进了一些新的字符串办法,以供给更便利和强壮的字符串操作功用。以下是一些JDK 11中新增的字符串办法:

  1. **String.isBlank()**:该办法用于查看字符串是否为空白字符串。它回来一个布尔值,指示字符串是否为空白。假如字符串是空白字符串(仅由空格、制表符、换行符等字符组成),则回来true;不然回来false
  2. **String.strip()**:该办法用于去除字符串的首尾空白字符。它回来一个新的字符串,其间去除了原始字符串的首尾空白字符。与trim()办法不同的是,strip()办法能够正确处理Unicode空白字符。
  3. **String.stripLeading()****String.stripTrailing()**:这两个办法分别用于去除字符串的前导空白字符和跟随空白字符。它们回来一个新的字符串,其间去除了原始字符串的前导或跟随空白字符。
  4. **String.lines()**:该办法回来一个包含字符串中一切行的Stream。它依据行停止符将字符串拆分成多个行,并回来一个Stream,每个元素代表一行。
  5. **String.repeat(int count)**:该办法用于重复字符串指定次数,并回来一个新的字符串。它承受一个整数参数count,指定要重复的次数。

这些办法都是在java.lang.String类中新增的,能够直接在字符串方针上调用。它们供给了更直观和便利的字符串操作,简化了对字符串的处理和转化。请留意,这些办法在JDK 11及更高版别中可用。

4.5 新的文件办法

JDK 11引进了一些新的文件办法,以供给更快捷和强壮的文件操作功用。以下是一些JDK 11中新增的文件办法:

  1. **Files.writeString()**:该办法用于将字符串写入文件。它承受一个文件途径和要写入的字符串,能够指定编码格局和可选的文件选项。假如文件不存在,则创立新文件;假如文件已存在,则掩盖原有内容。
  2. **Files.readString()**:该办法用于读取文件内容并以字符串办法回来。它承受一个文件途径,能够指定编码格局和可选的文件选项。
  3. **Files.writeStringList()**:该办法用于将字符串列表逐行写入文件。它承受一个文件途径和字符串列表,能够指定编码格局和可选的文件选项。
  4. **Files.readStringList()**:该办法用于逐行读取文件内容,并以字符串列表的办法回来。它承受一个文件途径,能够指定编码格局和可选的文件选项。
  5. **Files.mismatch()**:该办法用于比较两个文件的内容。它承受两个文件途径,并回来第一个不匹配的字节的方位。假如文件完全相同,则回来-1。

这些办法都是在java.nio.file.Files类中新增的,用于处理文件的读写和比较操作。它们供给了更快捷和高效的办法来操作文件内容。 以下是一个示例代码,演示怎么运用JDK 11的新文件办法读取和写入文件:

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.List;
public class FileOperations {
    public static void main(String[] args) throws Exception {
        String filePath = "example.txt";
        // 写入文件
        String content = "Hello, world!";
        Files.writeString(Path.of(filePath), content);
        // 读取文件
        String fileContent = Files.readString(Path.of(filePath));
        System.out.println("文件内容:\n" + fileContent);
        // 逐行写入文件
        List<String> lines = List.of("Line 1", "Line 2", "Line 3");
        Files.writeStringList(Path.of(filePath), lines, StandardOpenOption.APPEND);
        // 逐行读取文件
        List<String> fileLines = Files.readStringList(Path.of(filePath));
        System.out.println("文件行数:" + fileLines.size());
        System.out.println("文件内容:");
        for (String line : fileLines) {
            System.out.println(line);
        }
    }
}

在上述示例中,咱们首要运用Files.writeString办法将字符串写入文件。然后运用Files.readString办法读取文件内容,并打印到操控台。 接下来,咱们运用Files.writeStringList办法逐行写入字符串列表到文件。然后运用Files.readStringList办法逐行读取文件内容,并打印到操控台。

4.6 一个无操作废物搜集器

JDK 11引进了一个名为”ZGC”(Z Garbage Collector)的新的废物搜集器,它被规划为一种无操作废物搜集器。这意味着它在大部分状况下几乎不会对运用程序的履行形成显着的中止 ZGC是一种低推迟的废物搜集器,旨在完结十分时刻短的中止时刻。它的方针是坚持最大15毫秒的中止时刻,并约束不超越10%的吞吐量损失。这使得ZGC适合那些对低推迟和高吞吐量要求都很高的运用程序。 ZGC运用了一些创新的技能来完结其方针。它运用了一种称为”Region”的内存布局,将堆内存区分为一系列巨细固定的区域,使得废物搜集能够在不停止整个运用程序的状况下并发进行。此外,ZGC还运用了写屏障技能来跟踪方针的引证改变,并在后台处理未拜访的方针。 需求留意的是,ZGC在JDK 11中被符号为试验性特性,而且默许状况下并不启用。要运用ZGC搜集器,需求经过JVM参数显式地启用。能够运用以下参数启用ZGC搜集器:

-XX:+UseZGC

运用ZGC搜集器的示例如下:

public class ZGCExample {
    public static void main(String[] args) {
        // 设置ZGC作为废物搜集器
        System.setProperty("java.vm.useZGC", "true");
        // 运用程序代码...
    }
}

需求留意的是,ZGC仅适用于支撑64位操作体系和64位JVM的渠道。而且在某些状况下,它或许与一些JVM选项不兼容,例如启用了某些特定的试验性特性。

4.7 发动单文件源代码程序

JDK 11引进了一项新功用,答应直接发动单个源代码文件而无需先将其编译为字节码文件。这个功用称为”单文件源代码程序”(Single-File Source-Code Programs)。 要在JDK 11中发动单文件源代码程序,能够运用以下指令:

java <options> <source-file>.java

其间,<options>是可选的JVM选项,<source-file>.java是要履行的源代码文件。 以下是一个示例,演示怎么运用JDK 11发动单文件源代码程序:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

保存上述代码为HelloWorld.java文件。 然后,经过以下指令运转该源代码文件:

java HelloWorld.java

留意,在履行单文件源代码程序时,JDK 11会在内部将源代码文件编译为字节码,并在运转时履行。这使得咱们能够更便利地运转和测验简略的Java程序,而无需事前编译为.class文件。 需求留意的是,单文件源代码程序首要适用于简略的小型程序或测验意图。关于杂乱的项目,依然主张将源代码编译为字节码文件,并运用传统的办法履行。

4.8 依据嵌套的拜访操控

JDK 11引进了一项新的言语特性,即依据嵌套的拜访操控(Nested Access Control)。这个特性旨在供给更细粒度的拜访操控机制,以维护类的内部结构,并更好地支撑模块化开发。 在传统的Java拜访操控中,类的成员(字段、办法、内部类等)能够被声明为publicprotectedprivate或默许(不写拜访修饰符)。这些修饰符操控着类的成员在不同上下文中的可见性。 而依据嵌套的拜访操控引进了两个新的拜访修饰符:privateprotected的嵌套办法。这些修饰符用于约束对嵌套类的拜访,使得只要特定的外部类能够拜访其嵌套类的成员。 详细而言,以下是依据嵌套的拜访操控修饰符的规矩:

  1. **private**的嵌套办法(private nested):内部类声明为private的嵌套办法时,只要外部类能够拜访该嵌套类。
  2. **protected**的嵌套办法(protected nested):内部类声明为protected的嵌套办法时,只要外部类及其子类能够拜访该嵌套类。

这些新的拜访修饰符关于模块化开发十分有用,能够更好地封装类的内部结构,避免不必要的拜访和依靠联系。 以下是一个示例,展现了依据嵌套的拜访操控的运用:

public class OuterClass {
    private int privateField;
    private static class PrivateNestedClass {
        private void privateMethod() {
            OuterClass outer = new OuterClass();
            outer.privateField = 10;
        }
    }
    protected static class ProtectedNestedClass {
        protected void protectedMethod() {
            OuterClass outer = new OuterClass();
            outer.privateField = 20;
        }
    }
    public static void main(String[] args) {
        PrivateNestedClass privateNested = new PrivateNestedClass();
        privateNested.privateMethod();
        ProtectedNestedClass protectedNested = new ProtectedNestedClass();
        protectedNested.protectedMethod();
    }
}

在上述示例中,PrivateNestedClass是一个私有的嵌套类,只要OuterClass内部能够拜访它。ProtectedNestedClass是一个受维护的嵌套类,只要OuterClass及其子类能够拜访它。 在main办法中,咱们能够实例化并调用这些嵌套类的办法,因为它们的拜访约束在其声明的上下文中是有用的。 需求留意的是,依据嵌套的拜访操控修饰符只适用于嵌套类,而不适用于尖端类(即没有外部类的类)。此外,依然能够运用传统的拜访修饰符(publicprotectedprivate和默许)来操控尖端类的拜访性。

4.9 Java 飞翔记载器

JDK 11引进了一个名为”Java飞翔记载器”(Java Flight Recorder,JFR)的功用,它是一个事情记载和剖析引擎,用于在运转时搜集和剖析Java运用程序的运转数据。 Java飞翔记载器能够捕获各种事情,包含办法调用、废物搜集、线程活动、I/O操作等。它还能够搜集各种衡量方针,如CPU运用率、内存运用量、线程数量等。这些事情和衡量方针能够用于剖析和优化运用程序的功用、诊断问题和进行毛病扫除。 运用Java飞翔记载器需求以下进程:

  1. 启用Java飞翔记载器:要运用Java飞翔记载器,首要需求在JVM参数中启用它。能够运用以下参数启用JFR:
-XX:+UnlockCommercialFeatures -XX:+FlightRecorder

留意,Java飞翔记载器归于商业特性,在某些Java发行版中或许需求恰当的许可证。

  1. 装备和发动飞翔记载器:一旦启用了Java飞翔记载器,你能够运用指令行东西(如jcmdjfr)或编程办法来装备和发动飞翔记载器。你能够指定要记载的事情类型、持续时刻等。
  2. 搜集和剖析记载数据:在运用程序运转期间,Java飞翔记载器将会搜集指定的事情和衡量方针。搜集的数据能够保存到文件中。然后,你能够运用Java Mission Control(JMC)或其他东西来加载和剖析这些记载文件,以取得有关运用程序功用和行为的详细信息。

Java飞翔记载器供给了强壮的功用剖析和毛病扫除才能,能够协助开发人员辨认和处理运用程序中的功用问题和反常状况。它是JDK 11中一个重要的调试和优化东西。

4.10 低开支的堆剖析

在JDK 11中,引进了一项名为”低开支的堆剖析”(Low Overhead Heap Profiling)的功用,它答应在运用程序运转时搜集堆剖析数据,以便更好地了解和调试内存运用状况。 传统的堆剖析东西一般会对运用程序的内存进行全面的快照,以获取详细的方针分配和引证联系信息。但是,这种全面的堆快照搜集进程或许会对运用程序的功用发生较大的开支,特别是在大型运用程序中。 低开支的堆剖析经过削减采样频率和记载粒度,以及运用一些技能手段来削减开支,然后供给了一种更轻量级的堆剖析办法。它能够在运用程序运转时进行堆剖析,对内存运用状况进行采样,并生成堆剖析报告。 要运用低开支的堆剖析功用,能够运用以下JVM参数:

-XX:StartFlightRecording=heap=low

这将启用低开支的堆剖析,并将堆剖析数据记载到默许的JFR文件中。 然后,能够运用Java Mission Control(JMC)或其他JFR剖析东西加载和剖析生成的JFR文件,以取得有关运用程序内存运用的详细信息。JFR剖析东西供给了堆分配热门、方针散布、方针生命周期等信息,协助开发人员辨认内存泄漏、过度分配和其他内存相关问题。 需求留意的是,低开支的堆剖析是一种近似的剖析办法,它或许会在某些状况下丢失一些细节信息。因而,在某些状况下,依然主张运用传统的全面堆剖析办法来获取更准确的堆快照。

4.11 从 Oracle JDK 中移除 JavaFX

从 Java 11 开端,JavaFX(以及相关的 javapackager 东西)不再随 JDK 一同供给。相反,咱们能够从 JavaFX 主页将其作为独自的 SDK 下载。

4.12 删去模块

JEP 320 从 JDK 中删去了以下模块:

  • java.xml.ws (JAX-WS)
  • java.xml.bind (JAXB)
  • java.activation (JAF)
  • java.xml.ws.annotation(通用注解)
  • java.corba (CORBA)
  • java.transaction (JTA)
  • java.se.ee(前面提到的六个模块的聚合器模块)
  • jdk.xml.ws(JAX-WS 东西)
  • jdk.xml.bind(JAXB 东西)

其他请参阅官方文档

五 JDK12 新特性

参阅:openjdk.org/projects/jd…


189:
Shenandoah: A Low-Pause-Time Garbage Collector (Experimental)Shenandoah: 低暂停时刻废物搜集器(试验)
230:
Microbenchmark Suite微基准测验套件
325:
Switch Expressions (Preview)开关表达式(预览)
334:
JVM Constants APIJVM 常量 API
340:
One AArch64 Port, Not Two一个 AArch64端口,不是两个
341:
Default CDS Archives默许的 CDS 存档
344:
Abortable Mixed Collections for G1可流产的 G1混合调集
346:
Promptly Return Unused Committed Memory from G1从 G1及时回来未运用的提交内存

5.1 Switch表达式(Preview)

JDK 12引进了一个名为”Switch表达式(Preview)”的功用,它对Switch句子进行了改善,使其愈加灵敏和易用。Switch表达式答应在Switch句子中运用Lambda风格的语法进行办法匹配,并直接回来值。 在传统的Switch句子中,每个case分支都需求运用break句子来避免掉落到下一个分支。而在Switch表达式中,咱们能够运用箭头(->)来直接回来值,而不需求运用break句子。 以下是Switch表达式的示例:

int day = 3;
String dayName = switch (day) {
    case 1, 2, 3, 4, 5 -> "Weekday";
    case 6, 7 -> "Weekend";
    default -> "Invalid day";
};

在上述代码中,Switch表达式依据day的值进行办法匹配,然后回来相应的字符串。在case分支中,能够运用逗号将多个值组合在一同,表明它们同享相同的处理逻辑。在最终的default分支中,假如没有匹配的状况,将回来”Invalid day”。 Switch表达式的语法比传统的Switch句子更简练和易读。它能够削减重复的代码和易错的break句子,使得代码愈加明晰和紧凑。 需求留意的是,Switch表达式在JDK 12中是作为预览功用引进的,意味着它是一项试验性的功用,或许会在后续的JDK版别中进行调整和改善。要运用Switch表达式,需求保证在编译器选项中启用了预览功用,例如运用--enable-preview选项。

5.2 微基准测验套件

JDK 12引进了Microbenchmark Suite(JEP 230),它是一个用于编写和运转微基准测验的套件。微基准测验是一种专门用于丈量小块代码片段的功用的测验办法。 Microbenchmark Suite供给了一组东西和库,协助开发人员编写和履行微基准测验,并供给准确的功用丈量成果。以下是Microbenchmark Suite的一些要害特色:

  1. @Benchmark注解:Microbenchmark Suite经过@Benchmark注解符号要进行功用测验的办法。这样,开发人员能够将注解增加到他们想要测验的办法上,以指示该办法是一个微基准测验。
  2. Blackhole类:Microbenchmark Suite供给了Blackhole类,用于耗费被测验办法的成果,以避免JVM进行优化和消除未运用的代码。这样能够更准确地丈量办法的功用。
  3. 测验运转器:Microbenchmark Suite供给了一个测验运转器,用于履行微基准测验,并生成关于每个测验的功用丈量成果。测验运转器能够装备以操控测验的参数和履行办法。

经过运用Microbenchmark Suite,开发人员能够编写和运转准确的微基准测验,以丈量特定代码片段的功用,并进行功用优化。微基准测验能够协助开发人员辨认潜在的功用问题、比较不同完结的功用差异,并确定功用优化的方向。 需求留意的是,微基准测验需求慎重运用,因为功用测验成果或许会遭到多种因素的影响,如硬件环境、废物搜集器、JVM参数等。因而,在进行微基准测验时,需求了解其原理、正确运用东西和库,并进行合理的成果解释和剖析。

5.3 JVM 常量 API

在 JDK 12 中,Java 虚拟机(JVM)引进了一些常量 API,以便在运转时获取 JVM 的一些常量信息。这些常量 API 首要位于 java.lang.constant 包中,供给了一种安全和类型安全的办法来拜访这些常量。 以下是 JDK 12 中一些常量 API 的首要类和接口:

  1. java.lang.constant.Constable:这是一个符号接口,表明一个常量值能够在编译时被笼统为常量。这个接口有助于在编译时履行常量折叠和内联优化。
  2. java.lang.constant.ConstantDesc:这是一个通用的常量描述符接口,用于表明各种类型的常量。它是一切常量类型的父接口。
  3. java.lang.constant.ClassDesc:这是一个常量描述符接口,表明一个类类型的常量。它供给了获取类名、包名等信息的办法。
  4. java.lang.constant.MethodTypeDesc:这是一个常量描述符接口,表明办法类型的常量。它供给了获取办法参数类型和回来类型的办法。
  5. java.lang.constant.DynamicCallSiteDesc:这是一个常量描述符接口,表明一个动态调用点(Dynamic Call Site)的常量。它供给了获取调用点信息的办法。
  6. java.lang.constant.DirectMethodHandleDesc:这是一个常量描述符接口,表明一个直接办法句柄(Direct Method Handle)的常量。它供给了获取办法句柄信息的办法。
  7. java.lang.constant.ConstableDesc:这是一个常量描述符接口,表明一个常量值的常量。它供给了获取常量值的办法。

除了上述接口,还有一些其他类和接口,用于支撑不同类型的常量,如字段常量、模块常量等。 这些常量 API 的引进使得开发人员能够更便利地在运转时拜访和处理 JVM 中的常量信息,然后完结更高效和更安全的代码。

5.4 默许 CDS 档案

JDK 12 引进了一个新功用,称为默许 CDS(Class Data Sharing)档案。CDS 是一项技能,它答应在 JVM 发动时将类的元数据和字节码预先加载到同享存档文件中,以进步运用程序的发动时刻和内存占用。 在 JDK 12 中,默许 CDS 供给了一种简化的办法来创立和运用 CDS 档案。它答应您运用默许的装备文件来主动创立 CDS 档案,而无需手动指定类列表。 以下是运用默许 CDS 档案的进程:

  1. 运转运用程序时,增加 -XX:DumpLoadedClassList=<classlist.txt> 参数。这将在运用程序退出时生成一个类列表文件 classlist.txt,其间包含了运用程序加载的一切类。
  2. 运用 jlink 指令创立一个包含默许 CDS 档案的自界说运转时映像。增加 --class-list=<classlist.txt> 参数,其间 <classlist.txt> 是第一步生成的类列表文件的途径。
  3. 在发动运用程序时,运用 java 指令指定 -Xshare:dump 参数来生成默许的 CDS 档案。这将依据默许的装备文件(<JDK>/lib/classlist)主动创立 CDS 档案。
  4. 在后续发动运用程序时,运用 -Xshare:on 参数来启用默许 CDS 档案。这将运用预先生成的 CDS 档案来加速运用程序的发动。

需求留意的是,默许 CDS 档案功用在不同的渠道和 JDK 发行版中或许有所差异。在一些渠道上,CDS 功用或许需求特定的许可证。此外,CDS 档案的创立和运用或许会因运用程序的特性而有所不同,因而主张参阅相关的 JDK 文档和文档以获取详细信息和指导。

5.5 G1 的可流动混合搜集

G1的方针之一是满意用户供给的暂停时刻方针以暂停其搜集暂停。G1运用高档剖析引擎来挑选在调集期间 要完结的作业量(这部分依据运用程序行为)。此挑选的成果是一组称为调集集的区域。一旦确定了调集集而且 现已开端调集,则G1有必要在不停止的状况下搜集调集集的一切区域中的一切活动方针。假如启发式挑选过大的收 集,则此行为可导致G1超越暂停时刻方针,例如,假如运用程序的行为发生改变,以致启发式作业在“陈腐”数据 上,则或许发生这种状况。特别是在混合调集期间能够调查到这种状况,其间调集集一般能够包含太多旧区域。 需求一种机制来检测启发式办法何时重复为调集挑选过错的作业量,假如是,则让G1逐渐递增地履行搜集作业, 其间调集能够在每个进程之后中止。这种机制将答应G1更频频地满意暂停时刻方针。 其他详细信息请参阅官网

六 JDK13 新特性

参阅官网:openjdk.org/projects/jd…


350:
Dynamic CDS Archives动态 CDS 存档
351:
ZGC: Uncommit Unused Memory撤销未运用内存
353:
Reimplement the Legacy Socket API从头完结遗留套接字 API
354:
Switch Expressions (Preview)开关表达式(预览)
355:
Text Blocks (Preview)文本块(预览)

6.1 动态CDS归档(Dynamic CDS Archiving)

在JDK 13中,引进了一项名为动态CDS归档(Dynamic CDS Archiving)的新功用。CDS(Class Data Sharing)是一种技能,它答应将类的元数据和字节码预先加载到同享归档文件中,以进步运用程序的发动时刻和内存占用。动态CDS归档进一步扩展了CDS的才能,使得在运用程序运转时能够动态地创立和更新CDS归档。 动态CDS归档的首要优势在于,它答应在运用程序运转时搜集和记载正在运用的类和库,并将它们增加到已存在的CDS归档中,然后完结动态的类同享。这样,在下次发动运用程序时,能够运用包含动态更新的CDS归档,进一步加速运用程序的发动。 以下是运用动态CDS归档的一般进程:

  1. 运用JDK 13构建运用程序,并保证启用CDS。能够经过运用以下参数来启用CDS:-XX:ArchiveClassesAtExit=<archive-file>
  2. 运转运用程序,让它进行正常操作。这将导致动态CDS归档文件被创立。
  3. 在下次发动运用程序时,运用以下参数来启用CDS并指定从前创立的动态CDS归档文件:-XX:SharedArchiveFile=<archive-file>

经过这种办法,运用程序能够运用从前搜集的动态CDS归档文件,然后加速发动时刻和削减内存耗费。 需求留意的是,动态CDS归档功用在JDK 13中是作为试验性功用引进的。因而,在运用时应慎重评价其在特定运用程序和环境中的作用,并保证遵从官方文档和最佳实践。

6.2 从头完结遗留套接字 API

java.net.Socket和java.net.ServerSocket API将一切套接字操作托付给java.net.SocketImpl,这是自JDK 1.0起现已存在的服务供给程序接口(SPI)机制。内置的完结称为“普通”完结,由非公开的PlainSocketImpl经过支撑类SocketInputStream和SocketOutputStream施行。 PlainSocketImpl由其他两个JDK内部完结扩展,这些完结支撑经过SOCKS和HTTP署理服务器的衔接。默许状况下,运用依据SOCKS的SocketImpl创立Socket和ServerSocket(有时是推迟的)。在ServerSocket的状况下,运用SOCKS完结是一个古怪的事情,能够追溯到对JDK 1.4中的署理服务器衔接的试验性(而且自从删去以来)支撑。 新的完结NioSocketImpl代替了PlainSocketImpl。它被开发为易于维护和调试。它与新I / O(NIO)完结同享相同的JDK内部根底结构,因而不需求自己的本机代码。它与现有的缓冲区高速缓存机制集成在一同,因而不需求将线程仓库用于I / O。它运用java.util.concurrent锁而不是同步办法,以便将来能够在fibers上很好地运用。在JDK 11中,大多数NIO SocketChannel和其他SelectableChannel完结都是在完结相同方针的状况下从头完结的。

6.3 Switch表达式

在JDK 13中,Switch表达式引进了一些新的语法和功用,使得在Switch句子中编写更简练和灵敏的代码成为或许。下面是一些JDK 13中Switch表达式的示例:

  1. 简略的Switch表达式:
int day = 3;
String dayName = switch (day) {
    case 1 -> "Monday";
    case 2 -> "Tuesday";
    case 3 -> "Wednesday";
    case 4 -> "Thursday";
    case 5 -> "Friday";
    default -> "Invalid day";
};
System.out.println(dayName);  // 输出: Wednesday

在这个比如中,咱们运用Switch表达式依据给定的day值回来对应的星期几称号。

  1. 表达式和句子的组合:
int day = 5;
String dayType = switch (day) {
    case 1, 2, 3, 4, 5 -> {
        yield "Weekday";  // 运用yield回来一个值
    }
    case 6, 7 -> {
        System.out.println("It's a weekend!");  // 履行句子
        yield "Weekend";
    }
    default -> {
        yield "Invalid day";
    }
};
System.out.println(dayType);  // 输出: Weekend

在这个比如中,咱们依据给定的day值回来对应的日期类型。假如是作业日(1-5),咱们运用yield回来一个字符串值。假如是周末(6-7),咱们首要打印一条音讯,然后回来一个字符串值。

  1. 表达式的回来类型揣度:
String dayName = switch (getDayOfWeek()) {
    case 1 -> "Monday";
    case 2 -> "Tuesday";
    case 3 -> "Wednesday";
    case 4 -> "Thursday";
    case 5 -> "Friday";
    default -> "Invalid day";
};
System.out.println(dayName);

在这个比如中,getDayOfWeek()办法回来一个整数表明星期几。在Switch表达式中,咱们依据这个回来值进行匹配,并回来对应的星期几称号。留意,咱们没有显式地指定Switch表达式的回来类型,而是运用类型揣度,编译器会主动揣度回来类型为String。 这些示例展现了JDK 13中Switch表达式的一些用法。Switch表达式的引进使得编写简练、灵敏的条件分支逻辑变得愈加简略。

6.4 文本块

在JDK 13中,引进了文本块(Text Blocks)功用,它供给了一种更直观和易读的办法来界说多行字符串。文本块使得在Java代码中编写包含换行符和缩进的长字符串变得愈加便利。下面是一些JDK 13中文本块的示例:

  1. 根本的文本块:
String htmlContent = """
    <html>
        <body>
            <h1>Hello, JDK 13!</h1>
        </body>
    </html>
""";

在这个比如中,咱们运用文本块界说了一个包含HTML符号的字符串。文本块运用三个双引号(”””)作为开始和结束符号,使得能够在字符串中包含多行内容,而且保存了换行符和缩进。

  1. 转义字符的处理:
String message = """
    This is a multiline string \
    with line continuation.
""";

在这个比如中,咱们运用文本块界说了一个包含转义字符的多行字符串。在文本块中,运用反斜杠(\)来表明行衔接符,能够在多行字符串中完结行的接连。

  1. 引号的处理:
String quote = """
    She said, "Java is awesome!"
""";

在这个比如中,咱们运用文本块界说了一个包含引号的多行字符串。在文本块中,能够直接运用引号而无需进行转义。

  1. 保存缩进的操控:
String indentedString = """
    This is an indented string.
        It has nested indentation.
    """;

在这个比如中,咱们运用文本块界说了一个具有保存缩进的字符串。文本块中的每行会保存与开始双引号的缩进等级一致的空格。

6.5 ZGC改善

在JDK 13中,ZGC(Z Garbage Collector)废物搜集器进行了一些改善,以进一步降低废物搜集的中止时刻并进步吞吐量。以下是一些JDK 13中ZGC的改善:

  1. 中止时刻优化:ZGC经过引进更多并发操作来削减废物搜集的中止时刻。JDK 13对ZGC进行了一些优化,以削减并发符号和并发收拾阶段的中止时刻。这意味着运用程序在运转时不会因为废物搜集而出现显着的中止。
  2. 吞吐量改善:ZGC的方针之一是在削减中止时刻的一起进步吞吐量。JDK 13引进了一些吞吐量方面的改善,以进步运用程序的整体功用。这些改善包含并发废物搜集的并行处理,以及更高效的内存分配和收回战略。
  3. 栈上分配:ZGC在JDK 13中引进了栈上分配(Stack Allocation)的优化。栈上分配是一种优化技能,将一些时刻短的方针分配到线程的栈上,而不是堆上。这样能够削减废物搜集的作业量,而且能够更快地收回这些时刻短方针。
  4. 并发Class Unloading:JDK 13中的ZGC引进了并发类卸载(Concurrent Class Unloading)的功用。这意味着当类不再运用时,能够在运用程序运转时卸载类,而无需停止运用程序的履行。这有助于削减内存占用,并进步运用程序的可弹性性。

这些改善使得ZGC在JDK 13中愈加适用于处理大型堆内存和具有低推迟要求的运用程序。但是,需求留意的是ZGC并非适用于一切场景,详细的废物搜集器挑选应该依据运用程序的特色和需求进行评价和挑选。 请留意,ZGC是在JDK 11中初次引进的,而在JDK 13中进行了一些改善和优化。

七 JDK14 新特性

参阅网站:openjdk.org/projects/jd…


305:
Pattern Matching for instanceof (Preview)Instanceof 的办法匹配(预览)
343:
Packaging Tool (Incubator)包装东西(孵化器)
345:
NUMA-Aware Memory Allocation for G1依据 NUMA 的 G1内存分配
349:
JFR Event StreamingJFR 事情流
352:
Non-Volatile Mapped Byte Buffers非易失性映射字节缓冲区
358:
Helpful NullPointerExceptions有用的 NullPointerException
359:
Records (Preview)档案(预览)
361:
Switch Expressions (Standard)开关表达式(规范)
362:
Deprecate the Solaris and SPARC Ports抛弃 Solaris 和 SPARC 端口
363:
Remove the Concurrent Mark Sweep (CMS) Garbage Collector删去并发符号扫描(CMS)废物搜集器
364:
ZGC on macOS
365:
ZGC on WindowsWindows 上的 ZGC
366:
Deprecate the ParallelScavenge + SerialOld GC Combination不引荐运用并行铲除 + SerialOld GC 组合
367:
Remove the Pack200 Tools and API删去 Pack200东西和 API
368:
Text Blocks (Second Preview)文本块(第2次预览)
370:
Foreign-Memory Access API (Incubator)外部内存拜访 API (孵化器)

7.1 instanceof办法匹配

instanceof办法匹配是JDK 14引进的一项新特性,用于简化对类型的查看和转化操作。在以往的Java版别中,运用instanceof进行类型查看后,需求进行显式的类型转化才能运用该类型的特定办法或特色。而运用instanceof办法匹配后,能够在同一表达式中进行类型查看和类型转化。 下面是一个运用instanceof办法匹配的示例:

public void processShape(Shape shape) {
    if (shape instanceof Circle c) {
        double area = Math.PI * c.getRadius() * c.getRadius();
        System.out.println("Circle area: " + area);
    } else if (shape instanceof Rectangle r) {
        double area = r.getWidth() * r.getHeight();
        System.out.println("Rectangle area: " + area);
    } else if (shape instanceof Triangle t) {
        double area = 0.5 * t.getBase() * t.getHeight();
        System.out.println("Triangle area: " + area);
    } else {
        System.out.println("Unknown shape");
    }
}

在上述示例中,processShape办法接收一个Shape方针作为参数,并运用instanceof办法匹配来查看方针的详细类型。假如方针是Circle类型,则在if句子中的instanceof后声明一个新的变量c,表明类型为Circle的方针,然后能够直接运用c的办法和特色。相同地,关于RectangleTriangle类型,也能够在对应的instanceof句子中声明新的变量并运用。 这种办法匹配的语法办法为:instanceof 类型 变量,其间类型是要查看的类型,变量是在该分支中表明该类型的方针。这样能够避免了显式的类型转化,使代码愈加简练和可读性更高。 需求留意的是,instanceof办法匹配只在对应的if句子分支中有用,假如想在后续的代码中持续运用现已声明的变量,需求将其进步到外部作用域。

7.2 Records(记载类型)

Records(记载类型)是JDK 14引进的一项新特性,它简化了创立不行变(immutable)数据方针的进程。经过运用record要害字,能够界说一个记载类型,该类型主动生成了一些规范的办法,如结构函数、getter办法、equals()、hashCode()和toString()等办法。 以下是一个运用记载类型的示例:

public record Person(String name, int age) {
    // 主动生成了结构函数和getter办法
}
// 创立记载类型的实例
Person person = new Person("John Doe", 30);
// 拜访记载类型的特色
String name = person.name();
int age = person.age();
// 主动生成的toString()办法
System.out.println(person);

在上述示例中,运用record要害字界说了一个名为Person的记载类型,它有两个特色:nameage。经过界说记载类型,咱们能够避免手动编写结构函数和getter办法,这些办法会主动生成并与记载类型绑定。 咱们能够运用记载类型的结构函数来创立实例,然后经过主动生成的getter办法拜访特色。例如,person.name()回来记载类型实例的name特色值。 此外,记载类型还供给了主动生成的equals()hashCode()办法,用于比较记载类型的持平性和生成哈希码。一起,它还供给了主动生成的toString()办法,用于以字符串办法表明记载类型的内容。 需求留意的是,记载类型是不行变的,即一旦创立,就不能修正其特色的值。假如需求修正特色,需求创立一个新的记载类型实例。 记载类型的引进简化了创立简略数据方针的进程,削减了样板代码,进步了代码的可读性和可维护性,特别适用于那些只包含数据的简略方针。

7.3 Switch表达式扩展

JDK 14对switch表达式进行了扩展,使其愈加强壮和灵敏。以下是一些switch表达式的扩展特性:

  1. 运用箭头语法(Arrow Syntax):在JDK 14之前,switch句子运用冒号(:)来分隔标签和相应的代码块。但在JDK 14中,引进了箭头(->)来代替冒号,使得switch句子愈加简练和易读。 示例:
int dayOfWeek = 3;
String dayType = switch (dayOfWeek) {
    case 1, 2, 3, 4, 5 -> "Weekday";
    case 6, 7 -> "Weekend";
    default -> throw new IllegalArgumentException("Invalid day of the week: " + dayOfWeek);
};
  1. 运用多个标签(Multiple Labels):在JDK 14中,能够在一个case句子中运用多个标签,以逗号分隔。这样能够将多个标签映射到同一段代码,避免了重复的代码块。 示例:
int number = 2;
switch (number) {
    case 1, 2, 3:
        System.out.println("Number is between 1 and 3");
        break;
    case 4, 5, 6:
        System.out.println("Number is between 4 and 6");
        break;
    default:
        System.out.println("Number is out of range");
        break;
}
  1. 运用yield句子回来值(Yield Statement):在JDK 14中,能够在switch表达式的每个分支中运用yield句子回来一个值。这样能够更便利地从switch表达式中回来成果。 示例:
int number = 2;
String numberType = switch (number) {
    case 0:
    case 1:
        yield "Even";
    case 2:
    case 3:
        yield "Odd";
    default:
        yield "Unknown";
};

这些扩展使得switch表达式愈加强壮和灵敏,能够更明晰地表达代码逻辑,并削减冗余代码。

7.4 废物收回器(Garbage Collectors)增强

在JDK 14中,引进了两个新的废物收回器:ZGC(Z Garbage Collector)和Shenandoah,以增强Java运用程序的废物收回功用。以下是对它们的扼要介绍:

  1. ZGC(Z Garbage Collector):ZGC是一种低推迟的废物收回器,旨在削减Java运用程序的中止时刻。它是一种并发废物收回器,能够在十分时刻短的暂停时刻内履行大部分的废物收回操作。ZGC的方针是使得废物收回中止时刻不超越10毫秒,而且在几百兆字节至几个太字节的堆巨细下具有可扩展性。
  2. Shenandoah:Shenandoah是另一种低推迟的废物收回器,专心于最小化运用程序的中止时刻。它是一种并发符号-铲除废物收回器,它的首要方针是在堆巨细为几百兆字节到几个太字节之间,供给可承受的废物收回中止时刻。Shenandoah选用了一种全局并发符号算法,使得符号阶段与运用程序线程并发履行,然后削减了中止时刻。

这两个废物收回器的共同方针是削减Java运用程序的中止时刻,以进步运用程序的呼应功用。它们选用了不同的废物收回算法和技能,适用于不同的运用场景和堆巨细。挑选运用哪个废物收回器取决于运用程序的特性、功用需求以及硬件装备。 需求留意的是,ZGC和Shenandoah在JDK 14中被符号为试验性功用,能够经过指令行选项来启用它们。在后续的JDK版别中,这些废物收回器或许会持续改善和优化,以供给更好的功用和安稳性。

7.5 Numeral Formatting

在JDK 14中,引进了对Numeral Formatting的增强,首要经过java.text.NumberFormat类的新办法和功用进行改善。以下是JDK 14中Numeral Formatting的一些新特性:

  1. 运用CompactNumberFormat类: JDK 14引进了CompactNumberFormat类,它是NumberFormat的子类,用于在格局化数字时以紧凑办法显示。它能够依据数字的巨细主动挑选适宜的单位(如K、M、B等)来显示数字。 示例:
double value = 12345678;
NumberFormat nf = NumberFormat.getCompactNumberInstance();
String formattedValue = nf.format(value);
System.out.println(formattedValue); // 输出:12M
  1. 新的toLocalizedPattern()toPattern()办法: 在JDK 14中,NumberFormat类新增了toLocalizedPattern()toPattern()办法,用于获取数字格局化办法的本地化字符串表明和原始字符串表明。 示例:
NumberFormat nf = NumberFormat.getInstance();
String localizedPattern = nf.toLocalizedPattern();
String pattern = nf.toPattern();
System.out.println(localizedPattern);
System.out.println(pattern);
  1. 增强的小数位数操控: 在JDK 14中,NumberFormat类的setMaximumFractionDigits()setMinimumFractionDigits()办法支撑负数参数,用于设置小数位数的上限和下限。负数值表明保存尽或许多的小数位数,但至少保存指定的数目。 示例:
double value = 1234.56789;
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(-1); // 保存尽或许多的小数位数
nf.setMinimumFractionDigits(2); // 至少保存2位小数
String formattedValue = nf.format(value);
System.out.println(formattedValue); // 输出:1,234.56789

这些增强使得在JDK 14中进行Numeral Formatting愈加便利和灵敏。能够依据需求运用紧凑办法、获取格局化办法的本地化字符串表明以及对小数位数进行更精密的操控。

八 JDK15新特性

参阅网站:openjdk.org/projects/jd…


339:
Edwards-Curve Digital Signature Algorithm (EdDSA)曲线数字签名算法
360:
Sealed Classes (Preview)密封类(预览)
371:
Hidden Classes躲藏类别
372:
Remove the Nashorn JavaScript Engine删去 Nashorn JavaScript 引擎
373:
Reimplement the Legacy DatagramSocket API从头完结遗留 DatagramSocket API
374:
Disable and Deprecate Biased Locking禁用和撤销误差确定
375:
Pattern Matching for instanceof (Second Preview)办法匹配(第2次预览)
377:
ZGC: A Scalable Low-Latency Garbage CollectorZGC: 一个可弹性的低推迟废物搜集器
378:
Text Blocks文本块
379:
Shenandoah: A Low-Pause-Time Garbage CollectorShenandoah: 一个低暂停时刻的废物搜集器
381:
Remove the Solaris and SPARC Ports删去 Solaris 和 SPARC 端口
383:
Foreign-Memory Access API (Second Incubator)外部内存拜访 API (第二个孵化器)
384:
Records (Second Preview)纪录(第2次预览)
385:
Deprecate RMI Activation for Removal不引荐激活 RMI 以便删去

8.1 Sealed Classes(密封类)

密封类(Sealed Classes)是JDK 15引进的一项重要特性,它是一种新的类和接口修饰符,用于操控类的承继联系。经过将类或接口声明为密封类,能够约束哪些类能够承继或完结该密封类 密封类的首要意图是供给更严厉的拜访操控,以保证承继层次结构的完好性和安全性。在运用密封类时,开发者能够明晰指定答应承继的类的范围,这样能够避免不受操控的扩展和承继。 要将一个类声明为密封类,需求运用sealed要害字进行修饰。例如:

sealed class Shape permits Circle, Square, Triangle {
    // Class body
}

在上面的比如中,Shape是一个密封类,它答应承继的类有CircleSquareTriangle。这意味着只要这三个类能够直接承继Shape,其他类无法承继它。假如其他类尝试承继Shape,编译器将报错。 经过运用密封类,能够有用地操控承继联系,并削减意外的扩展。这关于结构和库的规划十分有用,能够保证只要受信赖的类能够扩展或完结密封类。 此外,密封类与办法匹配(Pattern Matching)功用相结合,能够更便利地处理密封类的实例。办法匹配能够依据实例的类型进行匹配,并依据匹配的成果履行相应的操作,然后简化了类型查看和转化的代码。 总之,密封类是JDK 15引进的一项重要特性,它经过操控承继联系来供给更严厉的拜访操控和安全性。它能够协助开发者更好地规划类层次结构,并削减意外的扩展。

8.2 Text Blocks(文本块)

文本块(Text Blocks)是JDK 15引进的一项重要特性,它供给了一种更自然、更易读的多行字符串表明办法,以削减在代码中编写长字符串时的转义字符和格局化问题。

在传统的Java中,假如要编写一个包含多行文本的字符串,需求运用转义字符(例如\n)或衔接操作符(+)将多行字符串拼接在一同。这样的写法不只冗长而且难以阅览和维护。

运用文本块,能够更简练地表明多行字符串,而无需运用转义字符或衔接操作符。文本块运用三个引号(”””)将多行字符串包裹起来,并经过缩进来界说字符串的内容。例如:

String textBlock = """
    Hello,
    This is a multi-line
    text block.
    """;

在上面的比如中,textBlock是一个文本块,包含了三行文本。经过运用文本块,咱们能够直观地看到字符串的格局和结构,而无需担心转义字符和格局化问题。 文本块还支撑一些额定的特性,例如去除前导空格和跟随空格。能够运用~字符来指定文本块的缩进等级,然后操控文本块中的空格。

String indentedBlock = """
        This is an indented block
        with leading and trailing spaces.
        """.stripIndent();

在上面的比如中,stripIndent()办法会主动去除前导空格,生成一个不包含缩进的文本块。 文本块在许多场景中都十分有用,特别是在编写HTML、JSON、SQL或其他格局化字符串时。它供给了更明晰和易于维护的代码,进步了开发功率。 需求留意的是,文本块是在编译时进行处理的,并不会在运转时影响字符串方针的表明办法。因而,文本块并不改动字符串的根本性质和操作。

8.3 Hidden Classes(躲藏类)

躲藏类(Hidden Classes)是JDK 15引进的一项特性,它答应在运转时动态生成类,一起不会对程序的功用发生负面影响。躲藏类关于某些特定的运用场景十分有用,如动态署理、代码生成和Java虚拟机的完结。 躲藏类的首要意图是在不露出类的字节码的状况下,答应生成和运用类。这关于一些涉及敏感逻辑或需求动态生成和加载类的运用程序十分有用。 躲藏类的生成和运用是经过Java虚拟机的Lookup方针和MethodHandles API进行的。Lookup方针供给了对类的私有成员拜访的权限,并能够用于创立躲藏类。MethodHandles API供给了对办法句柄的操作和调用。 生成躲藏类的进程能够归纳为以下几个进程:

  1. 获取Lookup方针:经过反射或其他办法获取Lookup方针,该方针具有足够的权限来创立躲藏类。
  2. 界说类的结构:运用Lookup方针的defineHiddenClass()办法界说类的结构,包含类的称号、父类、接口等。
  3. 加载和链接类:运用Lookup方针的lookupClass()办法加载和链接躲藏类。
  4. 创立实例和调用办法:运用MethodHandles API和躲藏类的句柄来创立实例和调用办法。

躲藏类的首要优势在于,它们能够在运转时动态生成和加载,而无需事前编写和编译类的字节码。这关于某些场景,如完结动态署理、插件体系、代码生成和热部署等,供给了更大的灵敏性和扩展性。 需求留意的是,躲藏类是一项高档特性,一般在特定的运用程序结构和库中运用,而不是普通的运用程序开发中。运用躲藏类需求慎重,保证了解其作业原理和适用场景。

8.4 Records(记载类)

JDK 15对记载类进行了一些改善,首要包含:

  1. 扩展性结构函数(Extended Constructor):在JDK 15之前,记载类只要一个隐式的结构函数,它承受一切特色作为参数。在JDK 15中,记载类引进了扩展性结构函数,答应开发者自界说结构函数,一起保存隐式结构函数的功用。
  2. @Override支撑:在JDK 15之前,因为记载类的办法是由编译器主动生成的,因而无法运用@Override注解来符号掩盖父类办法。在JDK 15中,支撑在记载类办法上运用@Override注解,以便更好地表明其掩盖联系。

8.5 Pattern Matching for instanceof(instanceof的办法匹配)

JDK 15引进了一项重要的特性,即”Pattern Matching for instanceof”(instanceof的办法匹配)。这个特性经过简化对类型的查看和转化来进步代码的可读性和简练性。 在Java中,咱们一般运用instanceof运算符来查看方针是否归于某个特定类型。在JDK 15之前,这一般需求将查看经往后的方针强制转化为方针类型,以便在后续的代码中运用。这样的代码办法十分普遍。 而在JDK 15中,引进了办法匹配的功用,能够将instanceof与类型转化结合起来,以更简练的办法完结类型查看和转化。下面是一个运用办法匹配的示例:

if (obj instanceof String str) {
    System.out.println(str.length());
}

在上面的比如中,咱们运用instanceof运算符查看obj是否是String类型。假如是,那么咱们能够在条件块内部直接运用str作为String类型的方针,而且编译器会主动将其视为String类型。这样,咱们就能够直接调用str上的办法或拜访其特色,而无需进行额定的强制类型转化。 这种办法匹配的语法能够协助开发者更直接地处理类型查看和类型转化,并削减了样板代码的编写。它供给了更简练和易读的办法来处理杂乱的类型判别和转化逻辑。 需求留意的是,办法匹配的作用域仅限于条件块内部,超出该范围后,变量将不再被视为特定类型。

九 JDK16新特性

参阅网站:openjdk.org/projects/jd…


338:
Vector API (Incubator)矢量 API (孵化器)
347:
Enable C++14 Language Features启用 C + + 14言语特性
357:
Migrate from Mercurial to Git从 Mercurial 迁移到 Git
369:
Migrate to GitHub迁移到 GitHub
376:
ZGC: Concurrent Thread-Stack ProcessingZGC: 并发线程仓库处理
380:
Unix-Domain Socket ChannelsUnix 域套接字通道
386:
Alpine Linux Port高山 Linux 端口
387:
Elastic Metaspace弹性元空间
388:
Windows/AArch64 PortWindows/AArch64端口
389:
Foreign Linker API (Incubator)外部衔接器 API (孵化器)
390:
Warnings for Value-Based Classes依据值的类的正告
392:
Packaging Tool包装东西
393:
Foreign-Memory Access API (Third Incubator)外部内存拜访 API (第三孵化器)
394:
Pattern Matching for instanceof办法匹配
395:
Records记载
396:
Strongly Encapsulate JDK Internals by Default默许状况下强封装 JDK 内部
397:
Sealed Classes (Second Preview)密封类(第2次预览)

9.1 Foreign Function & Memory API(外部函数和内存 API)

Foreign Function & Memory API(外部函数和内存 API)是 JDK 16 中引进的一个特性,它供给了一种规范化的机制,用于与外部本机代码进行交互。该 API 旨在改善 Java 与本机代码集成的体会,并简化本机代码拜访和操作。 Foreign Function & Memory API 的首要组成部分包含以下内容:

  1. Foreign Linker API(外部链接器 API):该 API 供给了一组接口和类,用于声明和操作与本机函数的链接。经过 Foreign Linker API,能够界说本机函数的签名、拜访本机库中的函数,并在 Java 代码中调用本机函数。
  2. Foreign Memory Access API(外部内存拜访 API):该 API 答应直接拜访本机内存,以便在 Java 代码中高效地处理本机数据。经过 Foreign Memory Access API,能够分配本机内存、读写本机内存的值,并履行本机内存的开释操作。
  3. Foreign Memory Segment API(外部内存段 API):该 API 供给了对接连内存段的笼统,能够在 Java 代码中表明和操作本机内存块。它包含操作内存段的办法,如复制、填充、移动和比较等。

Foreign Function & Memory API 使得 Java 开发人员能够愈加灵敏地与本机代码进行交互,而且能够进步功用和降低与本机代码集成的杂乱性。它在与本机库、操作体系接口、硬件加速等方面有广泛的运用场景。 请留意,运用 Foreign Function & Memory API 需求慎重处理本机代码和内存的拜访,以保证安全性和安稳性。在运用该 API 时,主张参阅官方文档和示例,以便正确地运用和办理本机函数和内存。

9.2 Unix-Domain Socket Channel(Unix 域套接字通道)

Unix-Domain Socket Channel(Unix 域套接字通道)是 JDK 16 中引进的一个特性,它答应 Java 程序经过 Unix 域套接字进行本机进程间通讯(IPC)。 Unix 域套接字是一种在同一台机器上的进程之间进行通讯的机制,相似于网络套接字,但在内部运用文件体系途径作为通讯端点而不是 IP 地址和端口号。 Unix-Domain Socket Channel 供给了一种与本机 Unix 域套接字进行交互的规范化办法,使开发人员能够运用 Java 程序进行进程间通讯。运用 Unix-Domain Socket Channel,能够创立、绑定、衔接和进行读写操作等。 以下是运用 Unix-Domain Socket Channel 的一些要害操作:

  1. 创立 Unix-Domain Socket Channel:运用静态工厂办法 UnixDomainSocketAddress.of(String path) 创立一个 Unix 域套接字地址,并运用 UnixDomainSocketChannel.open() 创立一个 Unix-Domain Socket Channel。
  2. 绑定和衔接:经过调用 bind(UnixDomainSocketAddress address) 办法绑定 Unix-Domain Socket Channel 到指定的地址,或运用 connect(UnixDomainSocketAddress address) 办法衔接到远程地址。
  3. 读写操作:能够运用 read(ByteBuffer dst)write(ByteBuffer src) 办法进行读取和写入操作,读写的数据将在本机套接字通道和对应的本机进程之间传输。
  4. 封闭通道:经过调用 close() 办法封闭 Unix-Domain Socket Channel,开释相关的资源。

Unix-Domain Socket Channel 供给了一种在 Java 中进行本机进程间通讯的高档机制,特别适用于需求高功用、低推迟和安全性的运用场景,如进程间协作、服务器和客户端通讯等。 请留意,Unix-Domain Socket Channel 只能在支撑 Unix 域套接字的操作体系上运用,如 Linux、Unix 和 macOS 等。

9.3 Vector API(向量 API)

Vector API(向量 API)是 JDK 16 中引进的一个特性,它供给了一组类和接口,用于在 Java 中履行数据并行核算和矢量化操作。经过运用向量 API,开发人员能够更高效地运用现代硬件的矢量化指令集履行并行核算。 以下是 Vector API 的一些要害特性和概念:

  1. 向量化数据类型:向量 API 引进了一组新的数据类型,如 Vector128、Vector256 等,用于表明向量化数据。这些数据类型能够存储和操作多个数据元素,并运用硬件的矢量化指令集进行并行核算。
  2. 向量操作办法:向量 API 供给了一组用于履行向量操作的办法,如加法、减法、乘法、除法、逐元素操作等。这些办法能够在向量数据类型上进行操作,并主动运用底层硬件的矢量化指令集进行并行核算。
  3. 向量掩码:向量 API 引进了一种向量掩码的概念,用于挑选性地运用向量操作。经过指定一个掩码,能够对向量数据的部分元素进行操作,而不影响其他元素。这样能够更灵敏地处理不规矩数据集和条件操作。
  4. 并行迭代:向量 API 支撑并行迭代操作,答应开发人员以向量化的办法处理数组和数据集。经过供给迭代器和并行流等机制,能够高效地在多个向量数据上履行操作。
  5. 与现有 API 集成:向量 API 与现有的 Java API 集成良好,能够与 Stream API、并行流、并发调集等其他并行核算机制一同运用。这样能够在现有代码中无缝地参加向量化操作,进步功用和并行度。

向量 API 的方针是供给一种简略、直观的办法来运用硬件的矢量化指令集进行数据并行核算。它能够在各种场景中发挥作用,如科学核算、图画处理、机器学习等需求大量数据操作和并行核算的领域。

9.4 Alpine Linux 支撑

在 JDK 16 中,引进了对 Alpine Linux 的官方支撑。Alpine Linux 是一个轻量级的 Linux 发行版,首要用于容器化运用程序。经过在 JDK 16 中增加对 Alpine Linux 的支撑,Java 开发人员能够更便利地在 Alpine Linux 上部署和运转他们的 Java 运用。 Alpine Linux 的特色是具有极小的镜像巨细、简化的软件包办理和依据 musl libc 的轻量级 C 库。它专心于供给一个细巧、高度可定制和安全的根底操作体系环境。 在 JDK 16 中,经过增加对 musl libc 的支撑,Java 程序能够直接在 Alpine Linux 上运转,而无需依靠传统的 glibc(GNU C Library)。这使得 Java 运用程序能够在更小的容器镜像中运转,而且能够更快地发动和部署。 Alpine Linux 支撑对 Java 开发人员来说是一个好音讯,特别是在容器化和云原生运用程序的场景下。它供给了更轻量级的根底操作体系挑选,而且与 JDK 16 一同运用,能够供给更高的灵敏性和功用。 需求留意的是,虽然 JDK 16 供给了对 Alpine Linux 的官方支撑,但依然需求遵从最佳实践和恰当的装备,以保证在 Alpine Linux 上的 Java 运用程序的正常运转。

十 JDK17 新特性

参阅网站:openjdk.org/projects/jd…


306:
Restore Always-Strict Floating-Point Semantics恢复一直严厉的浮点语义
356:
Enhanced Pseudo-Random Number Generators增强型伪随机数发生器
382:
New macOS Rendering Pipeline新的 macOS 渲染管道
391:
macOS/AArch64 PortMacOS/AArch64端口
398:
Deprecate the Applet API for Removal抛弃 Applet API 以便删去
403:
Strongly Encapsulate JDK Internals强封装 JDK 内部结构
406:
Pattern Matching for switch (Preview)开关办法匹配(预览)
407:
Remove RMI Activation删去 RMI 激活
409:
Sealed Classes密封类
410:
Remove the Experimental AOT and JIT Compiler删去试验性 AOT 和 JIT 编译器
411:
Deprecate the Security Manager for Removal撤销安全办理器以便删去
412:
Foreign Function & Memory API (Incubator)外部函数和内存 API (孵化器)
414:
Vector API (Second Incubator)矢量 API (第二个孵化器)
415:
Context-Specific Deserialization Filters特定于上下文的反序列化过滤器
JDK 17 will be a long-term support (LTS) release from most vendors. For a complete list of the JEPs integrated since the previous LTS release, JDK 11, please see here.
JDK 17将是来自大多数供货商的长时刻支撑(LTS)版别。有关自上一个 LTS 版别 JDK 11以来集成的 JEP 的完好列表,请参阅这儿。

10.1 Context-Specific Deserialization Filters(上下文特定的反序列化过滤器)

Context-Specific Deserialization Filters(上下文特定的反序列化过滤器)是 JDK 17 中引进的一个特性,用于增强 Java 运用程序对反序列化进程的操控和安全性。 在 Java 中,反序列化是将方针从字节序列还原为内存中的方针的进程。但是,反序列化操作或许存在安全危险,因为恶意序列化数据能够触发未经授权的代码履行或方针创立。 Context-Specific Deserialization Filters 答应开发人员界说特定于上下文的反序列化过滤器,以约束哪些类能够被反序列化。开发人员能够在特定的上下文中设置反序列化过滤器,例如在运用程序的安全办理器中、在 RMI 远程调用中、在方针输入流的特定实例上等。 经过界说上下文特定的反序列化过滤器,开发人员能够完结以下方针:

  1. 类过滤:能够界说白名单或黑名单,只答应或制止特定的类进行反序列化。这有助于约束潜在的安全危险和不受信赖的类的反序列化。
  2. 内容查看:能够对反序列化的方针进行更严厉的验证和查看,以保证数据的完好性和合法性。
  3. 安全战略施行:能够经过上下文特定的反序列化过滤器施行特定的安全战略,以满意运用程序的需求和要求。

经过运用 Context-Specific Deserialization Filters,开发人员能够在反序列化进程中更细粒度地操控和验证方针的创立和内容。这有助于进步运用程序的安全性,削减潜在的安全漏洞和攻击面。

10.2 Strong encapsulation of JDK internals(JDK 内部模块的强封装)

Strong encapsulation of JDK internals(JDK 内部模块的强封装)是 JDK 17 中引进的一个特性,旨在进一步约束和封装 JDK 内部模块的拜访。 在 Java 9 中,引进了模块体系(Module System),经过将 JDK 分为一组模块来供给更严厉的拜访操控和模块化。但是,在较早版其他 JDK 中,某些 JDK 内部模块的拜访等级依然比较宽松,或许会导致潜在的不安全和不安稳的代码依靠联系。 JDK 17 引进了 Strong encapsulation 特性,经过进一步约束和封装 JDK 内部模块的拜访,以进步体系的安全性和安稳性。详细来说,它包含以下方面:

  1. JDK 内部 API 的强封装:许多 JDK 内部 API 在 JDK 17 中被符号为强封装,不再公开为公共 API。这些 API 的拜访等级被约束在 JDK 内部,开发人员不该直接拜访或依靠这些 API。
  2. 模块的强封装:JDK 17 强化了一些 JDK 内部模块的封装,以避免外部模块直接拜访这些内部模块。这增加了对 JDK 内部完结细节的维护,降低了对内部模块的直接依靠。

经过强封装 JDK 内部模块,能够削减对不安稳的和非正式的 API 的依靠,并进步运用程序的牢靠性和可移植性。这也促进开发人员运用公共和安稳的 API,以保证运用程序在不同版其他 JDK 上的兼容性。 需求留意的是,在运用 JDK 17 时,假如运用程序依靠于 JDK 内部的 API 或模块,或许会遭到这种强封装的影响。

10.3 Sealed JNI(密封 JNI)

Sealed JNI(密封 JNI)是 JDK 17 中引进的一个特性,旨在约束本机接口(JNI)的完结,以进步本机代码的安全性。 JNI 是 Java Native Interface 的缩写,它答应 Java 程序与本机代码进行交互。经过 JNI,Java 程序能够调用本机库中的函数,也能够从本机代码中调用 Java 办法。但是,JNI 也带来了一些安全危险,因为不受信赖的本机代码或许会拜访和修正 Java 程序的内部状况。 Sealed JNI 引进了密封 JNI 的概念,经过约束本机接口的完结来进步本机代码的安全性。详细来说,Sealed JNI 能够经过以下办法完结:

  1. 密封本机接口库:开发人员能够将本机接口库符号为密封(sealed),以约束它的完结。密封本机接口库只能在特定的上下文中运用,例如指定的模块、类加载器或其他条件。
  2. 安全战略的强制履行:经过密封 JNI,能够强制履行安全战略,只答应受信赖的本机接口库进行调用。这能够削减潜在的恶意或不安全的本机代码对 Java 程序的影响。

Sealed JNI 的方针是进步本机代码的安全性,并削减与不受信赖的本机代码相关的潜在危险。开发人员能够运用密封 JNI 来约束本机接口库的运用范围,并保证只要受信赖的代码能够调用本机办法。

10.4 改善的废物搜集器

在 JDK 17 中,进行了一些改善和优化,以供给更好的废物搜集器功用和安稳性。以下是一些与废物搜集器相关的改善:

  1. ZGC:ZGC 是一种低推迟的废物搜集器,旨在削减运用程序的中止时刻。在 JDK 17 中,ZGC 进行了一些改善,包含改善的内存分配、增强的并发处理和更好的功用。
  2. Shenandoah GC:Shenandoah GC 是另一种低推迟的废物搜集器,适用于大内存堆的运用程序。在 JDK 17 中,Shenandoah GC 进行了一些改善,包含更好的废物搜集算法、并发处理和功用优化。
  3. G1 GC 改善:G1(Garbage-First)是一种面向大堆和低中止的废物搜集器。在 JDK 17 中,对 G1 GC 进行了一些改善,包含功用优化、内存分配改善和更好的并发处理。
  4. 废物搜集器接口:JDK 17 引进了一组新的废物搜集器接口,答应开发人员完结自界说的废物搜集器。这样,开发人员能够依据自己的需求和场景开发定制的废物搜集器。

这些改善和优化旨在供给更好的废物搜集器功用、降低中止时刻,并进步大堆和低推迟运用程序的吞吐量。详细的改善和优化细节能够在 JDK 17 的发行阐明和相关文档中找到。