1. 程式人生 > 其它 >Java9至17的新特性總結

Java9至17的新特性總結

總覽

講講Java 9-17 的一些語法糖和一些新發布的jeps, 重點講講JVM的垃圾回收器

時間線

SpringBoot 為什麼選擇Java17這個版本。我估計跟下面這個圖有關係。

Java 8 新特性

這裡簡單羅列一下Java 8 釋出的jeps
1、Lambda表示式
2、函數語言程式設計
3、介面可以新增預設方法和靜態方法,也就是定義不需要實現類實現的方法
4、方法引用
5、重複註解,同一個註解可以使用多次
6、引入Optional來避免空指標
7、引入Streams相關的API
8、引入新的Date/Time相關的API
9、新增jdeps命令列,來分析類、目錄、jar包的類依賴層級關係
10、JVM使用MetaSpace代替了永久代(PermGen Space)

Java 9 新特性

jeps

jdk9 新特性openjdk官網

102:程序 API 更新
110:HTTP 2 客戶端 *
143:改進競爭鎖定
158:統一 JVM 日誌記錄
165:編譯器控制
193:變數控制代碼
197:分段程式碼快取
199:智慧 Java 編譯,第二階段
200:模組化 JDK *
201:模組化原始碼 *
211:在匯入語句中省略棄用警告
212:解決 Lint 和 Doclint 警告
213:Milling Project Coin
214:刪除 JDK 8 中已棄用的 GC 組合 *  https://openjdk.java.net/jeps/173
215:javac 的分層歸因
216:正確處理匯入語句
217:註釋管道 2.0
219:資料報傳輸層安全性 (DTLS)
220:模組化執行時影象
221:簡化的 Doclet API
222:jshell:Java Shell(讀取-評估-列印迴圈)
223:新版本字串方案
224:HTML5 Javadoc
225:Javadoc 搜尋
226:UTF-8 屬性檔案
227:Unicode 7.0
228:新增更多診斷命令
229:預設建立 PKCS12 金鑰庫
231:刪除啟動時 JRE 版本選擇
232:提高安全應用程式效能
233:自動生成執行時編譯器測試
235:測試由 javac 生成的類檔案屬性
236:Nashorn 解析器 API
237:Linux/AArch64 埠
238:多版本 JAR 檔案
240:刪除 JVM TI hprof 代理
241:刪除 jhat 工具
243:Java 級 JVM 編譯器介面
244:TLS 應用層協議協商擴充套件
245:驗證 JVM 命令列標誌引數
246:利用 GHASH 和 RSA 的 CPU 指令
247:為舊平臺版本編譯
248:使 G1 成為預設垃圾收集器  ***
249:用於 TLS 的 OCSP 裝訂
250:在 CDS 檔案中儲存內部字串
251:多解析度影象
252:預設使用 CLDR 區域設定資料
253:為模組化準備 JavaFX UI 控制元件和 CSS API
254:緊湊字串
255 :將選定的 Xerces 2.11.0 更新合併到 JAXP
256: BeanInfo 註釋
257:將 JavaFX/Media 更新到 GStreamer 的較新版本
258: HarfBuzz 字型佈局引擎
259: Stack-Walking API
260:封裝大多數內部 API
261:模組系統  **
262:TIFF 影象 I/O
263:Windows 和 Linux 上的 HiDPI 圖形
264:平臺日誌記錄 API 和服務
265:Marlin 圖形渲染器
266:更多併發更新  **
267:Unicode 8.0
268:XML 目錄
269:集合的便利工廠方法  **
270:保留關鍵部分的堆疊區域
271:統一 GC 日誌記錄
272:特定於平臺的桌面功能
273:基於 DRBG 的 SecureRandom 實現
274:增強的方法控制代碼
275:模組化 Java 應用程式打包  **
276:語言定義的物件模型的動態連結
277:增強的棄用
278:G1 中巨大物件的附加測試
279:改進測試失敗故障排除
280:指示字串連線
281:HotSpot C++ 單元測試框架
282:jlink:Java 連結器
283:在 Linux 上啟用 GTK 3
284:新的 HotSpot 構建系統
285:Spin-Wait 提示
287:SHA-3 雜湊演算法
288:禁用 SHA-1 證書
289:棄用 Applet API
290:過濾傳入的序列化資料
291:棄用併發標記清除 (CMS) 垃圾收集器
292:在 Nashorn 中實現選定的 ECMAScript 6 功能
294:Linux/s390x 埠
295:提前編譯
297:統一 arm32/arm64 埠
298:刪除演示和示例
299:重新組織文件
集合的便利工廠方法
 Map<String, String> of = Map.of();
 Map<String, Integer> e = Map.of("e", 1);
 Map<String, Integer> e1 = Map.ofEntries(Map.entry("e", 1));
 Set<String> set = Set.of("e");
 List<App> list = List.of();
