JAVA8之後的版本履歷

目錄

一、JDK介紹

1.1 Java 的發佈週期

1.2 OpenJDK VS Oracle JDK

1.3 Android 和 JDK

1.4 JVM 和 TCK

1.5 Harmony 和 OpenJDK

1.6 Oracle 和 Google 關於 JDK 糾紛

二、JAVA版本發佈

2.1 JAVA8

2.1.1  Lambda 和 函數式接口

2.1.2. 方法引用

2.1.3 接口默認方法和靜態方法

2.1.4 重複註解

2.1.5. 類型註解

2.1.6. 更好的類型推斷

2.1.7. Optional

2.1.8. Stream

2.1.9. 日期時間 API

2.1.10. Base64 支持

2.1.11. 並行數組 ParallelSort

2.1.12. 其他新特性

2.2 Java 9

2.2.1 Jigsaw 模塊系統

2.2.2 JShell REPL

2.2.3. 私有接口方法,接口中使用私有方法

2.2.4. 集合不可變實例工廠方法

2.2.5. 改進 try-with-resources

2.2.6. 多版本兼容 jar 包

2.2.7. 增強了 Stream,Optional,Process API

2.2.8. 新增 HTTP2 Client

2.2.9. 增強 Javadoc,增加了 HTML 5 文檔的輸出,並且增加了搜索功能

2.2.10. 增強 @Deprecated

2.2.11. 增強了鑽石操作符 "<>",可以在 匿名內部類中使用了。

2.2.12. 多分辨率圖像 API:定義多分辨率圖像API,開發者可以很容易的操作和展示不同分辨率的圖像了。

2.2.13. 改進的 CompletableFuture API

2.3 Java 10

2.3.1. 局部變量類型推斷

2.3.2. GC改進和內存管理

2.3.3. 線程本地握手(JEP 312)

2.3.4. 備用內存設備上的堆分配(JEP 316)

2.3.5. 其他Unicode語言 - 標記擴展(JEP 314)

2.3.6. 基於Java的實驗性JIT編譯器

2.3.7. 根證書(JEP 319)

2.3.8. 根證書頒發認證

2.3.9. 將JDK生態整合單個存儲庫(JEP 296)

2.3.10. 刪除工具javah(JEP 313)

2.4 Java 11

2.4.1 本地變量類型推斷

2.4.2 字符串加強

2.4.3 集合加強

2.4.4 Stream 加強

2.4.5 Optional 加強

2.4.6 InputStream 加強

2.4.7 HTTP Client API

2.4.8 化繁爲簡,一個命令編譯運行源代碼

2.5 Java 12

2.5.1 switch 表達式

2.5.2 2 默認CDS歸檔

2.5.3 Shenandoah GC

2.5.4 JMH 基準測試

2.5.5 JVM 常量 API 

2.5.6 G1的可中斷 mixed GC

2.5.7 G1歸還不使用的內存

2.5.8移除多餘ARM64實現

三、其他參考資料


不知不覺,JAVA13都快要發佈了,現在還在使用java8,。畢竟java也收費了。HTTP2.0未來應該也是趨勢,不升級是不可能的了。未來該怎麼樣,還是靜靜的觀望吧,不管怎樣,新版本特性我們還是要了解的。

JDK版本總結,持續更新

一、JDK介紹

JDK 全稱 Java Development Kit,是 Java 開發環境。我們通常所說的 JDK 指的是 Java SE (Standard Edition) Development Kit。除此之外還有 Java EE(Enterprise Edition)和 Java ME(Micro Edition platforms)。

1.1 Java 的發佈週期

聊聊 Java8 以後各個版本的新特性

下面我們看一些 Java 發展過程中重要的節點。

1995 年 alpha 和 beta Java 公開版本發佈,取名爲 WebRunner。

1996.1.23 Java 第一個版本發佈,取名叫 Oak。但是第一個穩定版本是 JDK 1.0.2,被稱做 Java 1。

1998.12.8 發佈了 J2SE 1.2。這個版本到 J2SE 5.0 更名爲 Java 2。其中的 SE 指的是 Standard Edition,爲了區別於 J2EE(Enterprise Edition)和 J2ME(Micro Edition)。

2000.5 發佈了 J2SE 1.3,其中包含了 HotSpot JVM。而 HotSpot JVM 首次發佈是在 1999.4,名爲 J2SE 1.2 JVM。

