---
# System prepended metadata

title: Java 8 - 17 jeps 重點整理
tags: [Java, java17]

---

# Java 8 - 17 jeps 重點整理
![](https://hackmd.io/_uploads/S114V7wEn.png)


## Java 17 簡介
原本Java是採用每六個月就是出新的短期版本，且一釋出，就會停止更新上一版本，而這次Java推出了 17是Java平台的最新的LTS的長期版本，它於2021年9月14日發布，距離上一個LTS的版本Java 11間隔3年，不斷從其他語言吸取經驗並與自身既有的語法、規範作結合。Java 17包含了許多新的功能和改進，旨在提高Java開發人員的生產力和性能，主要有兩大類型，一是簡化語法提升效能，二是影響設計風格的語法。以下是Java 17中一些重要的新功能和改進：

1. Sealed Classes和Interfaces：限制誰可以繼承或實現類或接口。
2. pattern matching for instanceof：簡潔的代碼，讓程式更容易閱讀和理解。
3. Switch表達式的增強：使用更多的類型替換傳統的switch語句。
4. JFR(Java Flight Recorde)事件流：Java 14及登場，於Java17增強，可以用來診斷和分析應用程式，想深入了解可以看[這裡](https://access.redhat.com/documentation/zh-tw/openjdk/17/html/using_jdk_flight_recorder_with_openjdk/starting-jdk-flight-recorder)。
5. 垃圾回收器的改進：改進G1收集器和ZGC收集器的性能和效率。
6. 非對稱加密算法：Java 17包括了一些新的非對稱加密算法，如X25519和Ed25519，以提供更強大的安全性。
7. 增強的Packing和Unpacking：提供更簡單、更有效的方法，用於將Java對象序列化和反序列化為二進製數據。


## 版本相容
Spring最為重要，其Spring 6與Spring Boot 3，至少要基於Java 17，而Spring 5.3.x及Spring Boot 2.x，則有相容於Java 17的版本，[詳見此](https://spring.io/blog/2021/09/02/a-java-17-and-jakarta-ee-9-baseline-for-spring-framework-6)。

Hibernate則直接宣告:[「All system go for java 17」](https://in.relation.to/2021/09/14/ready-for-jdk17/)

## 版本選用

基本上使用LTS的版本最好，就是8、11、17，這三個版本間所發行的版本，以官方的觀點來說，算是小版本更新而已。


## java 8 後各版本重點新特性(僅選重點，非齊全)

### java 8

#### JEP 126 - Lambda

- 簡介
    - Lambda 是指在 java 中，可以使用`->`來建立匿名方法，讓程式碼更加簡潔。
- 使用情境
  - 當我們需要建立匿名方法時，就可以使用 Lambda。
- 範例
    - 在還沒有 Lambda 的時候，我們建立匿名方法時，必須使用`new`來建立匿名類別，例如：

    ```java
    public class LambdaTest {
        public static void main(String[] args) {
            // 1. 建立匿名類別
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println("Hello World");
                }
            };
            // 2. 執行匿名類別
            runnable.run();
        }
    }
    ```

    - 在有了 Lambda 的時候，我們建立匿名方法時，可以使用`->`來建立匿名方法，例如：

    ```java
    public class LambdaTest {
        public static void main(String[] args) {
            // 1. 建立匿名方法
            Runnable runnable = () -> System.out.println("Hello World");
            // 2. 執行匿名方法
            runnable.run();
        }
    }
    ```
* Lambda還很強大，這邊講不完，所以
![](https://hackmd.io/_uploads/rkfLeYv4h.png)

#### JEP 107 - Stream

- 簡介
    - `Stream`可以用來處理集合，它是一種操作序列元素的方式。它讓開發者可以以更簡潔、更有彈性的方式處理集合類型的資料。Java Stream 可以大大簡化開發者的程式碼，並且增加了可讀性和可維護性。
- 使用情境
  - 當集合需要進行運算、過濾、轉換等操作時。
- 範例
    - 在還沒有 Stream 的時候，我們處理集合時，必須使用`for`迴圈來處理集合，例如：

    ```java
    public class StreamTest {
        public static void main(String[] args) {
            // 1. 建立集合
            List<String> names = Arrays.asList("John", "Tom", "Jane");
            // 2. 處理集合
            for (String name : names) {
                System.out.println(name);
            }
        }
    }
    ```

    - 在有了 Stream 的時候，我們處理集合時，可以使用`Stream`來處理集合，例如：

    ```java
    public class StreamTest {
        public static void main(String[] args) {
            // 1. 建立集合
            List<String> names = Arrays.asList("John", "Tom", "Jane");
            // 2. 處理集合
            names.stream().forEach(System.out::println);
        }
    }
    ```
* Stream的內容也還有很多，所以
![](https://hackmd.io/_uploads/r1uqgKwEh.png)


#### JEP 129 - Optional

- 簡介
    - `Optional`是一種可以容納null或非null值的容器類型，它可以幫助開發人員更優雅地處理null值，並提供更清晰、更容易閱讀的代碼。
- Optional 使用情境
  - 當需要對一個可能為null的物件進行操作時，可以使用Optional包裝該物件，並使用Optional的一些方法來處理null值。
- 在還沒有 Optional 的時候，我們處理空值時，必須使用`if`判斷式來處理空值，例如：
```java
public class OptionalTest {
    public static void main(String[] args) {
        // 1. 建立空值
        String name = null;
        // 2. 處理空值
        if (name != null) {
            System.out.println(name);
        }
    }
}
```

- 在有了 Optional 的時候，我們處理空值時，可以使用`Optional`來處理空值，例如：

```java
public class OptionalTest {
    public static void main(String[] args) {
        // 1. 建立空值
        String name = null;
        // 2. 處理空值
        Optional.ofNullable(name).ifPresent(System.out::println);
    }
}
```
- option的內容也還有很多，可以看[這邊](https://hackmd.io/YitwxGAvT0atTU1VqRA-Gg?view)

#### JEP 150 - Date Time API

- 簡介
    - Java Date Time API是Java 8中引入的一個日期和時間處理API，提供了更好的日期和時間處理方式，包括新的日期時間類型、時間區間、時區處理等功能。
- 使用情境
  - Java Date Time API可以應用於所有需要處理日期和時間的場景，包括但不限於：
    - 日期和時間的格式化和解析
    - 時間計算和差異
    - 不同時區之間的時間轉換
    - 定期事件和時間表達式的處理
- 範例
    - 在還沒有 Date Time API 的時候，我們處理日期時間時，必須使用`Calendar`來處理日期時間，例如：

    ```java
    public class DateTimeAPITest {
        public static void main(String[] args) {
            // 1. 建立日期時間
            Calendar calendar = Calendar.getInstance();
            calendar.set(2021, Calendar.JANUARY, 1);
            // 2. 處理日期時間
            System.out.println(calendar.getTime());
        }
    }
    ```

    - 在有了 Date Time API 的時候，我們這以這樣改寫
    ```java
    public class DateTimeAPITest {
        public static void main(String[] args) {
            // 1. 建立日期時間
            LocalDate localDate = LocalDate.of(2021, Month.JANUARY, 1);
            // 2. 處理日期時間
            System.out.println(localDate);
        }
    }
    ```
    - 再提供一些 Date Time API 的範例
    ```java
    // 創建日期
    LocalDate date = LocalDate.of(2022, 5, 15);
    // 創建時間
    LocalTime time = LocalTime.of(14, 30);
    // 合併日期和時間
    LocalDateTime dateTime = LocalDateTime.of(date, time);
    // 轉換為另一個時區的時間
    ZonedDateTime zonedDateTime = dateTime.atZone(ZoneId.of("Asia/Tokyo"));
    // 格式化時間
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");
    String formattedDateTime = zonedDateTime.format(formatter);
    System.out.println(formattedDateTime); // 輸出：2022-05-15 13:30:00 JST
    ```
- Date Time API的LocalDateTime與ZonedDateTime在時間的處理上，真的很香，很值得使用，所以
    ![](https://hackmd.io/_uploads/BJoA-KuV2.png)


#### JEP 135 - Base64

- 簡介
    - Base64是一種用於將二進位數據編碼為ASCII字符集的編碼方式，並且可以將編碼後的數據解碼為原始二進位數據。Base64提供了方便的API來執行這些操作。在 java 8 之前，我們要將字串轉換成 Base64，必須使用第三方套件，例如：Apache Commons Codec。
- 使用情境
    - Base64通常用於在不同的系統之間傳輸二進制數據，例如在網絡上傳輸數據。Java的Base64 API可以幫助開發人員編碼和解碼數據，並且可以將編碼後的數據作為字符串傳輸。
- 範例

    - 在 java 8 之後，我們可以使用`Base64`來將字串轉換成 Base64
    ```java
    public class Base64Example {
        public static void main(String[] args) {
            // 定義要編碼的字串
            String originalString = "This is a string to be encoded.";

            // 編碼字串
            String encodedString = Base64.getEncoder().encodeToString(originalString.getBytes());
            System.out.println("Encoded String: " + encodedString);

            // 解碼字串
            byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
            String decodedString = new String(decodedBytes);
            System.out.println("Decoded String: " + decodedString);
        }
    }
    ```

#### JEP 106 - Static Methods in Interfaces
#### JEP 126 - Default Methods for Interfaces
#### JEP 155 - Concurrency Enhancements
#### JEP 203 - IO Enhancements
#### JEP 118 - Type and Repeating Annotations
#### JEP 103 - Parallel Array Sorting

### java 9

#### JEP 110 - HTTP 2 Client
#### JEP 102 - Process API Improvement
#### JEP 213 - Diamond Operator for Anonymous Inner Class
#### JEP 213 - Private Methods in Interfaces
#### JEP 222 - JShell
#### JEP 266 - Reactive Streams
#### JEP 264 - Platform Logging API and Service

### java 10

#### JEP 286 - Local Variable Type Inference
- 簡介
    - Local Variable Type Inference（區域變數類型推斷）此特性，Java允許聲明區域變數時省略類型，而是讓編譯器通過變量初始化的表達式推斷類型。
- 使用情境
    - Local Variable Type Inference可以在幾個方面提高Java的可讀性和簡潔性，特別是在以下情況下：
        1. 當變量類型明顯時，例如使用匿名類和Lambda表達式時。
        2. 當變量類型比較冗長，例如使用泛型時。
        3. 當聲明複雜的類型或帶有泛型的集合時。
- 範例
    - 還未有這個功能前的宣告方式如下

    ```java
    public class LocalVariableTypeInferenceTest {
        public static void main(String[] args) {
            // 1. 宣告變數時，必須指定型別
            ArrayList<String> list = new ArrayList<>();
            String str = "Hello World!";
            HashMap<Integer, String> map = new HashMap<>();
        }
    }
    ```

    - 在有了 Local Variable Type Inference 後，我們宣告變數時，不需要指定型別，例如：

    ```java
    public class LocalVariableTypeInferenceTest {
        public static void main(String[] args) {
            // 1. 宣告變數時，不需要指定型別
            var list = new ArrayList<String>();  //聲明ArrayList<String>的變量
            var str = "Hello World!";            //聲明String的變量
            var map = new HashMap<Integer, String>();  //聲明HashMap<Integer, String>的變量
        }
    }
    ```

#### JEP 307 - Parallel Full GC for G1
#### JEP 310 - Application Class-Data Sharing
#### JEP 317 - Experimental Java-Based JIT Compiler

### java 11

#### JEP 321 - HTTP Client (Standard)
- 簡介
    - 提供了一個簡單的HTTP客戶端API，用於向HTTP服務器發送請求和接收響應。HTTP Client API提供了更現代和靈活的方法，以替換過時的HttpURLConnection API。
- 使用情境
  - Java HTTP Client API可以用於訪問Web服務器，以獲取或發送數據。
- 範例

    ```java
    public class HttpClientTest {
        public static void main(String[] args) throws IOException, InterruptedException {
            // 1. 建立HttpClient
            HttpClient httpClient = HttpClient.newHttpClient();

            // 2. 建立HttpRequest
            HttpRequest httpRequest = HttpRequest.newBuilder()
                    .uri(URI.create("https://www.google.com"))
                    .build();

            // 3. 建立HttpResponse
            HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());

            // 4. 取得狀態碼
            System.out.println(httpResponse.statusCode());

            // 5. 取得內容
            System.out.println(response.body());
        }
    }
    ```


#### JEP 320 - Remove the Java EE and CORBA Modules
#### JEP 328 - Flight Recorder
#### JEP 318 - Epsilon: A No-Op Garbage Collector
#### JEP 331 - Low-Overhead Heap Profiling
#### JEP 309 - Dynamic Class-File Constants
#### JEP 181 - Nest-Based Access Control

### java 12

#### JEP 189 - Shenandoah: A Low-Pause-Time Garbage Collector (Experimental)

#### JEP 325 - Switch Expressions 
- [見 java 14](#java-14)

#### JEP 372 - Compact Number Formatting

#### JEP 362 - Teeing Collectors

#### New Methods in String Class 
- 簡介
    - String 類別中新增了幾個方法，讓 String 處理更加方便。這些方法包括：indent、transform、describeConstable 和 resolveConstantDesc。其中，indent 和 transform 方法是最受歡迎的方法，它們允許使用更少的代碼來進行字符串操作，並且支持函數式編程風格。
- 使用情境
    - 新的方法在多個場景下都可以使用。
        - indent 可以將字符串縮進指定的空格數量，可以用於格式化文本；
        - transform 可以將字符串轉換為新的字符串，可以用於簡化字串操作代碼。
        - describeConstable 和 resolveConstantDesc 方法則與 Java 12 引入的 Switch 表達式有關，用於提供常量表達式的描述和解析功能。
- 範例
    ```java
    // indent方法示例
    String text = "Hello\nworld";
    String indented = text.indent(4);
    System.out.println(indented);
    // 輸出:
    //     Hello
    //     world

    // transform方法示例
    String str = "hello";
    String transformed = str.transform(s -> s + " world");
    System.out.println(transformed);
    // 輸出:
    //     hello world

    // describeConstable和resolveConstantDesc方法示例
    public enum Color {
        RED, GREEN, BLUE;
        public String describeConstable() {
            return name();
        }
        public Optional<Color> resolveConstantDesc(Constable desc) {
            return Optional.of(desc)
                .filter(c -> c instanceof Color)
                .map(c -> (Color) c);
        }
    }

    String input = "BLUE";
    Color color = Enum.valueOf(Color.class, input);
    System.out.println(color); // BLUE
    ```
#### JEP 334 - JVM Constants API

#### JEP 341 - Default CDS Archives
- 簡介
    - JDK 14中引入了Default CDS Archives功能，它允許使用者在JDK安裝時生成Class Data Sharing(CDS)檔案。CDS檔案是一個存儲Java類元數據的預編譯二進制文件，以加快JVM啟動速度。
- 使用情境
    - 使用者可以使用Default CDS Archives在JDK安裝時生成CDS檔案，而不需要手動執行JVM啟動器來生成CDS檔案。這樣可以提高JVM啟動速度，尤其是對於大型應用程序和多模塊應用程序而言，效果更為顯著。

#### JEP 346 - Promptly Return Unused Committed Memory from G1
- 簡介
    - JEP 346是Java中一個重要的性能優化功能，目的是釋放G1 GC中未使用的已分配內存，並在應用程序需要時迅速返回可用內存，提高內存的利用率和應用程序的性能。
- 使用情境
    - 當Java應用程序中的某些區域佔用的內存已被回收但未返回給操作系統時，它會導致Java虛擬機佔用更多內存，從而影響應用程序的性能。JEP 346的目的是將未使用的已分配內存迅速返回操作系統，以提高內存的利用率和應用程序的性能。
### java 13

#### JEP 355 - Text Blocks (Preview)

- [見 java 15](#java-15)

#### JEP 354 - Switch Expressions (Standard)

- [見 java 14](#java-14)

#### JEP 350 - Dynamic CDS Archives

#### JEP 351 - ZGC: Uncommit Unused Memory
- 簡介：
    - Java的Z Garbage Collector (ZGC)是一個可擴展的低延遲的垃圾收集器，旨在提供極低的停頓時間和可預測的性能。JEP 351介紹了ZGC的一項新功能，即可以不用停止應用程序就能釋放未使用的堆內存。
- 使用情境：
    - 當Java應用程序需要處理大量內存並且需要維持極低的延遲時間時，ZGC是一個不錯的選擇。JEP 351所引入的功能使ZGC在釋放未使用的堆內存方面更加高效，這將進一步提高應用程序的性能。
- 範例：
    - 以下是一個簡單的Java程式碼示例，它展示了如何使用JEP 351中引入的新功能來釋放未使用的內存：
    ```java

    public class ZGCUncommitMemoryExample {
        public static void main(String[] args) {
            List<ByteBuffer> buffers = new ArrayList<>();

            for (int i = 0; i < 100; i++) {
                ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024 * 10);
                buffers.add(buffer);
            }

            // 釋放前50個buffer的內存
            for (int i = 0; i < 50; i++) {
                buffers.get(i).cleaner().clean();
            }

            // 釋放未使用的內存
            System.gc();

            // 確認內存釋放後已經無法訪問前50個buffer
            for (int i = 0; i < 50; i++) {
                try {
                    buffers.get(i).put((byte) 1);
                } catch (Exception e) {
                    System.out.println("Unable to access buffer " + i + ": " + e.getMessage());
                }
            }
        }
    }
    ```

#### JEP 353 - Reimplement the Legacy Socket API

### java 14

#### JEP 361 - Switch Expressions (Preview)
- 簡介
    - Switch Expressions 是 Java SE 12 新增的功能之一，允許在 switch 中使用表達式而不是陳述句。JEP 361 引入了進一步的改進，包括：允許使用傳統的 colon 分隔符號以及簡化的箭頭語法、對 switch 節點的完整支援等。
- 使用情境
    - Switch Expressions 可以讓程式碼更加簡潔易讀，特別是在需要判斷較多條件的情況下。例如在處理字串或者枚舉類型的時候，可以用 Switch Expressions 取代傳統的 switch 語句。
- 範例
    - 以下是一個使用傳統 switch 語句的範例，該語句的作用是根據給定的星期幾顯示相應的英文名稱：
    ```java
    public static void displayDayOfWeek(int day) {
        switch (day) {
            case 1:
                System.out.println("Monday");
                break;
            case 2:
                System.out.println("Tuesday");
                break;
            case 3:
                System.out.println("Wednesday");
                break;
            case 4:
                System.out.println("Thursday");
                break;
            case 5:
                System.out.println("Friday");
                break;
            case 6:
                System.out.println("Saturday");
                break;
            case 7:
                System.out.println("Sunday");
                break;
            default:
                System.out.println("Invalid day");
                break;
        }
    }
    ```
    - 使用 Switch Expressions 可以簡化上述代碼，例如：
    ```java
    public static void displayDayOfWeek(int day) {
        String dayName = switch (day) {
            case 1 -> "Monday";
            case 2 -> "Tuesday";
            case 3 -> "Wednesday";
            case 4 -> "Thursday";
            case 5 -> "Friday";
            case 6 -> "Saturday";
            case 7 -> "Sunday";
            default -> "Invalid day";
        };
        System.out.println(dayName);
    }
    ```

#### JEP 305 - Pattern Matching for instanceof (Preview)

- [見 java 16](#java-16)

#### JEP 358 - Helpful NullPointerExceptions

- 簡介：
    - JEP 358 是 Java Enhancement Proposal 的縮寫，是 Java 官方提出的一個改進 Java 語言的功能的提案。這個提案的目標是改進 Java 語言在處理空指針異常時給出的錯誤信息，使得開發者能夠更容易地定位和修復這些錯誤。

- 使用情境：
    - Java 中的空指針異常是一個常見的錯誤，而且對於開發者來說也很難 debug。通常 Java 的空指針異常會在一個方法調用出現錯誤時抛出，但是這個錯誤信息中並沒有明確指出哪個對象是空指針。這就使得開發者在修復這個錯誤時需要花費更多的時間去定位問題所在。而 JEP 358 的目標就是讓錯誤信息更加明確，幫助開發者更快地定位和修復空指針異常。

- 範例：
    - 在 JEP 358 之前，當一個空指針異常被拋出時，通常會得到一個類似這樣的錯誤信息：

    ```console
    Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:23)
        at com.example.myproject.Author.getBookTitles(Author.java:25)
        at com.example.myproject.Promotion.getCelebrityBooks(Promotion.java:123)
        at com.example.myproject.Promotion.launch(Promotion.java:63)
        at com.example.myproject.Main.main(Main.java:32)
    ```
    - 在這個錯誤信息中，我們可以看到出錯的類和方法，但是卻無法看到哪個對象是空指針。而在 JEP 358 中，錯誤信息會變得更加明確，例如：
    ```console
    Exception in thread "main" java.lang.NullPointerException: cannot invoke "String.length()" because "str" is null
        at com.example.myproject.Book.getTitle(Book.java:23)
        at com.example.myproject.Author.getBookTitles(Author.java:25)
        at com.example.myproject.Promotion.getCelebrityBooks(Promotion.java:123)
        at com.example.myproject.Promotion.launch(Promotion.java:63)
        at com.example.myproject.Main.main(Main.java:32)
    ```
    - 在這個錯誤信息中，我們可以看到 "str" 是一個空指針，並且因此不能調用 "String.length()" 方法。這讓開發者更容易定位問題所在，從而修復問題。

#### JEP 359 - Records (Preview)

- [見 java 16](#java-16)

#### JEP 368 - Text Blocks (Second Preview)

- [見 java 15](#java-15)

#### JEP 343 - Packaging Tool (Incubator) 

- [見 java 16](#java-16)

#### JEP 364 - ZGC on macOS

- 簡介
    - JEP 364 是 Java Enhancement Proposal 的縮寫，提供了ZGC（Z Garbage Collector）在 macOS 上的原生支援。ZGC是一種低延遲的垃圾回收器，具有在大量內存應用程序上優秀的表現和穩定性。

- 使用情境
    - macOS用戶可以使用ZGC來優化Java應用程序的效能和穩定性，尤其是在處理具有高內存需求的應用時，例如大型資料庫和遊戲。

#### JEP 345 - NUMA-Aware Memory Allocation for G1

#### JEP 363 - Remove the Concurrent Mark Sweep (CMS) Garbage Collector

### java 15

#### JEP 360 - Sealed Classes (Preview)

- [見 java 17](#java-17)

#### JEP 371 - Hidden Classes

- 簡介
    - Hidden Classes 是一種新的類別類型，可以在類別初始化之後，將其隱藏起來。這意味著只有它的創建者能夠訪問這個類別，而其他的類別和程式碼則無法訪問它。因為它有不可發現、訪問控制以及較短的生命週期特性，所以它可以用於實現某些安全性、性能和可維護性方面的需求。
- 使用情境
    - Hidden Classes 可以用於需要創建類別的環境，而這些類別將被用於一個較小的模塊內，而不是整個應用程式中。這種情況下，使用 Hidden Classes 可以讓程式碼更加安全、可維護和易於管理。Hidden Classes 也可以用於維護緩存或代理物件等方案。
- 範例
    - 下面是一個使用 Hidden Classes 的簡單範例：
    ```java
    public class HiddenClassDemo {
        public static void main(String[] args) throws Throwable {
            MethodHandles.Lookup lookup = MethodHandles.lookup();
            Class<?> hiddenClass = lookup.defineHiddenClass(new byte[0], true, MethodHandles.Lookup.ClassOption.NESTMATE);
            Object obj = hiddenClass.getDeclaredConstructor().newInstance();
            System.out.println(obj.getClass());
        }
    }
    ```
    - 這個範例中，我們使用 MethodHandles.Lookup 類別定義一個 Hidden Class，然後創建一個該類別的物件。最後，我們輸出這個物件的類別，可以看到它是一個隱藏的類別。

    - 關於和 Reflection 的比較，Reflection 可以在執行時獲取類別的訊息和方法，但是它不支援隱藏類別。Hidden Classes 能夠實現更高的安全性和可維護性，而 Reflection 則更適合於動態創建和操作物件。在一些情況下，Hidden Classes 可以取代 Reflection 來實現某些目的。

#### JEP 378 - Text Blocks (Second Preview)


- 簡介
    - Text Blocks 是 Java SE 15 引入的新特性，讓開發者能夠更輕鬆地在 Java 程式碼中嵌入多行長字串。這項功能在 JEP 378 中進行了第二次預覽，並已於 Java SE 17 正式發佈。它可以讓我們在字串中，使用換行符號，而不需要使用`\n`。

- 使用情境
    - Text Blocks 可以方便地處理多行長字串，特別是在 SQL 語句中。傳統上，開發者必須手動處理轉義符號和換行符號，這會導致代碼難以閱讀和維護。但是，使用 Text Blocks 可以使 SQL 語句的代碼更加清晰和簡潔。

- 範例

    - 傳統方式下的 SQL 字串：
    ```java
    String sql = "SELECT first_name, last_name, email FROM customers WHERE age > 18 AND city = 'New York'";
    ```
    - 使用 Text Blocks 的方式下的 SQL 字串：
    ```java
    String sql = """
                SELECT first_name, last_name, email 
                FROM customers 
                WHERE age > 18 
                AND city = 'New York'
                """;
    ```
    - 可以看到，使用 Text Blocks 可以直接在 Java 程式碼中嵌入多行長字串，不需要再手動處理轉義符號和換行符號，更方便閱讀和維護。

#### JEP 384 - Records (Second Preview)

- [見 java 16](#java-16)

#### JEP 339 - Edwards-Curve Digital Signature Algorithm (EdDSA)
- 簡介
    - Edwards-Curve Digital Signature Algorithm (EdDSA) 是一種公鑰加密技術，其基礎原理是基於橢圓曲線數學理論，可以用來實現數據加密和數字簽名等安全功能。JEP 339 旨在將 EdDSA 加入到 Java 平台中，讓 Java 開發人員能夠在自己的應用程序中使用這種加密算法。與JDK中已存在的簽名方案相比，EdDA有更高的安全性及效能，且在OpenSSL和BoringSSL等加密庫中已經得到支持。

- 使用情境
    - EdDSA 算法可用於數據加密、數字簽名、身份驗證等方面，通常應用於需要高度安全性的場合，例如金融、醫療、電子商務等。對於 Java 開發人員而言，JEP 339 提供了一種方便的方式來實現這些功能。

- 範例
    - 以下是使用 Java 實現 EdDSA 算法的簡單範例，用於生成密鑰、簽名和驗證數字簽名：

    ```java
    public class EdDSASample {

        public static void main(String[] args) throws Exception {
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EdDSA", "BC");
            keyGen.initialize(256, new SecureRandom());
            KeyPair keyPair = keyGen.generateKeyPair();
            PrivateKey privateKey = keyPair.getPrivate();
            PublicKey publicKey = keyPair.getPublic();

            // 簽名
            Signature signature = Signature.getInstance("EdDSA", "BC");
            signature.initSign(privateKey);
            byte[] message = "Hello World".getBytes();
            signature.update(message);
            byte[] sigBytes = signature.sign();

            // 驗證簽名
            Signature verifier = Signature.getInstance("EdDSA", "BC");
            verifier.initVerify(publicKey);
            verifier.update(message);
            boolean verified = verifier.verify(sigBytes);
            System.out.println("verified: " + verified);
        }
    }
    ```
    - 此範例使用了 Bouncy Castle 提供的加密庫，首先生成一對公私鑰，然後使用私鑰簽名，接著使用公鑰驗證簽名，最後輸出驗證結果。
    
#### JEP 394 - Pattern Matching for instanceof (Second Preview)

- [見 java 16](#java-16)

#### JEP 379 - Shenandoah: A Low-Pause-Time Garbage Collector (Production)

- 簡介
    - Shenandoah是Java虛擬機的一種垃圾回收器（Garbage Collector），由Red Hat公司開發。它可以在保持極低的暫停時間的情況下對堆進行收集。JEP 379在Java 15中將Shenandoah GC推出生產環境。
- 使用情境
    - Shenandoah GC適用於需要高效率、低延遲的Java應用程序。特別是對於大型的應用程式或應用程式需要大量的記憶體使用時，Shenandoah可以提供比其他垃圾回收器更好的效能和响应時間。
- 範例
    - Shenandoah GC在Java 15中成為預設的GC，應用程序無需任何修改即可使用。可以通過以下命令啟用Shenandoah GC：
    ```ruby
    -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC
    ```
#### JEP 385 - Remove RMI Activation

### java 16

#### JEP 395 - Records

- 簡介
    - Records是Java 16中的一個新特性，它可以讓使用者輕鬆地定義不可變的輕量級class。Records在程式設計中可以減少代碼量，並且提供了更好的可讀性和安全性。
- 使用情境
    - Records主要適用於需要輕量級且只有少量屬性的class。使用Records可以讓程式設計師更快速地撰寫程式碼，並且提高可讀性和安全性。
- 範例
    - 以下是一個使用Records來定義一個Person class的範例：
    ```java
    public record Person(String name, int age) {}
    ```
    - 然後，使用者可以像下面這樣使用這個Person class：

    ```java
    Person person = new Person("John", 30);
    System.out.println(person.name());
    System.out.println(person.age());
    ```
    - 關於返回到前端的VO使用Record好還是使用一般的class物件比較好，這取決於具體情況。使用Records的好處是可以讓程式碼更簡潔和易讀，但是Records目前還不支援繼承和泛型，如果這些特性對你的程式碼很重要，那麼使用一般的class物件可能更好。總的來說，使用Records還是使用一般的class物件取決於程式設計師對可讀性和程式碼量之間的權衡的取捨。

#### JEP 394 - Pattern Matching for instanceof (Second Preview)

- 簡介
    - JEP 394推出了Java中對instanceof的模式匹配（pattern matching）功能的第二個預覽版。它可以將對instanceof運算符的使用與類型的轉換（cast）結合在一起，以提供更簡潔的代碼。
- 使用情境
    - Pattern Matching for instanceof適用於那些需要使用instanceof運算符的代碼，尤其是那些需要在一個地方進行instanceof檢查，然後轉換該對象到一個特定的類型。這個新功能可以簡化代碼，並提高可讀性。
- 範例
    - 在還沒有JEP 394之前，開發者需要使用冗長的程式碼進行instanceof的判斷，例如：
    ```java
    if (obj instanceof Integer) {
        Integer i = (Integer) obj;
        System.out.println("Integer value: " + i);
    } else if (obj instanceof String) {
        String s = (String) obj;
        System.out.println("String value: " + s);
    }
    ```
    - 在使用JEP 394推出的新功能之後，可以使用模式匹配來簡化上述的程式碼，例如：
    ```java
    if (obj instanceof Integer i) {
        System.out.println("Integer value: " + i);
    } else if (obj instanceof String s) {
        System.out.println("String value: " + s);
    }
    ```
    - 可以看到，使用模式匹配可以直接把變數的聲明和instanceof的判斷放在同一行程式碼中，減少了冗長的程式碼，提高了可讀性和維護性。

#### JEP 357 - Migrate from Mercurial to Git
- 簡介
    - 這個提案是要將 OpenJDK 的原始碼從 Mercurial 轉移到 Git，這個提案在 java 16 的時候，已經完成了，所以在 java 16 的時候，OpenJDK 的原始碼已經從 Mercurial 轉移到 Git 了。
    - 轉移的原因
      - Mercurial 的開發人員已經不再維護 Mercurial 了，所以在 java 16 的時候，就將 OpenJDK 的原始碼從 Mercurial 轉移到 Git 了。
      - Git 的使用者比 Mercurial 多，所以在 java 16 的時候，就將 OpenJDK 的原始碼從 Mercurial 轉移到 Git 了。

#### JEP 376 - ZGC: Concurrent Thread-Stack Processing

- 簡介
    - JEP 376是ZGC垃圾回收器的一個增強功能，該功能可以同時進行並行執行緒堆棧處理。這可以幫助減少垃圾回收器的停頓時間，進一步提高Java應用程序的效能。
    - ZGC是一種針對大型內存的低停頓時間垃圾回收器，可用於處理多達16TB的Java堆。對於具有大量並行執行緒並且需要快速回應的Java應用程序，ZGC可以提供更好的垃圾回收性能。
    - ZGC 是在 java 11 的時候，就已經有了，但是在 java 11 的時候，ZGC 還是一個實驗性的功能，但是在 java 16 的時候，ZGC 已經是一個正式的功能了，可以放心的使用在 production 環境中。

#### JEP 338 - Vector API (Incubator)

- [見 java 17](#java-17)

#### JEP 392 - Packaging Tool

### java 17

#### JEP 306: Restore Always-Strict Floating-Point Semantics

- 簡介
	- JEP 306 提出了將 Java 平台的浮點運算行為恢復到 IEEE 754 標準的 "always strict" 規範。
- 使用情境
	- 這項改變可以確保浮點數計算在各種平台上的結果始終保持一致，從而使開發人員能夠更加信任他們的程式碼。
- 範例
	- 在使用 JEP 306 之前，Java 程序的浮點運算行為是可以寬鬆或嚴格的，這取決於處理器和作業系統的實現。然而，由於不同平台之間可能存在微小的差異，因此可能會導致浮點運算結果的不確定性。JEP 306 將始終採用 "always strict" 浮點運算，從而確保結果的一致性。
    
- 這個重要到連Java之父都來發文慶祝了
[![](http://bs.wfh.cloud-world.me/uploads/images/gallery/2023-05/scaled-1680-/image-1683768940763.png)](http://bs.wfh.cloud-world.me/uploads/images/gallery/2023-05/image-1683768940763.png)

#### JEP 409 - Sealed Classes (Second Preview)

- 簡介

    - Sealed Classes是Java 15推出的一個新功能，可以讓開發人員限制類的繼承層級。透過明確指定哪些類可以繼承自己，讓程式設計師更容易確保代碼的安全性和可維護性。
- 使用情境

    - Sealed Classes可以在開發Java應用程序時使用。開發人員可以使用它來限制哪些類可以繼承自己，以確保類的安全性。這可以使程式設計師更容易構建可擴展的程式設計模式，並減少潛在的bug。
- 範例

    - 以下是一個示例代碼，展示了如何使用Sealed Classes限制哪些類可以繼承自定義的抽象類：
    ```java
    public sealed abstract class Shape permits Circle, Square {
        public abstract double area();
    }
    public final class Circle extends Shape {
        private final double radius;
        public Circle(double radius) { this.radius = radius; }
        public double area() { return Math.PI * radius * radius; }
    }
    public final class Square extends Shape {
        private final double side;
        public Square(double side) { this.side = side; }
        public double area() { return side * side; }
    }
    ```
    - 上面的示例定義了一個抽象類Shape，只允許Square和Circle類繼承它。其他類的繼承將被編譯器拒絕。這樣就可以避免意外的類繼承和安全風險。

#### JEP 406 - Pattern Matching for switch(Preview)

- 簡介
    - JEP 406是Java的一個新功能，提供了對switch語句的模式匹配支持，使得開發人員可以更方便地使用複雜的分支邏輯。
- 使用情境
    - 在需要對一個變量進行多種可能的分支判斷時，使用switch語句可以使程式碼更加簡潔易讀。而JEP 406所提供的模式匹配支持，可以進一步簡化對多種分支判斷的程式碼，使得開發人員能夠更加輕鬆地處理複雜的邏輯。
- 範例
    - 在Java 14之前的版本，對於一個變量的多種可能值的判斷，可能需要使用多個if語句，例如：
    ```java
    if (obj instanceof Integer) {
        System.out.println("obj is an Integer");
    } else if (obj instanceof String) {
        System.out.println("obj is a String");
    } else if (obj instanceof List) {
        System.out.println("obj is a List");
    } else {
        System.out.println("obj is something else");
    }
    ```
    - 而在Java 14及以上版本，可以使用switch語句對多種可能值進行判斷，例如：
    ```java
    switch (obj) {
        case Integer i -> System.out.println("obj is an Integer");
        case String s -> System.out.println("obj is a String");
        case List<?> l -> System.out.println("obj is a List");
        default -> System.out.println("obj is something else");
    }
    ```
#### JEP 403 - Strongly Encapsulate JDK Internals by Default

- 簡介
    - 在Java 16中，為了改善JDK的安全性和可維護性，對內部API進行了封裝，但也留下了後門，可以使用啟動參數--illegal-access來控制內部API的封裝程度。（參見Java 16的新特性）

    - 到了Java 17中，除了sun.misc.Unsafe仍然可以使用外，其他內部API都變成了強制封裝模式，並且--illegal-access命令也被移除。如果在命令中仍添加此參數，將直接報錯： 
    ```console
    ~ $ java -version
    openjdk version "17.0.1" 2021-10-19
    OpenJDK Runtime Environment (build 17.0.1+12-39)
    OpenJDK 64-Bit Server VM (build 17.0.1+12-39, mixed mode, sharing)
    ~ $ java --illegal-access
    Unrecognized option: --illegal-access
    Error: Could not create the Java Virtual Machine.
    Error: A fatal exception has occurred. Program will exit.
    ```

#### JEP 410 - Remove the Experimental AOT and JIT Compiler

#### JEP 412 - Foreign Function & Memory API (Incubator)

- 簡介
    - JEP 412 是 Java 平台上的一個外來函式庫和內存 API 孵化器，它可以允許 Java 程序直接與其他語言編寫的原生函式進行交互，並且允許程序在內存中直接操作原生內存區域。

- 使用情境
    - Foreign Function & Memory API 可以讓 Java 程序與原生庫相互交互，這在與 C、C++ 或 Rust 等語言編寫的庫進行交互時非常有用。這也讓 Java 程序可以使用原生代碼編寫的高效函式。

- 範例
    - 以下是一個使用 JEP 412 的簡單示例，該示例顯示如何調用外部 C 函式庫：

    ```java
    public class JEP412Example {
        static {
            System.loadLibrary("myLib");
        }

        public static void main(String[] args) {
            var segment = Segment.allocateNative(1024);
            var libc = CLinker.getInstance();
            var printf = libc.downcallHandle(
                libc.lookup("printf").get(),
                MethodType.methodType(int.class, MemoryAddress.class),
                true
            );
            var formatString = segment.allocateCString("%s");
            var helloWorld = segment.allocateCString("Hello, world!");
            printf.invoke(formatString.address(), helloWorld.address());
        }
    }
    ```
    - 此示例創建了一個本地段，並使用 CLinker 來調用 printf 函式庫，並在控制台上輸出 "Hello, world!"。

#### JEP 414 - Vector API (Second Incubator)
- 簡介
    - Vector API 向量計算 API 是為了讓 Java 可以使用 SIMD(Single Instruction Multiple Data)指令集，讓 Java 可以使用 SIMD 指令集。
    - Vector API 是一個用於加速數值計算的庫，它提供了一個高層級的向量化程式設計模型，並且支援多個硬體平台，包括CPU、GPU、以及FPGA等。
    - 在JDK 16中，Vector API已經成為了JDK的一部分，但仍然是實驗性的功能，需要透過JVM選項啟用。
    - 在JDK 17中，Vector API已經被標記為第二個孵化器級別，仍然需要透過JVM選項啟用，但相較於JDK 16中的版本，增加了更多的功能和性能優化。
- 使用情境
    - Vector API主要針對數值計算領域的應用，尤其是那些需要處理大量數據並進行高效計算的場景。
    - 在需要對數據進行快速處理的應用中，使用Vector API可以提供顯著的性能優勢。
    - Vector API同時也支援跨平台的應用開發，並且支援不同的硬體平台。
- 範例
    - 原本的向量運算是使用 for 迴圈，例如下面的範例。

    ```java
    public class Main {
        public static void main(String[] args) {
            var a = new float[4];
            var b = new float[4];
            var c = new float[4];
            for (int i = 0; i < a.length; i++) {
                c[i] = a[i] + b[i];
            }
        }
    }
    ```

    - 在上面的範例中，可以看到原本的向量運算是使用 for 迴圈，但是在 java 17 的時候，就可以使用 Vector API 來取代 for 迴圈，例如下面的範例。

    ```java
    public class Main {
        public static void main(String[] args) {
            var a = FloatVector.zero(4);
            var b = FloatVector.zero(4);
            var c = a.add(b);
        }
    }
    ```

#### JEP 411 - Remove the Security Manager
#### JEP 405 - Remove the Concurrent Mark Sweep (CMS) Garbage Collector
#### JEP 402 - Remove the TraceEvent, TraceFormat, and TraceReader APIs
#### JEP 407 - Remove the Solaris and SPARC Ports
#### JEP 398 - Deprecate the Applet API for Removal




---
引用
* [https://spring.io/blog/2021/09/02/a-java-17-and-jakarta-ee-9-baseline-for-spring-framework-6](https://spring.io/blog/2021/09/02/a-java-17-and-jakarta-ee-9-baseline-for-spring-framework-6)
* [https://www.ithome.com.tw/voice/147487](https://www.ithome.com.tw/voice/147487)
* [https://in.relation.to/2021/09/14/ready-for-jdk17/](https://in.relation.to/2021/09/14/ready-for-jdk17/)
* [https://openjdk.org/projects/jdk/17/](https://openjdk.org/projects/jdk/17/)
* [https://openjdk.org/jeps/0](https://openjdk.org/jeps/0)
* [我是看山的小屋部落格](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzI4OTU5NTA1Ng==&action=getalbum&album_id=1732392238946533378&subscene=159&subscene=&scenenote=https%3A%2F%2Fmp.weixin.qq.com%2Fs%2FUESHDzuY3H7p5LLPJfwyAw&nolastread=1#wechat_redirect)

---
###### tags: `java` `java17`