響應式程式設計

Flow API 是 Java 9 引入的響應式程式設計的介面 RXJava

java.util.concurrent.Flow;
Publisher:釋出者,負責釋出訊息 定義了生產資料和控制事件的方法;
Subscriber:訂閱者,負責訂閱處理訊息  定義了消費資料和事件的方法   ;
Subscription:訂閱控制類,可用於釋出者和訂閱者之間通訊 定義了連結Publisher和Subscriber的方法;
Processor:處理者,同時充當Publisher和Subscriber的角色 定義了轉換Publisher到Subscriber的方法
class SubmissionPublisher<T>是Flow.Publisher<T>的實現,她可以靈活的生產資料,同時與Reactive Stream相容。


SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
publisher.consume(v -> System.out.println("consumer:" + v));
publisher.submit("1");
publisher.submit("2");
publisher.submit("3");
publisher.submit("4");
publisher.offer("3",(d,v)->{
  System.out.println("droped");
	return true;
});
新的HTTP API

JDK 9 已經完成了一些原型設計工作,於JDK10釋出

設計目標

必須易於用於常見情況,包括簡單的阻塞模式。

必須提供事件通知,例如“收到的標頭”、錯誤和“收到的響應正文”。此通知不一定基於回撥,但可以使用 CompletableFuture 等非同步機制。

一個簡單而簡潔的 API,可滿足 80-90% 的應用程式需求。這可能意味著相對較小的 API 佔用空間,不一定會暴露協議的所有功能。

必須向伺服器公開 HTTP 協議請求的所有相關方面,以及來自伺服器的響應(標頭、正文、狀態程式碼等)。

必須支援標準和通用的身份驗證機制。這最初將僅限於基本身份驗證。

必須能夠輕鬆設定 WebSocket 握手。

必須支援HTTP/2。(HTTP/2 的應用程式級語義與 1.1 基本相同,儘管有線協議完全不同。)

必須能夠協商從 1.1 升級到 2(或不升級),或者從一開始就選擇 2。

必須支援伺服器推送,即伺服器無需客戶端明確請求即可向客戶端推送資源的能力。

必須執行與現有網路 API 一致的安全檢查。

應該對 lambda 表示式等新的語言特性友好。

應該對嵌入式系統要求友好,特別是避免永久執行的計時器執行緒。

必須支援 HTTPS/TLS。

HTTP/1.1 的效能要求:

效能必須與現有HttpURLConnection 實施相提並論。

當用作客戶端 API 時,效能必須與 Apache HttpClient 庫以及 Netty 和 Jetty 相當。

新 API 的記憶體消耗必須與HttpURLConnectionApache HttpClient 以及 Netty 和 Jetty 用作客戶端 API 的記憶體消耗相當或更低。

HTTP/2 的效能要求:

儘管有任何平臺限制(例如,TCP 段確認視窗),效能必須在新協議所期望的方面(即在可擴充套件性和延遲方面)優於 HTTP/1.1。

當用作 HTTP/2 的客戶端 API 時,效能必須與 Netty 和 Jetty 相當。

HttpURLConnection新 API 的記憶體消耗必須與使用、Apache HttpClient 以及用作客戶端 API 時的 Netty 和 Jetty相同或更低。

效能比較只會在可比較的操作模式的上下文中進行,因為新的 API 將強調簡單性和易用性,而不是涵蓋所有可能的用例,

這項工作是為 JDK 9 設計的。Java EE 在 Servlet 4.0 API 中的 HTTP/2 實現中可能會重用一些程式碼,
因此僅使用 JDK 8 語言功能,並在可能的情況下使用 API。

其目的是利用在 JDK 9 中使用 API 的經驗,可以在 JDK 10 中的 java.net 名稱空間下標準化 Java SE 中的 API。
當這種情況發生時,作為未來 JEP 的一部分,API將不再作為孵化器模組存在。

模組化

JDK模組化

應用程式模組化

通過定義module-info.java來控制Java的模組化