2004.9.30 發佈了 J2SE 5.0。爲什麼這個版本命名和前面幾個版本不一樣呢?這個版本原本計劃以 1.5 命名的,沿用以前的命名方式。但是爲了更好的反映這個版本的成熟度,所以改名爲 5.0。

這個版本以後,有了一個新的版本控制系統,5.0 用來表示產品版本,用來表示穩定的 J2SE 版本,而 1.5.0 用來表示開發者版本,也就是 Java 5.0 = JDK 1.5.0。

2006.12.11,J2SE 改名爲 Java SE,版本號去掉了 .0。此後對應版本就是 Java 6 = JDK 1.6,Java 7 = JDK 1.7。

2011.7.7. 發佈 Java SE 7,是一個重大版本更新。更新了衆多特性。

2018.3 發佈 Java SE 10。在此之前,Java 基本上是兩年一個版本,除了 Java SE 7 經過了五年,Java SE 8 經過了三年。在此之後,就是每六個月發佈一次新版本。但是不是每個版本都是 LTS(Long-Term-Support)。按照 Oracle 的計劃,每三年會有一個 LTS 版本。最近的 LTS 版本就是 Java SE 11 了。

1.2 OpenJDK VS Oracle JDK

OpenJDK 是 在 2007 年由 Sun Corporation(現在的Oracle Corporation) 發佈的。是 Oracle JDK 的開源實現版本,以 GPL 協議發佈。在 JDK 7 的時候,Sub JDK 就是在 Open JDK 7 的基礎上發佈的,只替換了少量的源碼。在 Sun 公司被 Oracle 收購以後,Sun SDK 就被稱爲 Oracle JDK。Oracle JDK 是基於 Oracle Binary COde License Agreement 協議。

兩者的區別如下:

  • Oracle JDK 將三年發佈一次穩定版本,OpenJDK 每三個月發佈一次。

  • Oracle JDK 支持 LTS,OpenJDK 只支持當前版本至下一個版本發佈。

  • Oracle JDK 採用 Oracle Binary Code License 協議,OpenJDK 採用 GPL v2 協議。

  • Oracle JDK 基於 OpenJDK 構建,技術上基本沒有差異。

1.3 Android 和 JDK

說起 Android 和 OpenJDK 的歷史淵源,還是略微複雜。

簡單來說,Android 最開始使用的 Java 是基於 Apache 協議發佈的 Harmony,後來由於 Harmony 本身的限制和 Oracle 公司的起訴,從 Android N 以後, Google 開始使用 OpenJDK。

然後我們再稍微展開聊聊。

1.4 JVM 和 TCK

Sun 公司最初開發了 Java 語言,同時也開發了 JVM,並且定義了 JVM 規範。這個我們比較清楚,只要基於 JVM 規範開發自己的語言,就可以運行在 JVM 上。但是依照規範開發了語言之後,需要通過 Sun 的 TCK(Technology Compatibility Kit)測試,之後才能成爲官方認可的 JVM 語言。

1.5 Harmony 和 OpenJDK

基於 JVM 規範,Apache 開發了一個開源免費的 Java 實現 Harmony,並且根據 Apache License v2 發佈。但是 Sun 公司並沒有給 Harmony TCK 許可。

在 2009.4.15 Sun 公司發佈了 OpenJDK,基於 GNU GPL 發佈。同時 Sun 公司規定只有衍生自 OpenJDK 採用的 GPL 協議的開源實現才能運行 OpenJDK 的 TCK。之後 Oracle 收購 Sun 公司以後接管了 OpenJDK。

由於 Apache 的 Harmony 是 Apache 協議,與 OpenJDK 的 GPL 協議不兼容,所以 Harmony 一直沒有得到 TCK 授權。

Android 最開始是採用了 Harmony 作爲自己的 Java 類庫,因爲 Harmony 使用的 Apache 協議更自由。而由於 Harmony 沒有通過 TCK 認證,也爲後來 Oracle 起訴 Google 埋下伏筆。

1.6 Oracle 和 Google 關於 JDK 糾紛

後來 Oracle 起訴 Google 主要集中在兩點,一是 Oracle 認爲 Google 代碼中使用了 Java 的 37 個 API,二是 Sun 公司前員工在跳槽後爲 Android 項目開發時,直接複製了 OpenJDK 中的九行代碼,而 Android 項目並沒有按照 GPL 協議授權,所以複製 OpenJDK 代碼是沒有通過 GPL 授權的。

所以到後來爲了解決專利的問題,Android N 以後,Android 開始使用 OpenJDK 替換 Harmony。

