新項(xiàng)目為什么決定用 JDK 17了

大家好,我是哪吒。
Java是一門非常流行的編程語言,由于其跨平臺性、可移植性以及強(qiáng)大的面向?qū)ο筇匦远鴤涫芮嗖A。Java最初由Sun Microsystems公司于1995年推出,隨著時(shí)間的推移,Java發(fā)展迅速,版本不斷更新。本篇博客將重點(diǎn)介紹Java 17與Java 8的對比,以及Java 17的新特性。
特征  | Java 17  | Java 8  | 
引入  | 2021年9月14日  | 2014年3月  | 
垃圾收集器  | ZGC(新型垃圾收集器)  | G1收集器  | 
其他垃圾收集器  | Shenandoah GC,G1 GC,Parallel GC,Serial GC  | Parallel GC,Serial GC  | 
垃圾回收策略  | 全堆回收和增量模式  | 復(fù)制模式  | 
應(yīng)用程序類數(shù)據(jù)共享(AppCDS)  | 支持  | 不支持  | 
JFR事件流  | 使用異步處理提高性能  | 未支持  | 
條件性實(shí)例化卡片  | 支持  | 支持  | 
嵌入式C / C ++庫  | JDK不包括C / C ++編譯器  | JDK不包括C / C ++編譯器  | 
算法升級  | SHA-3,SM3 / SM4,Ed448,RSASSA-PSS,X25519 / X448  | SHA-1,RC4,DES,MD5,DSA,DH  | 
一、Java 17與Java 8的對比
Java 17與Java 8是Java版本中的兩個(gè)重要里程碑。Java 8是Java版本中的一次重大更新,于2014年發(fā)布,引入了很多新的特性和功能,包括Lambda表達(dá)式、Stream API、函數(shù)式接口等。Java 17是Java SE 17版本,于2021年9月發(fā)布,是Java SE 16的長期支持(LTS)版本。Java 17中也有一些新的特性和改進(jìn),我們將在后文中詳細(xì)討論。
二、性能比較
Java 17與Java 8在性能方面的比較非常重要。Java 8引入了一些性能改進(jìn),例如優(yōu)化了字符串連接和數(shù)組排序等操作。Java 17在性能方面也有一些新的改進(jìn),例如:
- 改進(jìn)了JIT編譯器,提高了應(yīng)用程序的性能。
 - 改進(jìn)了垃圾回收器,提高了垃圾回收的效率和吞吐量。
 - 引入了C++風(fēng)格的內(nèi)存管理,包括對堆內(nèi)存分配的優(yōu)化和對垃圾回收的改進(jìn)。這些改進(jìn)都可以提高Java應(yīng)用程序的性能和響應(yīng)速度。
 
三、語言特性比較
Java 8引入了一些新的語言特性,例如Lambda表達(dá)式和函數(shù)式接口。這些特性讓Java程序員能夠使用函數(shù)式編程的方式編寫代碼,從而使得代碼更加簡潔、易讀、易維護(hù)。Java 17在語言特性方面也有一些新的改進(jìn),例如:
- 引入了Sealed類,這是一種新的類修飾符,用于限制類的繼承。這樣可以使得代碼更加安全、可維護(hù)。
 - 引入了Pattern Matching for Switch語法,這是一種新的switch語法,可以用于模式匹配。這樣可以使得代碼更加簡潔、易讀、易維護(hù)。
 - 引入了Record類,這是一種新的數(shù)據(jù)類,可以用于定義只有屬性和訪問器的簡單數(shù)據(jù)對象。這樣可以使得代碼更加簡潔、易讀、易維護(hù)。
 - 這些改進(jìn)都可以使得Java程序員能夠使用更加先進(jìn)、更加高效的語言特性編寫代碼。
 
