Java11新特性一览
Java 11是自Java 8以來的又一個LTS版本,是目前全球使用最多的LTS版本之一。下邊我們看一下JAVA11的新特性
字符串API增強
在Java 11中,針對String的操作進一步得到加強。避免我們在很常見的場景中引入額外的、復雜的API。
isBlank()
用來判斷字符串是不是空字符"“或者trim()之后(” ")為空字符:
String blankStr = " ";// trueboolean trueVal = blankStr.isBlank();
lines()
將一個字符串按照行終止符(換行符\n或者回車符\r)進行分割,并將分割為Stream流:
String newStr = "Hello Java 11 \n felord.cn \r 2021-09-28";?Stream<String> lines = newStr.lines();lines.forEach(System.out::println);
// Hello Java 11 // 張三李四周吳鄭王 // 2022-18-44
strip()
去除字符串前后的“全角和半角”空白字符:
String str = "HELLO\u3000";// str = 6System.out.println("str = " + str.length());// trim = 6System.out.println("trim = " + str.trim().length());// strip = 5System.out.println("strip = " + str.strip().length());
從上面也看出來了差別,trim()只能去除半角空白符。
strip()方法還有兩個變種,stripLeading()用來去除前面的全角半角空白符;stripTrailing()用來去除尾部的全角半角空白符。
repeat(n)
按照給定的次數重復串聯字符串的內容:
String str = "HELLO";// 空字符String empty = str.repeat(0);// HELLOString repeatOne = str.repeat(1);// HELLOHELLOString repeatTwo = str.repeat(2);
集合轉對應類型的數組
之前想集合轉對應的數組很麻煩,要么用迭代;要么用Stream流,現在你可以這樣:
List<String> sampleList = Arrays.asList("張三", "java 11");// array = {"張三", "java 11"};String[] array = sampleList.toArray(String[]::new);
斷言取反
java.util.function.Predicate是我們很常用的斷言謂詞函數。在以前取反我們得借助于!符號,到了Java 11我們可以借助于其靜態方法not來實現,這樣語義就更加清晰了:
List<String> sampleList = Arrays.asList("張三", "java 11","jack");// [jack]List<String> result = sampleList.stream()// 過濾以j開頭的字符串.filter(s -> s.startsWith("j"))// 同時不包含11的字符串.filter(Predicate.not(s -> s.contains("11"))).collect(Collectors.toList());
var可以用于修飾Lambda局部變量
在Java 10中引入的var來進行類型推斷。在Java 10中它不能用于修飾Lambda表達式的入參,其實對于一個Lambda表達式來說它入參的類型其實是可以根據上下文推斷出來的。拿上面的例子來說,s -> s.startsWith(“j”)中的s肯定是字符串類型,因此在Java 11中var可以用于修飾Lambda局部變量:
List<String> sampleList = Arrays.asList("張三", "java 11","jack");List<String> result = sampleList.stream()// 過濾以j開頭的字符串.filter((@NotNull var s) -> s.startsWith("j"))// 同時不包含11的字符串.filter(Predicate.not((@NotNull var s) -> s.contains("11"))).collect(Collectors.toList());
如果我們不聲明var就沒有辦法為輸入參數添加@NotNull注解。
文件中讀寫字符串內容更方便
Java 11中可以更輕松地從文件中讀取和寫入字符串內容了,我們可以通過Files工具類提供的新的靜態方法readString和writeString分別進行讀寫文件的字符串內容,放在之前老麻煩了,特別是對IO流不熟悉的同學來說。現在簡單幾行就搞定了:
String dir= "C://yourDir/hello.txt";
// 寫入文件Path path = Files.writeString(Path.of(dir), "hello java 11");
// 讀取文件String fileContent = Files.readString(path);// hello java 11System.err.println(fileContent);
嵌套類的訪問控制規則
Java 11之前,內部嵌套類訪問外部類的私有屬性和方法是可行的:
public class Outer {private int outerInt;class Inner {public void printOuterField() {System.out.println("Outer field = " + outerInt);}}
}
但是如果你通過反射API實現內部類訪問外部類的私有屬性和方法就會拋出IllegalStateException異常。Java 11 修復了反射不能訪問的問題.
JVM 訪問規則不允許嵌套類之間進行私有訪問。我們能通過常規方式可以訪問是因為 JVM 在編譯時為我們隱式地創建了橋接方法。Java 11 中引入了兩個新的屬性:一個叫做 NestMembers 的屬性,用于標識其它已知的靜態 nest 成員;另外一個是每個 nest 成員都包含的 NestHost 屬性,用于標識出它的 nest 宿主類。在編譯期就映射了雙方的寄宿關系,不再需要橋接了。
HttpClient支持HTTP2
Java 9 引入了一個新的醞釀中的 HttpClient API 來處理 HTTP 請求。從 Java 11開始,這個API 現在是最終版本,可以在標準庫包 java.net 中使用。讓我們來實驗一下這個 API 能做些什么。
var request = HttpRequest.newBuilder().uri(URI.create("https://baidu.com")).GET().build();var client = HttpClient.newHttpClient();HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.println(response.body());
// <html>
// <head><title>302 Found</title></head>
// <body bgcolor="white">
// <center><h1>302 Found</h1></center>
// <hr><center>bfe/1.0.8.18</center>
// </body>
// </html>
同樣的請求可以異步執行。調用 sendAsync 不會阻塞當前線程,而是返回一個CompletableFuture 來構建異步操作管道。
var request = HttpRequest.newBuilder().uri(URI.create("https://baidu.com")).build();
var client = HttpClient.newHttpClient();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body).thenAccept(System.out::println);
數據流 Streams
流是在 Java 8 中引入的,現在增加了三個新方法。Stream.ofNullable 從單個元素構造流:
Stream.ofNullable(null).count() // 0
dropWhile 和 takeWhile 方法都接受一個謂詞來決定從流中放棄或選用哪些元素
Stream.of(1, 2, 3, 2, 1).dropWhile(n -> n < 3).collect(Collectors.toList()); // [3, 2, 1]Stream.of(1, 2, 3, 2, 1).takeWhile(n -> n < 3).collect(Collectors.toList()); // [1, 2]
Optionals
Optionals 增加了非常方便的新方法,例如,你現在可以簡單地將 Optionals 轉換為流,或者提供另一個 Optionals 作為空 Optionals 的回調
Optional.of("foo").orElseThrow(); // foo
Optional.of("foo").stream().count(); // 1
Optional.ofNullable(null).or(() -> Optional.of("fallback")).get();
Epsilon垃圾收集器
JDK上對這個特性的描述是:開發一個處理內存分配但不實現任何實際內存回收機制的GC,一旦可用堆內存用完,JVM就會退出。我們可以來嘗試著使用一下它,首先我們編寫一段程序:
public class EpsilonTest {public static void main(String[] args) throws Exception {var list = new ArrayList<>();boolean flag = true;int count = 0;while (flag) {list.add(new Garbage());if (count++ == 500) {list.clear();}}}
}class Garbage {private double d1 = 1;private double d2 = 2;/*** GC在清除本對象時會調用該方法*/@Overrideprotected void finalize() throws Throwable {System.out.println(this + " collecting");}
}
這是一個無限循環的程序,循環體不斷創建Garbage對象并放入集合,當循環次數達到500時將集合清空,此時的500個對象均為垃圾,會被GC清理,清理時調用finalize()方法打印信息。運行這段程序,結果如下:
...
com.itcast.Garbage@1e9c634c collecting
java.lang.OutOfMemoryError: Java heap spaceat com.itcast.EpsilonTest.main(EpsilonTest.java:11)
com.itcast.Garbage@1174213e collecting
com.itcast.Garbage@2029a4b8 collecting
...
當程序執行到某一刻時,內存溢出,程序終止?,F在我們來使用一下Epsilon,啟動參數: UnlockExperimentalVMOptions:解鎖隱藏的虛擬機參數。
-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xms100m -Xmx100m
運行程序后,結果如下:
程序開始
Terminating due to java.lang.OutOfMemoryError: Java heap space
會發現,控制臺只輸出了這么一句,說明被清除的集合中的對象并沒有被回收,而且內存溢出的速度也非???#xff0c;這說明該GC是并不會回收垃圾,那么它有什么作用呢?它提供完全被動的GC實現,具有有限的分配限制和盡可能低的延遲開銷,但代價是內存占用和內存吞吐量,它的主要用途有以下幾個方面:
- 性能測試(它可以幫助過濾掉GC引起的性能假象)
- 內存壓力測試
- 非常短的JOB任務
- VM接口測試
ZGC垃圾回收器
據說這是JDK11最為矚目的特性,沒有之一,是最重磅的升級,那么ZGC的優勢在哪里呢?
- GC暫停時間不會超過10毫秒
- 既能處理幾百兆的小堆,也能處理幾個T的大堆
- 和G1相比,應用吞吐能力不會下降超過15%
- 為未來的GC功能和利用colord指針以及Load barriers優化奠定了基礎
ZGC是一個并發、基于region、壓縮型的垃圾收集器,只有root掃描階段會STW(strop the world,停止所有線程),因此ZGC的停頓時間不會隨著堆的增長和存活對象的增長而變長。用法:-XX:UnlockExperimentalVMOptions -XX:+UseZGC雖然功能如此強大,但很遺憾的是,在Windows系統的JDK中并沒有提供ZGC,所以也就沒有辦法測試了
總結
以上是生活随笔為你收集整理的Java11新特性一览的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 隔空投送失败是为什么
- 下一篇: 程序员入门必读 的十大编程语言你了解吗