以上 Android 和 JDK 參考資料:

https://juejin.im/entry/5abc516b518825556f557f90
https://gudong.name/2019/04/05/android-why-java-harmony.html

聊了一些關於 Java 的歷史,下面我們看看各個 Java 版本有那些新特性。這裏只列出了對開發者影響比較大的一些特性~(如果需要Java面試知識點,可以在Java知音公衆號回覆”Java面試題聚合“)

二、JAVA版本發佈

2.1 JAVA8

Java8 參考資料

http://ifeve.com/java-8-features-tutorial/
https://juejin.im/post/5ae6bfb66fb9a07a9b35bac1
https://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html
https://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html

2.1.1  Lambda 和 函數式接口

Lambda 表達式相信不用再過多的介紹,終於在 Java 8 引入了,可以極大的減少代碼量,代碼看起來更清爽。

函數式接口就是有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。可以隱式轉化爲 Lambda 表達式。

我們定義一個函數式接口如下:

@FunctionalInterface
interface Operation {
    int operation(int a, int b);
}

再定義一個 Class 用來操作 Operation 接口。

class Test {
    private int operate(int a, int b, Operation operation) {
        return operation.operation(a, b);
    }
}

Test test = new Test();

在 Java 8 之前,我們想要實現 Operation 接口並傳給 Test.operate() 方法使用,我們要定義一個匿名類,實現 Operation 方法。

test.operate(1, 2, new Operation() {
    @Override
    public int operation(int a, int b) {
        return a + b;
    }
});

而使用 Lambda 表達式,我們就可以這樣寫了:

test.operate(1, 2, (a, b) -> a + b);

2.1.2. 方法引用

通過方法引用,可以使用方法的名字來指向一個方法。使用一對冒號來引 "::" 用方法。還是以上面的例子來看,我們再添加幾個方法:

@FunctionalInterface
interface Operation {
    int operation(int a, int b);
}

interface Creater<T> {
    T get();
}

interface TestInt {
    int cp(Test test1, Test test2);
}

class Test {
    public static Test create(Creater<Test> creater) {
        return creater.get();
    }

    private int operate(int a, int b, Operation operation) {
        return operation.operation(a, b);
    }

    private static int add(int a, int b) {
        return a + b;
    }

    private int sub(int a, int b) {
        return a - b;
    }

    public int testM(Test test) {
        return 0;
    }

    public void test(TestInt testInt) {
        Test t1 = Test.create(Test::new); 
        Test t2 = Test.create(Test::new);
        testInt.cp(t1, t2);
    }

}

那麼對應的方法引用有四種:

構造方法引用

使用方式:Class::new

Test test = Test.create(Test::new);

靜態方法引用

使用方式:Class::staticMethod

test.operate(1, 2, Test::add);

對象的實例方法引用

使用方式:instance::method

test.operate(1, 2, test::sub);

類的實例方法引用

使用方式:Class::method

test.test(Test::testM);

其實上面三種方法引用都好理解,最後類的實例方法引用,有兩個條件:

  • 首先要滿足實例方法,而不是靜態方法

  • Lambda 表達式的第一個參數會成爲調用實例方法的對象

根據這兩點我們看上面的例子,test 方法接受一個 TestInt 實例,用 Lambda 表達式表示就是 (Test t1, Test t2) -> res,而我們調用 test 方法時傳入的方法引用是 Test::testM,其參數也是一個 Test 實例,最終 test.test(Test::testM) 的調用效果就是 t1.testM(t2)

2.1.3 接口默認方法和靜態方法

Java 8 新增了接口的默認實現,通過 default 關鍵字表示。同時也可以提供靜態默認方法。

public interface TestInterface {
    String test();

    // 接口默認方法
    default String defaultTest() {
        return "default";
    }

    static String staticTest() {
        return "static";
    }
}

2.1.4 重複註解

Java 8 支持了重複註解。在 Java 8 之前想實現重複註解,需要用一些方法來繞過限制。比如下面的代碼。

@interface Author {
    String name();
}

@interface Authors {
    Author[] value();
}

@Authors({@Author(name="a"), @Author(name = "b")})
class Article {
}

而在 Java 8 中,可以直接用下面的方式。

@Repeatable(Authors.class)
@interface Author {
    String name();
}

@interface Authors {
    Author[] value();
}

@Author(name = "a")
@Author(name = "b")
class Article {
}

在解析註解的時候,Java 8 也提供了新的 API。