四、應(yīng)用場景比較
Java 8和Java 17都可以用于不同的應(yīng)用場景,但是它們在一些方面有所不同。Java 8適用于開發(fā)中小型應(yīng)用程序和Web應(yīng)用程序,例如Web服務(wù)、企業(yè)級應(yīng)用程序和桌面應(yīng)用程序等。Java 8也可以用于開發(fā)大型應(yīng)用程序,但是在大型應(yīng)用程序中可能會(huì)出現(xiàn)一些性能問題。Java 17則更適合用于開發(fā)大型應(yīng)用程序和高性能應(yīng)用程序,例如高性能計(jì)算、云計(jì)算、大數(shù)據(jù)處理等。
五、Java 17的新特性
Java 17是Java SE 17版本,于2021年9月發(fā)布,是Java SE 16的長期支持(LTS)版本。Java 17中有許多新的特性和改進(jìn),以下是一些主要特性:
1、Sealed類
Sealed類是一種新的類修飾符,用于限制類的繼承。Sealed類可以控制哪些類可以繼承自它,這樣可以使得代碼更加安全、可維護(hù)。Sealed類的使用可以在編譯時(shí)強(qiáng)制執(zhí)行一些規(guī)則,從而避免運(yùn)行時(shí)錯(cuò)誤。
(1)代碼示例
public sealed abstract class Shape permits Circle, Rectangle {
    public abstract double calculateArea();
}
public final class Circle extends Shape {
    private double radius;
    public Circle(double radius) {
        this.radius = radius;
    }
    public double getRadius() {
        return radius;
    }
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}
public final class Rectangle extends Shape {
    private double length;
    private double width;
    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }
    public double getLength() {
        return length;
    }
    public double getWidth() {
        return width;
    }
    public double calculateArea() {
        return length * width;
    }
}(2)代碼說明:
在這個(gè)示例中,Shape 是一個(gè)抽象類,并且使用 permits 關(guān)鍵字,明確允許哪些類繼承該類。Circle 和 Rectangle 是 Shape 的子類,并使用 final 關(guān)鍵字來表示它們是封閉類,不允許有其他子類繼承它們。這種方式可以在編譯時(shí)校驗(yàn)代碼,并防止意外創(chuàng)建不受預(yù)期的子類。
2、Pattern Matching for Switch語法
Pattern Matching for Switch語法是一種新的switch語法,可以用于模式匹配。Pattern Matching for Switch語法可以根據(jù)不同的模式執(zhí)行不同的操作,從而使得代碼更加簡潔、易讀、易維護(hù)。Pattern Matching for Switch語法可以減少代碼量,避免出現(xiàn)大量的if-else語句。
(1)代碼示例
public static void main(String[] args) {
    Object obj = "hello";
    switch (obj) {
        case String s && s.length() > 5 -> System.out.println("長字符串");
        case String s -> System.out.println("短字符串");
        case Integer i -> System.out.println("整型數(shù)");
        default -> System.out.println("不支持的類型");
    }
}(2)代碼說明:
在這個(gè)示例中,我們首先定義了一個(gè) Object 類型的變量 obj,它可能是一個(gè)字符串、整型數(shù)或其他類型的對象。
接下來,我們使用了 switch 語句,并對 obj 進(jìn)行了幾個(gè)模式匹配:
- 如果 obj 是一個(gè)長度大于 5 的字符串,表達(dá)式 case String s && s.length() > 5 就會(huì)被匹配并執(zhí)行相應(yīng)的代碼塊。
 - 如果 obj 是一個(gè)短字符串,表達(dá)式 case String s 會(huì)匹配并執(zhí)行相應(yīng)代碼塊。
 - 如果 obj 是一個(gè)整型數(shù),表達(dá)式 case Integer i 就會(huì)執(zhí)行相應(yīng)代碼塊。
 - 如果 obj 不屬于以上任何一種類型,就會(huì)執(zhí)行默認(rèn)代碼塊。
 
