2018年9月26日,Oracle 官方宣布 Java 11 正式發(fā)布,。這是 Java 大版本周期變化后的第一個長期支持版本(LTS版本,,Long-Term-Support,,持續(xù)支持到2026年9月),非常值得關(guān)注,。
Java11 帶來了 ZGC,、Http Client 等重要特性,,一共包含 17 個 JEP(JDK Enhancement Proposals,JDK 增強提案),。
*本人十分確信 JDK 11 將是一個 企業(yè)不可忽視 的版本(Java8的免費支持時間馬上到期了,,公司在這個時間窗口可以選擇過度到Java11)
不知不覺 JDK 11 已經(jīng)發(fā)布了,,從 9 開始,,JDK 進入了讓人學(xué)不動的更新節(jié)奏,對于廣大 Java 工程師來說,,真是又愛又恨,,Java 演進快速意味著它仍將能夠保持企業(yè)核心技術(shù)平臺的地位,我們對 Java 的投入和飯碗是安全的,,但同時也帶來了學(xué)習(xí),、選擇的困惑。
JDK 更新很重要嗎,?答:非常重要
- 最新的安全更新,,如,安全協(xié)議等基礎(chǔ)設(shè)施的升級和維護,,安全漏洞的及時修補,,這是 Java 成為企業(yè)核心設(shè)施的基礎(chǔ)之一。安全專家清楚,,即使開發(fā)后臺服務(wù),,而不是前端可直接接觸,編程語言的安全性仍然是重中之重,。
- 大量的新特性,、Bug 修復(fù),例如,,容器環(huán)境支持,,GC 等基礎(chǔ)領(lǐng)域的增強。很多生產(chǎn)開發(fā)中的 Hack,,其實升級 JDK 就能解決了,。
- 不斷改進的 JVM,提供接近零成本的性能優(yōu)化
- …
“Easy is cheap”? Java 的進步雖然“容易”獲得,,但莫忽略其價值,,這得益于廠商和 OpenJDK 社區(qū)背后的默默付出。
特性列表
貼一張官方的新特性截圖吧:
本文針對于讀者對關(guān)心,、也是最實用的八大新特性做出一些講解
- 本地變量類型推斷
- 字符串加強
- 集合加強
- Stream 加強
- Optional 加強
- InputStream 加強
- HTTP Client API
- 化繁為簡,,一個命令編譯運行源代碼
1、本地變量類型推斷
什么是局部變量類型推斷,?
var javastack = "javastack";
System.out.println(javastack);
大家看出來了,,局部變量類型推斷就是左邊的類型直接使用 var 定義,,而不用寫具體的類型,編譯器能根據(jù)右邊的表達式自動推斷類型,,如上面的 String ,。
var javastack = "javastack";
就等于:
String javastack = "javastack";
2、字符串加強
Java 11 增加了一系列的字符串處理方法,,如以下所示,。
// 判斷字符串是否為空白
" ".isBlank(); // true
// 去除首尾空格
" Javastack ".strip(); // "Javastack"
// 去除尾部空格
" Javastack ".stripTrailing(); // " Javastack"
// 去除首部空格
" Javastack ".stripLeading(); // "Javastack "
// 復(fù)制字符串
"Java".repeat(3);// "JavaJavaJava"
// 行數(shù)統(tǒng)計
"A\nB\nC".lines().count(); // 3
3、集合加強
自 Java 9 開始,,Jdk 里面為集合(List/ Set/ Map)都添加了 of 和 copyOf 方法,,它們兩個都用來創(chuàng)建不可變的集合,來看下它們的使用和區(qū)別,。
示例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());
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
可以看出 copyOf 方法會先判斷來源集合是不是 AbstractImmutableList 類型的,如果是,,就直接返回,,如果不是,則調(diào)用 of 創(chuàng)建一個新的集合,。
示例2因為用的 new 創(chuàng)建的集合,,不屬于不可變 AbstractImmutableList 類的子類,所以 copyOf 方法又創(chuàng)建了一個新的實例,,所以為false.
注意:使用of和copyOf創(chuàng)建的集合為不可變集合,,不能進行添加、刪除,、替換,、排序等操作,不然會報 java.lang.UnsupportedOperationException 異常,。
上面演示了 List 的 of 和 copyOf 方法,,Set 和 Map 接口都有。
public static void main(String[] args) {
Set<String> names = Set.of("Fred", "Wilma", "Barney", "Betty");
//JDK11之前我們只能這么寫
System.out.println(Arrays.toString(names.toArray(new String[names.size()])));
//JDK11之后 可以直接這么寫了
System.out.println(Arrays.toString(names.toArray(size -> new String[size])));
System.out.println(Arrays.toString(names.toArray(String[]::new)));
}
Collection.toArray(IntFunction)
在java.util.Collection接口中添加了一個新的默認方法toArray(IntFunction),。此方法允許將集合的元素傳輸?shù)叫聞?chuàng)建的所需運行時類型的數(shù)組,。
public static void main(String[] args) {
Set<String> names = Set.of("Fred", "Wilma", "Barney", "Betty");
//JDK11之前我們只能這么寫
System.out.println(Arrays.toString(names.toArray(new String[names.size()])));
//JDK11之后 可以直接這么寫了
System.out.println(Arrays.toString(names.toArray(size -> new String[size])));
System.out.println(Arrays.toString(names.toArray(String[]::new)));
}
新方法是現(xiàn)有toArray(T [])方法的重載,該方法將數(shù)組實例作為參數(shù),。添加重載方法會導(dǎo)致次要源不兼容,。以前,形式為coll.toArray(null)的代碼將始終解析為現(xiàn)有的toArray方法,。使用新的重載方法,,此代碼現(xiàn)在不明確,將導(dǎo)致編譯時錯誤,。 (這只是源不兼容?,F(xiàn)有的二進制文件不受影響,。)應(yīng)該更改模糊代碼以將null轉(zhuǎn)換為所需的數(shù)組類型,例如toArray((Object [])null)或其他一些數(shù)組類型,。請注意,,將null傳遞給toArray方法指定為拋出NullPointerException。
4,、Stream 加強
Stream 是 Java 8 中的新特性,,Java 9 開始對 Stream 增加了以下 4 個新方法。
- 增加單個參數(shù)構(gòu)造方法,,可為null
Stream.ofNullable(null).count(); // 0
//JDK8木有ofNullable方法哦
源碼可看看:
/**
* @since 9
*/
public static<T> Stream<T> ofNullable(T t) {
return t == null ? Stream.empty()
: StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}
- 增加 takeWhile 和 dropWhile 方法
Stream.of(1, 2, 3, 2, 1)
.takeWhile(n -> n < 3)
.collect(Collectors.toList()); // [1, 2]
takeWhile表示從開始計算,,當(dāng) n < 3 時就截止,。
Stream.of(1, 2, 3, 2, 1)
.dropWhile(n -> n < 3)
.collect(Collectors.toList()); // [3, 2, 1]
dropWhile這個和上面的相反,,一旦 n < 3 不成立就開始計算
3)iterate重載
這個 iterate 方法的新重載方法,可以讓你提供一個 Predicate (判斷條件)來指定什么時候結(jié)束迭代,。
public static void main(String[] args) {
// 這構(gòu)造的是無限流 JDK8開始
Stream.iterate(0, (x) -> x + 1);
// 這構(gòu)造的是小于10就結(jié)束的流 JDK9開始
Stream.iterate(0, x -> x < 10, x -> x + 1);
}
5,、Optional 加強
Opthonal 也增加了幾個非常酷的方法,,現(xiàn)在可以很方便的將一個 Optional 轉(zhuǎn)換成一個 Stream, 或者當(dāng)一個空 Optional 時給它一個替代的,。
Optional.of("javastack").orElseThrow(); // javastack
Optional.of("javastack").stream().count(); // 1
Optional.ofNullable(null)
.or(() -> Optional.of("javastack"))
.get(); // javastack
or方法和stream方法顯然都是新增的
6、InputStream 加強
InputStream 終于有了一個非常有用的方法:transferTo,,可以用來將數(shù)據(jù)直接傳輸?shù)?OutputStream,,這是在處理原始數(shù)據(jù)流時非常常見的一種用法,如下示例,。
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);
}
7,、HTTP Client API(重磅)
在java9及10被標(biāo)記incubator的模塊jdk.incubator.httpclient,在java11被標(biāo)記為正式,,改為.http模塊,。
這是 Java 9 開始引入的一個處理 HTTP 請求的的孵化 HTTP Client API,該 API 支持同步和異步,,而在 Java 11 中已經(jīng)為正式可用狀態(tài),,你可以在 包中找到這個 API。
來看一下 HTTP Client 的用法:
var request = HttpRequest.newBuilder()
.uri(URI.create("https://"))
.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,后續(xù)有機會再做演示,。
現(xiàn)在 Java 自帶了這個 HTTP Client API,,我們以后還有必要用 Apache 的 HttpClient 工具包嗎?我覺得沒啥必要了
8,、化繁為簡,,一個命令編譯運行源代碼
看下面的代碼,。
// 編譯
javac Javastack.java
// 運行
java Javastack
在我們的認知里面,要運行一個 Java 源代碼必須先編譯,,再運行,,兩步執(zhí)行動作。而在未來的 Java 11 版本中,,通過一個 java 命令就直接搞定了,,如以下所示。
java Javastack.java
移除項
- 移除了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
廢棄項
- 廢棄了Nashorn JavaScript Engine
- 廢棄了-XX+AggressiveOpts選項
- -XX:+UnlockCommercialFeatures以及-XX:+LogCommercialFeatures選項也不- 再需要
- 廢棄了Pack200工具及其API
說到最后
java11是java改為6個月發(fā)布一版的策略之后的第一個LTS(Long-Term Support)版本(oracle版本才有LTS),,這個版本最主要的特性是:在模塊方面移除Java EE以及CORBA模塊,,在JVM方面引入了實驗性的ZGC,在API方面正式提供了HttpClient類,。
從java11版本開始,,不再單獨發(fā)布JRE或者Server JRE版本了,有需要的可以自己通過jlink去定制runtime image
備注:ZGC作為實驗性功能包含在內(nèi),。要啟用它,,因此需要將-XX:+ UnlockExperimentalVMOptions選項與-XX:+ UseZGC選項結(jié)合使用。
ZGC的這個實驗版具有以下限制:
- 它僅適用于Linux / x64,。
- 不支持使用壓縮的oops和/或壓縮的類點,。默認情況下禁用-XX:+UseCompressedOops和-XX:+UseCompressedClassPointers選項。啟用它們將不起作用,。
- 不支持類卸載,。默認情況下禁用-XX:+ ClassUnloading和-XX:+ - - ClassUnloadingWithConcurrentMark選項。啟用它們將不起作用,。
- 不支持將ZGC與Graal結(jié)合使用,。
|