AnnotatedElement.getAnnotationsByType(Class<T>)

2.1.5. 類型註解

Java 8 之前註解只能用在聲明中,在 Java 8 中,註解可以使用在 任何地方。

@Author(name="a")
private Object name = "";
private String author = (@Author(name="a")String) name;

2.1.6. 更好的類型推斷

Java 8 對於類型推斷做了改進。

比如在 Java 7 中下面的寫法:

List<String> stringList = new ArrayList<>();
stringList.add("A");
stringList.addAll(Arrays.<String>asList());

在 Java 8 中改進後的寫法,可以自動做類型推斷。

List<String> stringList = new ArrayList<>();
stringList.add("A");
stringList.addAll(Arrays.asList());

2.1.7. Optional

Java 8 中新增了 Optional 類用來解決空指針異常。Optional 是一個可以保存 null 的容器對象。通過 isPresent() 方法檢測值是否存在,通過 get() 方法返回對象。
除此之外,Optional 還提供了很多其他有用的方法,具體可以查看文檔。下面是一些示例代碼。

// 創建一個 String 類型的容器
Optional<String> str = Optional.of("str");
// 值是否存在
boolean pre = str.isPresent();
// 值如果存在就調用 println 方法,這裏傳入的是 println 的方法引用
str.ifPresent(System.out::println);
// 獲取值
String res = str.get();
// 傳入空值
str = Optional.ofNullable(null);
// 如果值存在,返回值,否則返回傳入的參數
res = str.orElse("aa");
str = Optional.of("str");
// 如果有值,對其調用映射函數得到返回值,對返回值進行 Optional 包裝並返回
res = str.map(s -> "aa" + s).get();
// 返回一個帶有映射函數的 Optional 對象
res = str.flatMap(s -> Optional.of(s + "bb")).flatMap(s -> Optional.of(s + "cc")).get();

2.1.8. Stream

Java 8 中新增的 Stream 類提供了一種新的數據處理方式。這種方式將元素集合看做一種流,在管道中傳輸,經過一系列處理節點,最終輸出結果。

關於 Stream 提供的具體方法,可以參照 API。下面是一些示例代碼。

List<String> list = Arrays.asList("maa", "a", "ab", "c");
list.stream()
        .filter(s -> s.contains("a"))
        .map(s -> s + "aa")
        .sorted()
        .forEach(System.out::println);

System.out.println("####");
list.parallelStream().forEach(System.out::println);

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
int res = numbers.stream().map(i -> i + 1).mapToInt(i -> i).summaryStatistics().getMax();
System.out.println(res);

2.1.9. 日期時間 API

Java 8 中新增了日期時間 API 用來加強對日期時間的處理,其中包括了 LocalDate,LocalTime,LocalDateTime,ZonedDateTime 等等,關於 API 可以參照官方文檔以及這篇博客,寫的很詳細。

https://www.cnblogs.com/muscleape/p/9956754.html

下面是示例代碼。

LocalDate now = LocalDate.now();
System.out.println(now);
System.out.println(now.getYear());
System.out.println(now.getMonth());
System.out.println(now.getDayOfMonth());

LocalTime localTime = LocalTime.now();
System.out.println(localTime);
LocalDateTime localDateTime = now.atTime(localTime);
System.out.println(localDateTime);

2.1.10. Base64 支持

Java 8 標準庫中提供了對 Base 64 編碼的支持。具體 API 見可參照文檔。下面是示例代碼。

String base64 = Base64.getEncoder().encodeToString("aaa".getBytes());
System.out.println(base64);
byte[] bytes = Base64.getDecoder().decode(base64);
System.out.println(new String(bytes));

2.1.11. 並行數組 ParallelSort

Java 8 中提供了對數組的並行操作,包括 parallelSort 等等,具體可參照 API。

Arrays.parallelSort(new int[] {1, 2, 3, 4, 5});

2.1.12. 其他新特性

  • 對併發的增強

  • 在java.util.concurrent.atomic包中還增加了下面這些類:
    DoubleAccumulator
    DoubleAdder
    LongAccumulator
    LongAdder

  • 提供了新的 Nashorn javascript 引擎

  • 提供了 jjs,是一個給予 Nashorn 的命令行工具,可以用來執行 JavaScript 源碼

  • 提供了新的類依賴分析工具 jdeps

  • JVM 的新特性
    JVM內存永久區已經被metaspace替換(JEP 122)。JVM參數 -XX:PermSize 和 –XX:MaxPermSize被XX:MetaSpaceSize 和 -XX:MaxMetaspaceSize代替。