3、Record類
Record類是一種新的數(shù)據(jù)類,可以用于定義只有屬性和訪問器的簡單數(shù)據(jù)對象。Record類可以簡化代碼,使得代碼更加易讀、易維護(hù)。Record類的使用可以減少代碼量,避免出現(xiàn)大量的getter和setter方法。
(1)代碼示例
public record Person(String name, int age) {}
public class RecordExample {
    public static void main(String[] args) {
        Person person = new Person("John", 30);
        System.out.println("Name: " + person.name());
        System.out.println("Age: " + person.age());
    }
}(2)代碼說明:
在這個(gè)示例中,我們定義了一個(gè)名為 Person 的 Record 類,它有兩個(gè)字段:name 和 age。Record 類會(huì)自動(dòng)生成一個(gè)帶有這些字段的構(gòu)造函數(shù)、getter 方法和 equals、hashCode 和 toString 方法。
- 我們在 main 方法中創(chuàng)建了一個(gè) Person 對象,并使用 name() 和 age() 方法獲取其名稱和年齡信息,然后將其打印出來。
 - 使用 Record 類,我們可以更輕松地定義簡單的數(shù)據(jù)類,而不需要手動(dòng)編寫大量的構(gòu)造函數(shù)和 getter 方法。這可以使我們的代碼更加簡潔、清晰,并且更易于閱讀和維護(hù)。
 
4、改進(jìn)的垃圾回收器
Java 17中改進(jìn)了垃圾回收器,提高了垃圾回收的效率和吞吐量。改進(jìn)的垃圾回收器可以更加高效地回收內(nèi)存,從而提高應(yīng)用程序的性能和響應(yīng)速度。
(1)代碼示例
public class GarbageCollectorExample {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            list.add(i);
        }
        System.out.println("List size: " + list.size());
        System.gc(); // 調(diào)用垃圾回收器
        System.out.println("List size after GC: " + list.size());
    }
}(2)代碼說明:
在這個(gè)示例中,我們使用了 ZGC 垃圾回收器來回收 list 對象占用的內(nèi)存。我們在代碼中使用了 System.gc() 方法來手動(dòng)觸發(fā)垃圾回收器。注意,在實(shí)際應(yīng)用中,我們通常不需要手動(dòng)觸發(fā)垃圾回收器,因?yàn)?JVM 會(huì)自動(dòng)進(jìn)行垃圾回收操作。
ZGC 垃圾回收器具有可伸縮性和低延遲的特點(diǎn),可以在處理大型、高并發(fā)應(yīng)用程序時(shí)提供更好的性能和吞吐量。除了 ZGC,Java 17 中還引入了 Shenandoah 垃圾回收器,它也具有類似的高性能和低延遲的特點(diǎn)。
5、改進(jìn)的JIT編譯器
Java 17中改進(jìn)了JIT編譯器,提高了應(yīng)用程序的性能。改進(jìn)的JIT編譯器可以更加高效地編譯代碼,從而提高應(yīng)用程序的性能和響應(yīng)速度。
(1)代碼示例
public class JITCompilerExample {
    public static void main(String[] args) {
        int sum = 0;
        for (int i = 0; i < 1000000; i++) {
            sum += i;
        }
        System.out.println("Sum is: " + sum);
    }
}在Java 17中,可以通過添加以下命令行參數(shù)來啟用Graal編譯器:
-XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseJVMCICompiler(2)代碼說明:
當(dāng)運(yùn)行上述示例代碼時(shí),Graal編譯器會(huì)自動(dòng)將循環(huán)優(yōu)化為一個(gè)簡單的算術(shù)公式,從而大大提高了性能。
6、風(fēng)格的內(nèi)存管理
Java 17中引入了C++風(fēng)格的內(nèi)存管理,包括對堆內(nèi)存分配的優(yōu)化和對垃圾回收的改進(jìn)。C++風(fēng)格的內(nèi)存管理可以使得Java應(yīng)用程序更加高效,從而提高應(yīng)用程序的性能和響應(yīng)速度。
(1)代碼示例
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.ManagementFactory;
public class MemoryManagementExample {
    public static void main(String[] args) throws InterruptedException {
        MemoryPoolMXBean heap = ManagementFactory.getMemoryPoolMXBeans().stream()
                .filter(p -> p.getName().equals("Java heap")).findFirst().orElseThrow();
            System.out.println("Heap memory utilization statistics:\n");
            try (var scope = heap.reserveMemory(1024 * 1024)) {
                long usedMemory = heap.getUsage().getUsed();
                long commitedMemory = heap.getUsage().getCommitted();
                System.out.printf("Before allocation: used=%d, committed=%d%n", usedMemory, commitedMemory);
                byte[] array = new byte[1024 * 1024];
                usedMemory = heap.getUsage().getUsed();
                int capacity = scope.getBytesReserved();
                System.out.printf("After allocation: used=%d, committed=%d, capacity=%d%n", usedMemory, commitedMemory,
                        capacity);
            }
            long usedMemory = heap.getUsage().getUsed();
            long commitedMemory = heap.getUsage().getCommitted();
            System.out.printf("After scope: used=%d, committed=%d%n", usedMemory, commitedMemory);
    }
}(2)代碼說明:
- 定義了一個(gè)名為 MemoryManagementExample 的類,然后獲取 Java heap 內(nèi)存池,并在 try-with-resources 語句中創(chuàng)建了一個(gè)名為 scope 的資源。
 - 然后,我們打印了內(nèi)存使用率統(tǒng)計(jì)信息,并在 scope 內(nèi)部分配了一個(gè) 1MB 的字節(jié)數(shù)組。我們使用 getBytesReserved() 方法獲取作用域中已保留的字節(jié)數(shù),并打印了內(nèi)存使用情況和容量等信息。
 - 最后,我們打印了作用域結(jié)束后內(nèi)存的使用情況。
 
