Java語言特性系列
序
本文主要講述一下Java12的新特性
版本號
java -version
openjdk version "12" 2019-03-19
OpenJDK Runtime Environment (build 12+33)
OpenJDK 64-Bit Server VM (build 12+33, mixed mode)
複製程式碼
從version資訊可以看出是build 12+33
特性列表
Shenandoah GC是一個面向low-pause-time的垃圾收集器,它最初由Red Hat實現,支援aarch64及amd64 architecture;ZGC也是面向low-pause-time的垃圾收集器,不過ZGC是基於colored pointers來實現,而Shenandoah GC是基於brooks pointers來實現;如果要使用Shenandoah GC需要編譯時--with-jvm-features選項帶有shenandoahgc,然後啟動時使用-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC
在jdk原始碼裡頭新增了一套基礎的microbenchmarks suite
對switch進行了增強,除了使用statement還可以使用expression,比如原來的寫法如下:
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
System.out.println(6);
break;
case TUESDAY:
System.out.println(7);
break;
case THURSDAY:
case SATURDAY:
System.out.println(8);
break;
case WEDNESDAY:
System.out.println(9);
break;
}
複製程式碼
現在可以改為如下寫法:
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
複製程式碼
以及在表示式返回值
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
複製程式碼
對於需要返回值的switch expression要麼正常返回值要麼丟擲異常,以下這兩種寫法都是錯誤的
int i = switch (day) {
case MONDAY -> {
System.out.println("Monday");
// ERROR! Block doesn't contain a break with value
}
default -> 1;
};
i = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY:
break 0;
default:
System.out.println("Second half of the week");
// ERROR! Group doesn't contain a break with value
};
複製程式碼
新增了JVM Constants API,具體來說就是java.base模組新增了java.lang.constant包,引入了ConstantDesc介面(
ClassDesc、MethodTypeDesc、MethodHandleDesc這幾個介面直接繼承了ConstantDesc介面
)以及Constable介面;ConstantDesc介面定義了resolveConstantDesc方法,Constable介面定義了describeConstable方法;String、Integer、Long、Float、Double均實現了這兩個介面,而EnumDesc實現了ConstantDesc介面
64-bit Arm platform (arm64),也可以稱之為aarch64;之前JDK有兩個關於aarch64的實現,分別是src/hotspot/cpu/arm以及open/src/hotspot/cpu/aarch64,它們的實現重複了,為了集中精力更好地實現aarch64,該特性在原始碼中刪除了open/src/hotspot/cpu/arm中關於64-bit的實現,保留其中32-bit的實現,於是open/src/hotspot/cpu/aarch64部分就成了64-bit ARM architecture的預設實現
java10的新特性JEP 310: Application Class-Data Sharing擴充套件了JDK5引入的Class-Data Sharing,支援application的Class-Data Sharing;Class-Data Sharing可以用於多個JVM共享class,提升啟動速度,最早只支援system classes及serial GC,JDK9對其進行擴充套件以支援application classes及其他GC演算法,並在JDK10中開源出來(
以前是commercial feature
);JDK11將-Xshare:off改為預設-Xshare:auto,以更加方便使用CDS特性;JDK12的這個特性即在64-bit平臺上編譯jdk的時候就預設在${JAVA_HOME}/lib/server目錄下生成一份名為classes.jsa的預設archive檔案(大概有18M
)方便大家使用
G1在garbage collection的時候,一旦確定了collection set(
CSet
)開始垃圾收集這個過程是without stopping的,當collection set過大的時候,此時的STW時間會過長超出目標pause time,這種情況在mixed collections時候比較明顯。這個特性啟動了一個機制,當選擇了一個比較大的collection set,允許將其分為mandatory及optional兩部分(當完成mandatory的部分,如果還有剩餘時間則會去處理optional部分
)來將mixed collections從without stopping變為abortable,以更好滿足指定pause time的目標
G1目前只有在full GC或者concurrent cycle的時候才會歸還記憶體,由於這兩個場景都是G1極力避免的,因此在大多數場景下可能不會及時會還committed Java heap memory給作業系統。JDK12的這個特性新增了兩個引數分別是G1PeriodicGCInterval及G1PeriodicGCSystemLoadThreshold,設定為0的話,表示禁用。當上一次garbage collection pause過去G1PeriodicGCInterval(
milliseconds
)時間之後,如果getloadavg()(one-minute
)低於G1PeriodicGCSystemLoadThreshold指定的閾值,則觸發full GC或者concurrent GC(如果開啟G1PeriodicGCInvokesConcurrent
),GC之後Java heap size會被重寫調整,然後多餘的記憶體將會歸還給作業系統
細項解讀
上面列出的是大方面的特性,除此之外還有一些api的更新及廢棄,主要見JDK 12 Release Notes,這裡舉幾個例子。
新增項
- 支援unicode 11
- 支援Compact Number Formatting
使用例項如下
@Test
public void testCompactNumberFormat(){
var cnf = NumberFormat.getCompactNumberInstance(Locale.CHINA, NumberFormat.Style.SHORT);
System.out.println(cnf.format(1_0000));
System.out.println(cnf.format(1_9200));
System.out.println(cnf.format(1_000_000));
System.out.println(cnf.format(1L << 30));
System.out.println(cnf.format(1L << 40));
System.out.println(cnf.format(1L << 50));
}
複製程式碼
輸出
1萬
2萬
100萬
11億
1兆
1126兆
複製程式碼
- String支援transform、indent操作
@Test
public void testStringTransform(){
System.out.println("hello".transform(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.hashCode();
}
}));
}
@Test
public void testStringIndent(){
System.out.println("hello".indent(3));
}
複製程式碼
- Files新增mismatch方法
@Test
public void testFilesMismatch() throws IOException {
FileWriter fileWriter = new FileWriter("/tmp/a.txt");
fileWriter.write("a");
fileWriter.write("b");
fileWriter.write("c");
fileWriter.close();
FileWriter fileWriterB = new FileWriter("/tmp/b.txt");
fileWriterB.write("a");
fileWriterB.write("1");
fileWriterB.write("c");
fileWriterB.close();
System.out.println(Files.mismatch(Path.of("/tmp/a.txt"),Path.of("/tmp/b.txt")));
}
複製程式碼
- Collectors新增teeing方法用於聚合兩個downstream的結果
@Test
public void testCollectorTeeing(){
var result = Stream.of("Devoxx","Voxxed Days","Code One","Basel One")
.collect(Collectors.teeing(Collectors.filtering(n -> n.contains("xx"),Collectors.toList()),
Collectors.filtering(n -> n.endsWith("One"),Collectors.toList()),
(List<String> list1, List<String> list2) -> List.of(list1,list2)
));
System.out.println(result.get(0));
System.out.println(result.get(1));
}
複製程式碼
- CompletionStage新增exceptionallyAsync、exceptionallyCompose、exceptionallyComposeAsync方法
@Test
public void testExceptionallyAsync() throws ExecutionException, InterruptedException {
LOGGER.info("begin");
int result = CompletableFuture.supplyAsync(() -> {
LOGGER.info("calculate");
int i = 1/0;
return 100;
}).exceptionallyAsync((t) -> {
LOGGER.info("error error:{}",t.getMessage());
return 0;
}).get();
LOGGER.info("result:{}",result);
}
複製程式碼
-
JDK12之前CompletionStage只有一個exceptionally,該方法體在主執行緒執行,JDK12新增了exceptionallyAsync、exceptionallyComposeAsync方法允許方法體在非同步執行緒執行,同時新增了exceptionallyCompose方法支援在exceptionally的時候構建新的CompletionStage
-
Allocation of Old Generation of Java Heap on Alternate Memory Devices
G1及Parallel GC引入experimental特性,允許將old generation分配在諸如NV-DIMM memory的alternative memory device
- ZGC: Concurrent Class Unloading
ZGC在JDK11的時候還不支援class unloading,JDK12對ZGC支援了Concurrent Class Unloading,預設是開啟,使用-XX:-ClassUnloading可以禁用
- 新增-XX:+ExtensiveErrorReports
-XX:+ExtensiveErrorReports可以用於在jvm crash的時候收集更多的報告資訊到hs_err.log檔案中,product builds中預設是關閉的,要開啟的話,需要自己新增-XX:+ExtensiveErrorReports引數
- 新增安全相關的改進
支援java.security.manager系統屬性,當設定為disallow的時候,則不使用SecurityManager以提升效能,如果此時呼叫System.setSecurityManager則會丟擲UnsupportedOperationException keytool新增-groupname選項允許在生成key pair的時候指定一個named group 新增PKCS12 KeyStore配置屬性用於自定義PKCS12 keystores的生成 Java Flight Recorder新增了security-related的event 支援ChaCha20 and Poly1305 TLS Cipher Suites
- jdeps Reports Transitive Dependences
jdeps的--print-module-deps, --list-deps, 以及--list-reduce-deps選項得到增強,新增--no-recursive用於non-transitive的依賴分析,--ignore-missing-deps用於suppress missing dependence errors
移除項
- 移除com.sun.awt.SecurityWarnin
- 移除FileInputStream、FileOutputStream、Java.util.ZipFile/Inflator/Deflator的finalize方法
- 移除GTE CyberTrust Global Root
- 移除javac的-source, -target對6及1.6的支援,同時移除--release選項
廢棄項
- 廢棄的API列表見deprecated-list
- 廢棄-XX:+/-MonitorInUseLists選項
- 廢棄Default Keytool的-keyalg值
已知問題
- Swing不支援GTK+ 3.20及以後的版本
- 在使用JVMCI Compiler(
比如Graal
)的時候,JVMTI的can_pop_frame及can_force_early_return的capabilities是被禁用的
其他事項
- 如果使用者沒有指定user.timezone且從作業系統獲取的為空,那麼user.timezone屬性的初始值為空變為null
- java.net.URLPermission的行為發生輕微變化,以前它會忽略url中的query及fragment部分,這次改動新增query及fragment部分,即
scheme : // authority [ / path ]
變動為scheme : // authority [ / path ] [ ignored-query-or-fragment ]
- javax.net.ssl.SSLContext API及Java Security Standard Algorithm Names規範移除了必須實現TLSv1及TLSv1.1的規定
小結
- java12不是LTS(
Long-Term Support
)版本(oracle版本才有LTS
),oracle對該版本的support週期為6個月。這個版本主要有幾個更新點,一個是語法層更新,一個是API層面的更新,另外主要是GC方面的更新。 - 語法層面引入了preview版本的Switch Expressions;API層面引入了JVM Constants API,引入CompactNumberFormat,讓NumberFormat支援COMPACTSTYLE,對String、Files、Collectors、CompletionStage等新增方法;GC方面引入了experimental版本的Shenandoah GC,不過oracle build的openjdk沒有enable Shenandoah GC support;另外主要對ZGC及G1 GC進行了改進
- 其中JDK12對ZGC支援了Concurrent Class Unloading,預設是開啟,使用-XX:-ClassUnloading可以禁用;對於G1 GC則新增支援Abortable Mixed Collections以及Promptly Return Unused Committed Memory特性
doc
- openjdk 12
- JDK 12 Release Notes
- Java 12 Released with Experimental Switch Expressions and Shenandoah GC
- Definitive Guide To Java 12
- Definitive Guide To Switch Expressions In Java 12
- JVM Class Data Sharing
- JEP 310: Application Class-Data Sharing
- Improve Launch Times On Java 10 With Application Class-Data Sharing
- Make -Xshare:auto the default for server VM
- Using application class-data sharing
- Java Performance Tuning News February 2018
- JDK 12 Security Enhancements