可以看到,Java 8 整體上的改進是很大的,最重要的是引入 Lambda 表達式,簡化代碼。

其他一些改進可參照:

https://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html

2.2 Java 9

參考資料

https://www.runoob.com/java/java9-new-features.html
https://www.twle.cn/c/yufei/java9/java9-basic-process-manage-api.html
https://docs.oracle.com/javase/9/whatsnew/toc.htm

2.2.1 Jigsaw 模塊系統

在 Java 9 以前,打包和依賴都是基於 JAR 包進行的。JRE 中包含了 rt.jar,將近 63M,也就是說要運行一個簡單的 Hello World,也需要依賴這麼大的 jar 包。在 Java 9 中提出的模塊化系統,對這點進行了改善。

關於模塊化系統具體可以看看這篇文章。

https://zhuanlan.zhihu.com/p/24800180

2.2.2 JShell REPL

Java 9 提供了交互式解釋器。有了 JShell 以後,Java 終於可以像 Python,Node.js 一樣在 Shell 中運行一些代碼並直接得出結果了。

2.2.3. 私有接口方法,接口中使用私有方法

Java 9 中可以在接口中定義私有方法。示例代碼如下:

public interface TestInterface {
    String test();

    // 接口默認方法
    default String defaultTest() {
        pmethod();
        return "default";
    }

    private String pmethod() {
        System.out.println("private method in interface");
        return "private";
    }
}

2.2.4. 集合不可變實例工廠方法

在以前,我們想要創建一個不可變的集合,需要先創建一個可變集合,然後使用 unmodifiableSet 創建不可變集合。代碼如下:

Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
set.add("C");

set = Collections.unmodifiableSet(set);
System.out.println(set);

Java 9 中提供了新的 API 用來創建不可變集合。

List<String> list = List.of("A", "B", "C");
Set<String> set = Set.of("A", "B", "C");
Map<String, String> map = Map.of("KA", "VA", "KB", "VB");

2.2.5. 改進 try-with-resources

Java 9 中不需要在 try 中額外定義一個變量。Java 9 之前需要這樣使用 try-with-resources:

InputStream inputStream = new StringBufferInputStream("a");
try (InputStream in = inputStream) {
    in.read();
} catch (IOException e) {
    e.printStackTrace();
}

在 Java 9 中可以直接使用 inputStream 變量,不需要再額外定義新的變量了。

InputStream inputStream = new StringBufferInputStream("a");
try (inputStream) {
    inputStream.read();
} catch (IOException e) {
    e.printStackTrace();
}

2.2.6. 多版本兼容 jar 包

Java 9 中支持在同一個 JAR 中維護不同版本的 Java 類和資源。

2.2.7. 增強了 Stream,Optional,Process API

2.2.8. 新增 HTTP2 Client

2.2.9. 增強 Javadoc,增加了 HTML 5 文檔的輸出,並且增加了搜索功能

2.2.10. 增強 @Deprecated

對 Deprecated 新增了 since 和 forRemoval 屬性

2.2.11. 增強了鑽石操作符 "<>",可以在 匿名內部類中使用了。

在 Java 9 之前,內部匿名類需要指定泛型類型,如下:

Handler<? extends Number> intHandler1 = new Handler<Number>(2) {
}

而在 Java 9 中,可以自動做類型推導,如下:

Handler<? extends Number> intHandler1 = new Handler<>(2) {
}

2.2.12. 多分辨率圖像 API:定義多分辨率圖像API,開發者可以很容易的操作和展示不同分辨率的圖像了。

2.2.13. 改進的 CompletableFuture API

CompletableFuture 類的異步機制可以在 ProcessHandle.onExit 方法退出時執行操作。

其他一些改進可參照:

https://docs.oracle.com/javase/9/whatsnew/toc.htm

2.3 Java 10

參考資料

https://baijiahao.baidu.com/s?id=1594437679552808575&wfr=spider&for=pc
https://blog.csdn.net/visant/article/details/79778967
https://www.oracle.com/technetwork/java/javase/10-relnote-issues-4108729.html

2.3.1. 局部變量類型推斷

局部變量類型推斷可以說是Java 10中最值得注意的特性,這是Java語言開發人員爲了簡化Java應用程序的編寫而採取的又一步,如下圖所示。

這個新功能將爲Java增加一些語法糖 - 簡化它並改善開發者體驗。新的語法將減少與編寫Java相關的冗長度,同時保持對靜態類型安全性的承諾。