7、增強(qiáng)的Java集合庫
Java 17中增強(qiáng)了Java集合庫,包括新增了一些集合類型和對現(xiàn)有集合類型的改進(jìn)。增強(qiáng)的Java集合庫可以提高開發(fā)人員的開發(fā)效率和代碼質(zhì)量,從而減少出現(xiàn)錯(cuò)誤的可能性。同時(shí),增強(qiáng)的Java集合庫也可以提高應(yīng)用程序的性能和響應(yīng)速度,使得Java應(yīng)用程序更加高效。
(1)of() 方法:創(chuàng)建一個(gè)不可變的集合
List<String> list = List.of("apple", "banana", "orange");
Set<Integer> set = Set.of(1, 2, 3, 4);
Map<String, Integer> map = Map.of("apple", 1, "banana", 2, "orange", 3);(2)forEach() 方法:遍歷集合
List<String> list = List.of("apple", "banana", "orange");
list.forEach(name -> System.out.println(name));
Set<Integer> set = Set.of(1, 2, 3, 4);
set.forEach(number -> System.out.println(number));(3)Collectors類:提供了一系列的歸約操作
List<String> list = List.of("apple", "banana", "orange");
String joinedString = list.stream().collect(Collectors.joining("-", "[", "]"));
System.out.println(joinedString);
Map<String, Integer> map = Map.of("apple", 1, "banana", 2, "orange", 3);
Map<Integer, String> reversedMap = map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
System.out.println(reversedMap);(4)takeWhile() 方法和 dropWhile() 方法:根據(jù)條件截取集合
List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7);
List<Integer> takenList = list.stream().takeWhile(number -> number < 5).collect(Collectors.toList());
System.out.println(takenList);
List<Integer> dropedList = list.stream().dropWhile(number -> number < 5).collect(Collectors.toList());
System.out.println(dropedList);(5)toArray(IntFunction<T[]>) 方法:返回集合中的所有元素到一個(gè)新數(shù)組中
List<String> list = List.of("apple", "banana", "orange");
String[] array = list.toArray(String[]::new);
System.out.println(Arrays.toString(array));本文轉(zhuǎn)載自微信公眾號「哪吒編程」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系哪吒編程公眾號。
















 
 
 










 
 
 
 