open module feature { //open 開放整個模組 為了執行時的反射
    requires xxx; // 需要使用該模組
    requires transitive  xxx; //繼承xxx的隱式可讀
    requires static jdk.internal.vm.ci; //編譯期檢查該模組是否已存在
    exports xxxx;
    exports xxx to xxx; //限制匯出 to 後面的模組才能訪問他
    //服務發現   ServiceLoader.load(interface.class);
    provides  Interface with Impl; //給interface 提供一個服務Impl
    uses Interface;//使用該interface 通過ServiceLoader 無需配置META-INFO
    opens jdk9.http2; //其他模組可以進行深度反射
    opens jdk9 to java.base; //只能由該模組可以進行深度反射
}
vm 引數
--illegal-access=permit //執行反射
 --add-opens
類載入器

JDK9後

  • 引導類載入器:定義核心Java SE和JDK模組。
  • 平臺類載入器:定義部分Java SE和JDK模組。
  • 應用或系統類載入器:定義CLASSPATH上的類和模組路徑中的模組。


JDK9之前

檔案流
        var classLoader = ClassLoader.getSystemClassLoader();
        InputStream in = classLoader.getResourceAsStream("file");
        try (var os = new FileOutputStream("file2")){
            in.transferTo(os);
        }
        in.close();

Java 10 新特性

jeps

Openjdk jeps網址

286:本地變數型別推斷 *
296:將 JDK 整合到一個儲存庫中 
304:垃圾收集器介面
307:G1 的並行Full GC *
310:應用程式類資料共享
312:執行緒本地握手
313:刪除 Native-Header生成工具 (javah)
314:附加 Unicode 語言標籤擴充套件
316:替代儲存裝置上的堆分配
317:基於 Java 的實驗性 JIT 編譯器 Graal *
319:根證書
322:基於時間的釋出版本控制
新語法糖
        var ss ="111";
        var list = List.of();
        var map = Map.of();
        var list2 = List.copyOf(list);
        var app = new VarApp();
        var set = Set.of();
        for (var i = 0; i <10; i++) {
            System.out.println(i);
        }
        System.out.println(int.class.getName());
        Stream<Integer> integerStream = Stream.of(3, 5, 6, 4, 5);

        LocalDate of = LocalDate.of(2022, 2, 28);

        //java9
        // 遇到 不滿足條件就跳出迴圈
        System.out.println("遇到 不滿足條件就跳出迴圈》》》》》》》》》》》》");
        integerStream.takeWhile(t->t%2!=0).forEach(System.out::println);
        System.out.println("只要碰到滿足的就把後面的資料留下來");
        integerStream = Stream.of(3, 4, 6, 4, 5,3);
        integerStream.dropWhile(t->t%2!=0).forEach(System.out::println);

        //流迭代
        Stream.iterate(2,n->n+1).limit(10).forEach(System.out::println);
        Stream.iterate(2,t->t<100,n->n+1).forEach(System.out::println);
GraalVM

GraalVM想成為一統天下的“最終”虛擬機器

Java 11 新特性

jeps

Openjdk jeps

181:基於巢狀的訪問控制
309:動態類檔案常量
315:改進 Aarch64 內在函式
318:Epsilon:無操作垃圾收集器
320:刪除 Java EE 和 CORBA 模組
321:HTTP 客戶端(標準) *
323:var 變數Lambda 引數的語法 *
324:與 Curve25519 和 Curve448 的金鑰協議
327:Unicode 10
328:JFR JVM監控  ***
329:ChaCha20 和 Poly1305 加密演算法
330:啟動單檔案原始碼程式
331:低開銷堆分析
332:傳輸層安全 (TLS) 1.3
333:ZGC:可擴充套件的低延遲垃圾收集器(實驗性) *
335:棄用 Nashorn JavaScript 引擎
336:棄用 Pack200 工具和 API
HTTP API

HTTP 客戶端是在 Java 11 中新增的。它可用於通過網路請求 HTTP 資源。
它支援 同步和非同步程式設計模型的HTTP/1.1和HTTP/2,將請求和響應主體作為響應流處理,並遵循熟悉的構建器模式。

HttpClient client = HttpClient.newHttpClient();
        client = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_2)
                .followRedirects(HttpClient.Redirect.NORMAL)
                .proxy(ProxySelector.of(new InetSocketAddress("www-proxy.com", 8080)))
                .authenticator(Authenticator.getDefault())
                .build();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://baidu.com/"))
                .build();

        request = HttpRequest.newBuilder()
                .uri(URI.create("http://openjdk.java.net/"))
                .timeout(Duration.ofMinutes(1))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString("{name:\"wang\",age:18}"))
                .build();

        HttpResponse<String> response =
                client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.statusCode());
        System.out.println(response.body());

        client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
                .thenApply(HttpResponse::body)
                .thenAccept(System.out::println)
                .join();