局部變量類型推斷將引入"var"關鍵字,也就是你可以隨意定義變量而不必指定變量的類型,如:

將被下面這個新語法所取代:

看完是不是有點JS的即視感???越來越像JS了嗎?!雖然類型推斷在Java中不是一個新概念,但在局部變量中確是很大的一個改進。

說到類型推斷,從JDK 5引進泛型,到JDK 7的"<>"操作符允許不綁定類型而初始化List,再到JDK 8的Lambda表達式,再到現在JDK 10的局部變量類型推斷,Java類型推斷正大刀闊斧的向前發展。

局部變量類型推薦僅限於如下使用場景:

  • 局部變量初始化
  • for循環內部索引變量
  • 傳統的for循環聲明變量

Java官方表示,它不能用於以下幾個地方:

  • 方法參數
  • 構造函數參數
  • 方法返回類型
  • 字段捕獲表達式(或任何其他類型的變量聲明)

2.3.2. GC改進和內存管理

JDK 10中有2個JEP專門用於改進當前的垃圾收集元素。

第一個垃圾收集器接口是(JEP 304),它將引入一個純淨的垃圾收集器接口,以幫助改進不同垃圾收集器的源代碼隔離。

預定用於Java 10的第二個JEP是針對G1的並行完全GC(JEP 307),其重點在於通過完全GC並行來改善G1最壞情況的等待時間。G1是Java 9中的默認GC,並且此JEP的目標是使G1平行。

2.3.3. 線程本地握手(JEP 312)

JDK 10將引入一種在線程上執行回調的新方法,因此這將會很方便能停止單個線程而不是停止全部線程或者一個都不停。

2.3.4. 備用內存設備上的堆分配(JEP 316)

允許HotSpot VM在備用內存設備上分配Java對象堆內存,該內存設備將由用戶指定。

2.3.5. 其他Unicode語言 - 標記擴展(JEP 314)

目標是增強java.util.Locale及其相關的API,以便實現語言標記語法的其他Unicode擴展(BCP 47)。

2.3.6. 基於Java的實驗性JIT編譯器

Oracle希望將其Java JIT編譯器Graal用作Linux / x64平臺上的實驗性JIT編譯器。

2.3.7. 根證書(JEP 319)

這個的目標是在Oracle的Java SE中開源根證書。

2.3.8. 根證書頒發認證

這將使OpenJDK對開發人員更具吸引力,它還旨在減少OpenJDK和Oracle JDK構建之間的差異。

2.3.9. 將JDK生態整合單個存儲庫(JEP 296)

此JEP的主要目標是執行一些內存管理,並將JDK生態的衆多存儲庫組合到一個存儲庫中。

2.3.10. 刪除工具javah(JEP 313)

從JDK中移除了javah工具,這個很簡單並且很重要。

其他可參考:

https://www.oracle.com/technetwork/java/javase/10-relnote-issues-4108729.html#NewFeature

2.4 Java 11

參考資料

https://blog.csdn.net/weixin_38055381/article/details/82865385
https://openjdk.java.net/projects/jdk/11/

2.4.1 本地變量類型推斷

什麼是局部變量類型推斷?

var javastack = "javastack";
System.out.println(javastack);
大家看出來了,局部變量類型推斷就是左邊的類型直接使用 var 定義,而不用寫具體的類型,編譯器能根據右邊的表達式自動推斷類型,如上面的 String 。

var javastack = "javastack";
就等於:
String javastack = "javastack";
 

2.4.2 字符串加強

Java 11 增加了一系列的字符串處理方法,如以下所示。

// 判斷字符串是否爲空白
" ".isBlank(); // true
// 去除首尾空格
" Javastack ".strip(); // "Javastack"
// 去除尾部空格
" Javastack ".stripTrailing(); // " Javastack"
// 去除首部空格
" Javastack ".stripLeading(); // "Javastack "
// 複製字符串
"Java".repeat(3);// "JavaJavaJava"
// 行數統計
"A\nB\nC".lines().count(); // 3


2.4.3 集合加強

自 Java 9 開始,Jdk 裏面爲集合(List/ Set/ Map)都添加了 of 和 copyOf 方法,它們兩個都用來創建不可變的集合,來看下它們的使用和區別。

示例1:

var list = List.of("Java", "Python", "C");
var copy = List.copyOf(list);
System.out.println(list == copy); // true

示例2:

