目錄
一、JShell
二、Dynamic Class-File Constants類文件新添的一種結構
三、局部變量類型推斷(var ”關鍵字”)
四、新加的一些實用API
1. 新的本機不可修改集合API
2. Stream 加強
3. String 加強
4. Optional 加強
5. 改進的文件API
五、移除的一些其他內容
六、標準Java異步HTTP客戶端
七、更簡化的編譯運行程序
八、Unicode 10
九、Remove the JavaEE and CORBA Moudles
十、JEP : 335 : Deprecate the Nashorn JavaScript Engine?
十一、JEP : 336 : Deprecate the Pack200 Tools and API?
十二、新的Epsilon垃圾收集器
十三、ZGC
十四、支持G1上的并行完全垃圾收集
十五、JEP 331 : Low-Overhead Heap Profiling免費的低耗能飛行記錄儀和堆分析儀
Oracle 表示會對 Java 11 提供大力支持,這一支持將會持續至 2026 年 9 月。這是據 Java 8 以后支持的首個長期版本。jdk9和jdk10不是,所以接下來介紹的有一些可能是在jdk9或者jdk10就已經支持的。
下面介紹的重點關注以下幾個新特性即可:
- JEP 321:HTTP Client 標準化
- JEP 333:ZGC(可伸縮低延遲垃圾收集器)
- JEP 323:Lambda 參數的局部變量語法
- JEP 330:啟動單文件源代碼程序
一、JShell
java9引入了jshell這個交互性工具,讓Java也可以像腳本語言一樣來運行,可以從控制臺啟動 jshell ,在 jshell 中直接輸入表達式并查看其執行結果。當需要測試一個方法的運行效果,或是快速的對表達式進行求值時,jshell 都非常實用。
把環境變量換成Jdk9,然后打開cmd,查看jdk版本為11,輸入jshell就可以開啟
嘗試使用
除了表達式之外,還可以創建 Java 類和方法。jshell 也有基本的代碼完成功能。我們在教人們如何編寫 Java 的過程中,不再需要解釋 “public static void main(String [] args)” 這句廢話。?
二、Dynamic Class-File Constants類文件新添的一種結構
Java的類型文件格式將被拓展,支持一種新的常量池格式:CONSTANT_Dynamic,加載CONSTANT_Dynamic會將創建委托給bootstrap方法。
其目標是降低開發新形式的可實現類文件約束帶來的成本和干擾。
三、局部變量類型推斷(var ”關鍵字”)
var javastack = "javastack";System.out.println(javastack);
局部變量類型推斷就是左邊的類型直接使用 var 定義,而不用寫具體的類型,編譯器能根據右邊的表達式自動推斷類型,如上面的 String 。
var javastack = "javastack";
就等于:
String javastack = "javastack";
在聲明隱式類型的lambda表達式的形參時允許使用var
使用var的好處是在使用lambda表達式時給參數加上注解
(@Deprecated var x, @Nullable var y) -> x.process(y);
四、新加的一些實用API
1. 新的本機不可修改集合API
自 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 elementscase 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 接口都有。
除了更短和更好閱讀之外,這些方法也可以避免您選擇特定的集合實現。在創建后,繼續添加元素到這些集合會導致 “UnsupportedOperationException”
2. 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的元素留下,當 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 (判斷條件)來指定什么時候結束迭代。
3. String 加強
如以下所示。
// 判斷字符串是否為空白" ".isBlank(); // true// 去除首尾空白" Javastack ".strip(); // "Javastack"// 去除尾部空格" Javastack ".stripTrailing(); // " Javastack"// 去除首部空格" Javastack ".stripLeading(); // "Javastack "// 復制字符串"Java".repeat(3);// "JavaJavaJava"// 行數統計"A\nB\nC".lines().count(); // 3
4. Optional 加強
Opthonal 也增加了幾個非常酷的方法,現在可以很方便的將一個 Optional 轉換成一個 Stream, 或者當一個空 Optional 時給它一個替代的。
Optional.of("javastack").orElseThrow(); // javastackOptional.of("javastack").stream().count(); // 1Optional.ofNullable(null).or(() -> Optional.of("javastack")).get(); // javastack
5. 改進的文件API
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);}
五、移除的一些其他內容
1、移除項
- 移除了com.sun.awt.AWTUtilities
- 移除了sun.misc.Unsafe.defineClass,
- 使用java.lang.invoke.MethodHandles.Lookup.defineClass來替代
- 移除了Thread.destroy()以及 Thread.stop(Throwable)方法
- 移除了sun.nio.ch.disableSystemWideOverlappingFileLockCheck、sun.locale.formatasdefault屬性
- 移除了jdk.snmp模塊
- 移除了javafx,openjdk估計是從java10版本就移除了,oracle jdk10還尚未移除javafx,而java11版本則oracle的jdk版本也移除了javafx
- 移除了Java Mission Control,從JDK中移除之后,需要自己單獨下載
- 移除了這些Root Certificates :Baltimore Cybertrust Code Signing CA,SECOM ,AOL and Swisscom
2、廢棄項
- -XX+AggressiveOpts選項
- -XX:+UnlockCommercialFeatures
- -XX:+LogCommercialFeatures選項也不再需要
六、標準Java異步HTTP客戶端
這是 Java 9 開始引入的一個處理 HTTP 請求的的 HTTP Client API,該 API 支持同步和異步,而在 Java 11 中已經為正式可用狀態,你可以在 java.net 包中找到這個 API。
來看一下 HTTP Client 的用法:
public class HTTPClientTest {@Testpublic void testName2() throws Exception {HttpClient client = HttpClient.newHttpClient(); // 創建Http客戶端// 工廠模式,通過build獲得HttpRequest對象HttpRequest request = HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/")).build();// 返回內容的解析器,將返回內容轉化為StringBodyHandler<String> responseBodyHandler = BodyHandlers.ofString();// 異步請求,非阻塞式CompletableFuture<HttpResponse<String>> sendAsync = client.sendAsync(request, responseBodyHandler);sendAsync.thenApply(t -> t.body()).thenAccept(System.out::println);//HttpResponse<String> response = sendAsync.get();//String body = response.body();//System.out.println(body);}@Testpublic void testName() throws Exception {HttpClient client = HttpClient.newHttpClient();HttpRequest request = HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/")).build();BodyHandler<String> responseBodyHandler = BodyHandlers.ofString();// 同步請求,阻塞式HttpResponse<String> response = client.send(request, responseBodyHandler);String body = response.body();System.out.println(body);}
}
?上面的 .GET() 可以省略,默認請求方式為 Get!
七、更簡化的編譯運行程序
JEP 330 : 增強java啟動器支持運行單個java源代碼文件的程序.
一個命令編譯運行源代碼,看下面的代碼。
// 編譯javac Javastack.java// 運行java Javastack
在我們的認知里面,要運行一個 Java 源代碼必須先編譯,再運行,兩步執行動作。而在未來的 Java 11 版本中,通過一個 java 命令就直接搞定了,如以下所示。
java Javastack.java
?注意點 :
- 執行源文件中的第一個類, 第一個類必須包含主方法
- 并且不可以使用別源文件中的自定義類, 本文件中的自定義類是可以使用的.
八、Unicode 10
Unicode 10 增加了8518個字符, 總計達到了136690個字符. 并且增加了4個腳本.同時還有56個新的emoji表情符號
九、Remove the JavaEE and CORBA Moudles
在java11中移除了不太使用的JavaEE模塊和CORBA技術
CORBA來自于二十世紀九十年代,Oracle說,現在用CORBA開發現代Java應用程序已經沒有意義了,維護CORBA的成本已經超過了保留它帶來的好處。
但是刪除CORBA將使得那些依賴于JDK提供部分CORBA API的CORBA實現無法運行。目前還沒有第三方CORBA版本,也不確定是否會有第三方愿意接手CORBA API的維護工作。
在java11中將java9標記廢棄的Java EE及CORBA模塊移除掉,具體如下:
1、xml相關的,
java.xml.ws,
java.xml.bind,
java.xml.ws,
java.xml.ws.annotation,
jdk.xml.bind,
jdk.xml.ws被移除,
只剩下java.xml,java.xml.crypto,jdk.xml.dom這幾個模塊;
2、java.corba,
java.se.ee,
java.activation,
java.transaction被移除,
但是java11新增一個java.transaction.xa模塊
十、JEP : 335 : Deprecate the Nashorn JavaScript Engine?
廢除Nashorn javascript引擎,在后續版本準備移除掉,有需要的可以考慮使用GraalVM?
十一、JEP : 336 : Deprecate the Pack200 Tools and API?
Java5中帶了一個壓縮工具:Pack200,這個工具能對普通的jar文件進行高效壓縮。其 ?實現原理是根據Java類特有的結構,合并常數 ?池,去掉無用信息等來實現對java類的高效壓縮。由于是專門對Java類進行壓縮的,所以對普通文件的壓縮和普通壓縮軟件沒有什么兩樣,但是對于Jar ?文件卻能輕易達到10-40%的壓縮率。這在Java應用部署中很有用,尤其對于移動Java計算,能夠大大減小代碼下載量。
Java5中還提供了這一技術的API接口,你可以將其嵌入到你的程序中使用。使用的方法很簡單,下面的短短幾行代碼即可以實現jar的壓縮和解壓:
壓縮
Packer packer=Pack200.newPacker();OutputStream output=new BufferedOutputStream(new ?FileOutputStream(outfile));packer.pack(new JarFile(jarFile), output);output.close();
解壓
Unpacker unpacker=Pack200.newUnpacker();output=new JarOutputStream(new FileOutputStream(jarFile));unpacker.unpack(pack200File, output);output.close();
Pack200的壓縮和解壓縮速度是比較快的,而且壓縮率也是很驚人的,在我是使用 ?的包4.46MB壓縮后成了1.44MB(0.322%),而且隨著包的越大壓縮率會根據明顯,據說如果jar包都是class類可以壓縮到1/9的大 ?小。其實JavaWebStart還有很多功能,例如可以按不同的jar包進行lazy下載和 單獨更新,設置可以根據jar中的類變動進行class粒度的下載。
但是在java11中廢除了pack200以及unpack200工具以及java.util.jar中的Pack200 API。因為Pack200主要是用來壓縮jar包的工具,由于網絡下載速度的提升以及java9引入模塊化系統之后不再依賴Pack200,因此這個版本將其移除掉。
十二、新的Epsilon垃圾收集器
A NoOp Garbage Collector
JDK上對這個特性的描述是: 開發一個處理內存分配但不實現任何實際內存回收機制的GC, 一旦可用堆內存用完, JVM就會退出.
如果有System.gc()調用, 實際上什么也不會發生(這種場景下和-XX:+DisableExplicitGC效果一樣), 因為沒有內存回收, 這個實現可能會警告用戶嘗試強制GC是徒勞.
用法 : -XX:+UnlockExperimentalVMOptions?-XX:+UseEpsilonGC
class Garbage {int n = (int)(Math.random() * 100);@Overridepublic void finalize() {System.out.println(this + " : " + n + " is dying");}
}
public class EpsilonTest {public static void main(String[] args) {boolean flag = true;List<Garbage> list = new ArrayList<>();long count = 0;while (flag) {list.add(new Garbage());if (list.size() == 1000000 && count == 0) {list.clear();count++;}}System.out.println("程序結束");}
}
如果使用選項-XX:+UseEpsilonGC, 程序很快就因為堆空間不足而退出
使用這個選項的原因 :
提供完全被動的GC實現, 具有有限的分配限制和盡可能低的延遲開銷,但代價是內存占用和內存吞吐量.
眾所周知, java實現可廣泛選擇高度可配置的GC實現. 各種可用的收集器最終滿足不同的需求, 即使它們的可配置性使它們的功能相交. 有時更容易維護單獨的實現, 而不是在現有GC實現上堆積另一個配置選項.
主要用途如下 :
- 1、性能測試(它可以幫助過濾掉GC引起的性能假象)
- 2、內存壓力測試(例如,知道測試用例 應該分配不超過1GB的內存, 我們可以使用-Xmx1g –XX:+UseEpsilonGC, 如果程序有問題, 則程序會崩潰)
非常短的JOB任務(對象這種任務, 接受GC清理堆那都是浪費空間)
1、VM接口測試
2、Last-drop 延遲&吞吐改進
十三、ZGC
ZGC, A Scalable Low-Latency Garbage Collector(Experimental)
ZGC, 這應該是JDK11最為矚目的特性, 沒有之一. 但是后面帶了Experimental, 說明這還不建議用到生產環境.
- ? ? ? ? 1、GC暫停時間不會超過10ms
- ? ? ? ? 2、既能處理幾百兆的小堆, 也能處理幾個T的大堆(OMG)
- ? ? ? ? 3、和G1相比, 應用吞吐能力不會下降超過15%
- ? ? ? ? 4、為未來的GC功能和利用colord指針以及Load barriers優化奠定基礎
- ? ? ? ? 5、初始只支持64位系統
- ? ? ? ? 4、為未來的GC功能和利用colord指針以及Load barriers優化奠定基礎
- ? ? ? ? 3、和G1相比, 應用吞吐能力不會下降超過15%
- ? ? ? ? 2、既能處理幾百兆的小堆, 也能處理幾個T的大堆(OMG)
ZGC的設計目標是:支持TB級內存容量,暫停時間低(<10ms),對整個程序吞吐量的影響小于15%。 將來還可以擴展實現機制,以支持不少令人興奮的功能,例如多層堆(即熱對象置于DRAM和冷對象置于NVMe閃存),或壓縮堆。
GC是java主要優勢之一. 然而, 當GC停頓太長, 就會開始影響應用的響應時間.消除或者減少GC停頓時長, java將對更廣泛的應用場景是一個更有吸引力的平臺. 此外, 現代系統中可用內存不斷增長,用戶和程序員希望JVM能夠以高效的方式充分利用這些內存, 并且無需長時間的GC暫停時間.
ZGC是一個并發, 基于region, 壓縮型的垃圾收集器, 只有root掃描階段會STW, 因此GC停頓時間不會隨著堆的增長和存活對象的增長而變長.
用法 : -XX:+UnlockExperimentalVMOptions –XX:+UseZGC, 因為ZGC還處于實驗階段, 所以需要通過JVM參數來解鎖這個特性
詳細可看:新一代垃圾回收器ZGC的探索與實踐 - 美團技術團隊 (meituan.com)
十四、支持G1上的并行完全垃圾收集
對于 G1 GC,相比于 JDK 8,升級到 JDK 11 即可免費享受到:并行的 Full GC,快速的 CardTable 掃描,自適應的堆占用比例調整(IHOP),在并發標記階段的類型卸載等等。這些都是針對 G1 的不斷增強,其中串行 Full GC 等甚至是曾經被廣泛詬病的短板,你會發現 GC 配置和調優在 JDK11 中越來越方便。
十五、JEP 331 : Low-Overhead Heap Profiling免費的低耗能飛行記錄儀和堆分析儀
通過JVMTI的SampledObjectAlloc回調提供了一個開銷低的heap分析方式
- 提供一個低開銷的, 為了排錯java應用問題, 以及JVM問題的數據收集框架, 希望達到的目標如下 :
- ????????提供用于生產和消費數據作為事件的API
- ????????提供緩存機制和二進制數據格式
- ????????允許事件配置和事件過濾
- ????????提供OS,JVM和JDK庫的事件
- ????????允許事件配置和事件過濾
- ????????提供緩存機制和二進制數據格式
- ????????提供用于生產和消費數據作為事件的API