JFR

原生jvm事件流監控

       Configuration config = Configuration.getConfiguration("default");
        try (var es = new RecordingStream(config)) {
            es.onEvent("jdk.GarbageCollection", System.out::println);
            es.onEvent("jdk.CPULoad", System.out::println);
            es.onEvent("jdk.JVMInformation", System.out::println);
            es.setMaxAge(Duration.ofSeconds(10));
            es.start();
        }
Optional
        Optional<String> s = Optional.ofNullable(null);
        //or stream  orElseThrow isEmpty  ifPresentOrElse
        String c = s.or(() -> Optional.of("c")).get();
        System.out.println(c);
        Order order = new Order();
        Optional<Store> storeOptional = Optional.ofNullable(null);
        storeOptional.ifPresentOrElse(k->{
                    order.storeName=k.name;
                },
                ()->{
                    order.storeName ="未知";
                }
        );

String
        System.out.println("".isBlank());
        // 取前後的空格
        System.out.println("  java  ".strip());
        // 取前的空格
        System.out.println(" java".stripLeading());
        // 取後的空格
        System.out.println("java ".stripTrailing());
        //複製字串
        System.out.println("java".repeat(2));
        //獲取行數
        System.out.println("java\n java\n java\n".lines().count());

Java 12 新特性

jeps

OpenJDK jeps

189:	Shenandoah:一種低暫停時間的垃圾收集器(實驗性)
230:	微基準套件
325:	swtich表示式(預覽)
334:	JVM 常量 API
340:	一個 AArch64 埠,不是兩個
341:	預設 CDS 檔案
344:	G1 的可中止混合集合
346:	立即從 G1 返回未使用的已提交記憶體
語法糖
 public static void main(String[] args) {
        int day = 1;
        Integer integer = get(day);
        System.out.println(integer);

        double mean = Stream.of(1, 2, 3, 4, 5).collect(Collectors.teeing(
                //總和
                Collectors.summingDouble(i -> i),
                //元素數量
                Collectors.counting(),
                //處理結果
                (sum, n) -> sum / n
        ));

        String ms = "app";
        String transform = ms.transform(t -> t + "aa");
        System.out.println(transform);

    }

    public static int get(int day) {
        return switch (day) {
            case MONDAY, FRIDAY, SUNDAY -> 6;
            case TUESDAY -> 7;
            case THURSDAY, SATURDAY -> 8;
            case WEDNESDAY -> 9;
            default -> 0;
        };
    }

Java 13 新特性

JEPS

OpenJDK jeps

350:	動態 CDS 檔案
351:	ZGC:取消提交未使用的記憶體
353:	重新實現 Legacy Socket API
354:	切換表示式(預覽)
355:	文字塊(預覽)
文字塊
        String html1=" <html>\n" +
                "                  <body>\n" +
                "                      <p>Hello, world</p>\n" +
                "                  </body>\n" +
                "              </html>";

        System.out.println(html1);

        String html =
              """
              <html>
                  <body>
                      <p>Hello, world</p>
                  </body>
              </html>
              """;
        System.out.println(html);

Java 14 新特性

JEPS

Openjdk jeps

305:	instanceof 的模式匹配(預覽版)
343:	包裝工具(孵化器)
345:	G1 的 NUMA 感知記憶體分配
349:	JFR 事件流
352:	非易失性對映位元組緩衝區
358:	有用的 NullPointerExceptions
359:	record(預覽)
361:	Switch表示式(標準)
362:	棄用 Solaris 和 SPARC 埠
363:	刪除併發標記清除 (CMS) 垃圾收集器
364:	macOS 上的 ZGC
365:	Windows 上的 ZGC
366:	棄用 ParallelScavenge + SerialOld GC 組合
367:	刪除 Pack200 工具和 API
368:	文字塊(第二次預覽)
370:	Foreign-Memory Access API(孵化器)
record
record Person<T>(String name,Integer age){
    public List<T> getList(){
        return List.of();
    }
}
instanceof
 public static void getList(Object o) {
        if (o instanceof String msg) {
            System.out.println(msg.length());
        }
    }