var list = new ArrayList<String>();
var copy = List.copyOf(list);
System.out.println(list == copy); // false

示例1和2代碼差不多,爲什麼一個爲true,一個爲false?

來看下它們的源碼:

static <E> List<E> of(E... elements) {
  switch (elements.length) { // implicit null check of elements
    case 0:
        return ImmutableCollections.emptyList();
    case 1:
        return new ImmutableCollections.List12<>(elements[0]);
    case 2:
        return new ImmutableCollections.List12<>(elements[0], elements[1]);
    default:
        return new ImmutableCollections.ListN<>(elements);
  }
}
static <E> List<E> copyOf(Collection<? extends E> coll) {
    return ImmutableCollections.listCopy(coll);
}
static <E> List<E> listCopy(Collection<? extends E> coll) {
    if (coll instanceof AbstractImmutableList && coll.getClass() != SubList.class) {
        return (List<E>)coll;
    } else {
        return (List<E>)List.of(coll.toArray());
    }
}


可以看出 copyOf 方法會先判斷來源集合是不是 AbstractImmutableList 類型的,如果是,就直接返回,如果不是,則調用 of 創建一個新的集合。

示例2 因爲用的 new 創建的集合,不屬於不可變 AbstractImmutableList 類的子類,所以 copyOf 方法又創建了一個新的實例,所以爲false.

注意:使用of和copyOf創建的集合爲不可變集合,不能進行添加、刪除、替換、排序等操作,不然會報 java.lang.UnsupportedOperationException 異常。

上面演示了 List 的 of 和 copyOf 方法,Set 和 Map 接口都有。

2.4.4 Stream 加強

Stream 是 Java 8 中的新特性,Java 9 開始對 Stream 增加了以下 4 個新方法。

1) 增加單個參數構造方法,可爲null

Stream.ofNullable(null).count(); // 0


2) 增加 takeWhile 和 dropWhile 方法

Stream.of(1, 2, 3, 2, 1)
.takeWhile(n -> n < 3)
.collect(Collectors.toList()); // [1, 2]


從開始計算,當 n < 3 時就截止。

Stream.of(1, 2, 3, 2, 1)
.dropWhile(n -> n < 3)
.collect(Collectors.toList()); // [3, 2, 1]


這個和上面的相反,一旦 n < 3 不成立就開始計算。

3)iterate重載

這個 iterate 方法的新重載方法,可以讓你提供一個 Predicate (判斷條件)來指定什麼時候結束迭代。

如果你對 JDK 8 中的 Stream 還不熟悉,可以看之前分享的這一系列教程。

2.4.5 Optional 加強

Opthonal 也增加了幾個非常酷的方法,現在可以很方便的將一個 Optional 轉換成一個 Stream, 或者當一個空 Optional 時給它一個替代的。

Optional.of("javastack").orElseThrow(); // javastack
Optional.of("javastack").stream().count(); // 1
Optional.ofNullable(null)
.or(() -> Optional.of("javastack"))
.get(); // javastack


2.4.6 InputStream 加強

InputStream 終於有了一個非常有用的方法:transferTo,可以用來將數據直接傳輸到 OutputStream,這是在處理原始數據流時非常常見的一種用法,如下示例。

var classLoader = ClassLoader.getSystemClassLoader();
var inputStream = classLoader.getResourceAsStream("javastack.txt");
var javastack = File.createTempFile("javastack2", "txt");
try (var outputStream = new FileOutputStream(javastack)) {
    inputStream.transferTo(outputStream);
}

2.4.7 HTTP Client API

這是 Java 9 開始引入的一個處理 HTTP 請求的的孵化 HTTP Client API,該 API 支持同步和異步,而在 Java 11 中已經爲正式可用狀態,你可以在 java.net 包中找到這個 API。

來看一下 HTTP Client 的用法:

var request = HttpRequest.newBuilder()
.uri(URI.create("https://javastack.cn"))
.GET()
.build();
var client = HttpClient.newHttpClient();
// 同步
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
// 異步
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);


上面的 .GET() 可以省略,默認請求方式爲 Get!

更多使用示例可以看這個 API,後續有機會再做演示。

現在 Java 自帶了這個 HTTP Client API,我們以後還有必要用 Apache 的 HttpClient 工具包嗎?

2.4.8 化繁爲簡,一個命令編譯運行源代碼

看下面的代碼。

// 編譯

javac Javastack.java

// 運行

java Javastack