空指標錯誤
        B b = new Main.B();
        System.out.println(b.a.c);
        /**
         * Cannot read field "c" because "b.a" is null
         * 	at jdk14.Main.main(Main.java:14)
         */

Java 15 新特性

jeps

Openjdk jeps

339:	愛德華茲曲線數字簽名演算法 (EdDSA)
360:	密封類(預覽版)
371:	隱藏類
372:	移除 Nashorn JavaScript 引擎
373:	重新實現舊版 DatagramSocket API
374:	禁用和棄用偏向鎖定
375:	instanceof 的模式匹配(第二次預覽)**
377:	ZGC:可擴充套件的低延遲垃圾收集器 **
378:	文字塊 **
379:	Shenandoah:一個低暫停時間的垃圾收集器 **
381:	刪除 Solaris 和 SPARC 埠
383:	Foreign-Memory Access API(第二個孵化器)
384:	record(第二次預覽)
385:	棄用 RMI 啟用以進行刪除
密封類
/**
 * 密封類對其允許的子類(由其permits子句指定的類)施加三個約束:
 *
 * 密封類及其允許的子類必須屬於同一個模組,並且如果在未命名的模組中宣告,則必須屬於同一個包。
 *
 * 每個允許的子類都必須直接擴充套件密封類。
 *
 * 每個允許的子類都必須選擇一個修飾符來描述它如何繼續由其超類發起的密封:
 *
 * public 可以定製那些類可以被繼承或實現
 */
 public sealed abstract class Shape permits Circle,Rectangle,Square {
 public non-sealed class Square extends Shape{
 public class SquareQA extends Square{
 public sealed class Rectangle extends Shape permits FilledRectangle {
 public final class FilledRectangle extends Rectangle{
public final class Circle extends Shape{

Java 16 新特性

OpenJDK jeps

338:	向量 API(孵化器)
347:	啟用 C++14 語言功能
357:	從 Mercurial 遷移到 Git
369:	遷移到 GitHub
376:	ZGC:併發執行緒堆疊處理
380:	Unix 域套接字通道
386:	高山 Linux 埠
387:	彈性元空間
388:	Windows/AArch64 埠
389:	外部連結器 API(孵化器)
390:	基於值的類的警告
392:	打包工具
393:	Foreign-Memory Access API(第三孵化器)
394:	instanceof 的模式匹配
395:	record
396:	預設情況下對 JDK 內部進行強封裝
397:	密封課程(第二次預覽)

Java 17 新特性

OpenJDK jeps

306:	恢復始終嚴格的浮點語義
356:	增強的偽隨機數生成器
382:	新的 macOS 渲染管道
391:	macOS/AArch64 埠
398:	棄用 Applet API 以進行刪除
403:	強烈封裝 JDK 內部
406:	開關的模式匹配(預覽版)
407:	刪除 RMI 啟用
409:	密封類
410:	刪除實驗性 AOT 和 JIT 編譯器  Graal
411:	棄用安全管理器以進行刪除
412:	外部函式和記憶體 API(孵化器)
414:	Vector API(第二個孵化器)
415:	特定於上下文的反序列化過濾器

Java 9 模組化

概念

  • 模組化(modularization)是指將系統分解成獨立且相互連結的木刻的行為
  • 模組(module)是包含程式碼的可識別工件, 使用了元資料來描述模組及其與其他模組的關係

為什麼引入模組化

  • 減少環境資源開銷,jlink打包後會打出最小映象
  • 可配置的封裝隔離機制 通過module-info

模組的核心原則

  • 強封裝性
    • 一個模組必須能夠對其他模組隱藏其部分程式碼。這樣一來,就可以在可公開使用的程式碼和被視為內部實現細節的程式碼之間劃定一條清晰的界限,從而防止模組之間發生意外或不必要的耦合,即無法使用被封裝的內容。
  • 定義良好介面
    • 雖然封裝是很好的做法,但如果模組需要一起工作,那麼就不能將所有的內容都進行封裝。從定義上講,沒有封裝的程式碼是模組公共API的一部分。由於其他模組可以使用這些公共程式碼,因此必須非常小心地管理它們。未封裝程式碼中任何一個重大更改都可能會破壞依賴該程式碼的其他模組。因此,模組應該向其他模組公開定義良好且穩定的介面。
  • 顯式依賴
    • 一個模組通常需要使用其他模組來完成自己的工作,這些依賴關係必須是模組定義的一部分,以便使模組能夠獨立執行。

截止到Jdk17的GC的垃圾回收器的發展史

//todo