在我們的認知裏面,要運行一個 Java 源代碼必須先編譯,再運行,兩步執行動作。而在未來的 Java 11 版本中,通過一個 java 命令就直接搞定了,如以下所示。

java Javastack.java

其他一些改進可以參照:

https://www.oracle.com/technetwork/java/javase/11-relnote-issues-5012449.html#NewFeature

2.5 Java 12

參考資料

https://zhuanlan.zhihu.com/p/59798800

2.5.1 switch 表達式

Java 12 以後,switch 不僅可以作爲語句,也可以作爲表達式。

private String switchTest(int i) {
    return switch (i) {
        case 1 -> "1";
        default -> "0";
    };
}

2.5.2 2 默認CDS歸檔

通過在64位平臺上的默認類列表的幫助下生成CDS歸檔來改進JDK構建過程,從而有效地消除了運行java -Xshare:dump。 此功能的目標包括:

  1. 改進開箱即用的啓動時間
  2. 擺脫使用-Xshare:dump。


2.5.3 Shenandoah GC

Shenandoah是一種垃圾收集(GC)算法,旨在保證低延遲(10 - 500 ms的下限)。 它通過在運行Java工作線程的同時執行GC操作減少GC暫停時間。 使用Shenandoah,暫停時間不依賴於堆的大小。 這意味着無論堆的大小如何,暫停時間都是差不多的。

這是一個實驗性功能,不包含在默認(Oracle)的OpenJDK版本中。

2.5.4 JMH 基準測試

此功能爲JDK源代碼添加了一套微基準測試(大約100個),簡化了現有微基準測試的運行和新基準測試的創建過程。 它基於Java Microbenchmark Harness(JMH)並支持JMH更新。

此功能使開發人員可以輕鬆運行當前的微基準測試併爲JDK源代碼添加新的微基準測試。 可以基於Java Microbenchmark Harness(JMH)輕鬆測試JDK性能。 它將支持JMH更新,並在套件中包含一組(約100個)基準測試。

2.5.5 JVM 常量 API 

JEP 334引入了一個API,用於建模關鍵類文件和運行時artifacts,例如常量池。 此API將包括ClassDesc,MethodTypeDesc,MethodHandleDesc和DynamicConstantDesc等類。此 API 對於操作類和方法的工具很有幫助。

2.5.6 G1的可中斷 mixed GC

此功能通過將Mixed GC集拆分爲強制部分和可選部分,使G1垃圾收集器更有效地中止垃圾收集過程。通過允許垃圾收集過程優先處理強制集,g1可以更多滿足滿足暫停時間目標。

G1是一個垃圾收集器,設計用於具有大量內存的多處理器機器。由於它提高了性能效率,g1垃圾收集器最終將取代cms垃圾收集器。

G1垃圾收集器的主要目標之一是滿足用戶設置的暫停時間。G1採用一個分析引擎來選擇在收集期間要處理的工作量。此選擇過程的結果是一組稱爲GC集的區域。一旦GC集建立並且GC已經開始,那麼G1就無法停止。

如果G1發現GC集選擇選擇了錯誤的區域,它會將GC區域的拆分爲兩部分(強制部分和可選部分)來切換到處理Mix GC的增量模式。如果未達到暫停時間目標,則停止對可選部分的垃圾收集。


2.5.7 G1歸還不使用的內存

此功能的主要目標是改進G1垃圾收集器,以便在不活動時將Java堆內存歸還給操作系統。 爲實現此目標,G1將在低應用程序活動期間定期生成或持續循環檢查完整的Java堆使用情況。

這將立即歸還未使用的部分Java堆內存給操作系統。 用戶可以選擇執行FULL GC以最大化返回的內存量。

2.5.8移除多餘ARM64實現

Java 12將只有一個ARM 64位實現(aarch64)。 目標是刪除所有與arm64實現相關的代碼,同時保留32位ARM端口和64位aarch64實現。

這將把重點轉移到單個64位ARM實現,並消除維護兩個實現所需的重複工作。 當前的JDK 11實現中有兩個64位ARM實現。

其他一些改進可以參照:

https://www.oracle.com/technetwork/java/javase/12-relnote-issues-5211422.html#NewFeature

 

三、其他參考資料

 

https://gudong.name/2019/04/05/android-why-java-harmony.html
https://juejin.im/post/5ca1c747e51d45761c7441fa
https://www.zhihu.com/question/19646618
www.zh.wikipedia.org/wiki/Java版本歷史
https://www.baeldung.com/oracle-jdk-vs-openjdk

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章