您好,我是湘王,這是我的部落格園,歡迎您來,歡迎您再來~
雖然到目前為止Java的版本更新還沒有什麼驚天動地的改變,但總是會冒出一些有趣的小玩意。前面列舉了Java9和Java10的一些特色,現在接著來擼一擼Java11之後的新奇特。
Java9更新了Http 2 Client,也說過先不著急看,因為在後續版本中語法會變。這不,到Java11就實現了。最直接的變化就是http相關包名由Java 9的jdk.incubator.http改為Java 11的java.net.http。感覺java.net.http才像那麼回事,incubator是個啥呢?好像完全和http不沾邊。本著好奇害死貓的精神,查了下incubator的意思:
好吧,原來JDK工作組認為http在Java9中出現是個「早產兒」。
再來看看Java11對http的更新,例如通過http存取某度的主頁:
// 包名由Java 9的jdk.incubator.http改為Java 11的java.net.http
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://www.baidu.com/"))
.build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
(現在Lambda表示式幾乎無處不在了,如果還不會的話搞不好以後Java程式碼都看不懂了)
Java11有如下變更:
除了http之外,比較有用的就兩個:基於巢狀的存取控制(181)和飛行記錄器(328)。
所謂基於巢狀的存取控制,其實就是能夠判斷某個類是不是另一個類的巢狀類。
/**
* 基於巢狀的存取控制
*
* @author 湘王
*/
public class OuterClass {
class InnerClass {
public InnerClass() {
}
public void printOuterInt() {
System.out.println("InnerClass");
}
}
public static void main(String[] args) {
Class<?> outerClass = OuterClass.class;
// 得到宿主類
Class<?> clazz1 = InnerClass.class.getNestHost();
System.out.println(clazz1.getName());
// 得到內部類成員
Class<?>[] clazz2 = OuterClass.class.getNestMembers();
for (Class<?> class1 : clazz2) {
System.out.println(class1.getName());
// 判斷類是否是某個類的巢狀類
System.out.println(outerClass.isNestmateOf(class1));
}
}
}
就是這樣子用的。
所謂飛行記錄器,就是模仿飛機上的黑匣子,是一種低開銷的事件資訊收集框架,它原來是JDK商業版(是一種大廠之間合作收費的版本)中的一項分析工具,主要資料來源於應用程式、JVM和OS,是在故障發生後,能夠從事件記錄檔案中提取出有用資訊對故障進行分析。到了Java11,它索性就免費了。
/**
* 飛行記錄器
*
* @author 湘王
*/
public class FlightRecorder {
@Label("Hello World")
@Description("Helps the programmer getting started")
static class HelloWorld extends Event {
@Label("Message")
String message;
}
public static void main(String[] args) {
HelloWorld event = new HelloWorld();
event.message = "hello, world!";
event.commit();
}
}
執行上述程式碼時加上JVM引數:
-XX:StartFlightRecording=duration=1s, filename=C:\\recording.jfr
然後再通過飛行記錄器來讀取資料:
// 讀取飛行記錄資料
final Path path = Paths.get("C:\\recording.jfr");
List<RecordedEvent> recordedEvents;
try {
recordedEvents = RecordingFile.readAllEvents(path);
for (RecordedEvent event : recordedEvents) {
System.out.println(event.getStartTime() + "," + event.getValue("message"));
}
} catch (IOException e) {
e.printStackTrace();
}
至於Java11中的其他更新項:
1、Epsilon GC(no-op GC,318)
2、ZGC可伸縮低延遲垃圾收集器(333)
3、支援TLSv1.3協定(332)
4、動態類檔案常數(309)
我個人覺得沒啥特別的。
Java11之後,感覺Java是為了更新而更新,新奇特不多。差不多每個版本多那麼一個小玩意。
這是Java12的更新:
Java12多了一個switch表示式(325):
@SuppressWarnings("preview")
public static void main(String[] args) {
DayOfWeek day = LocalDate.now().getDayOfWeek();
int number = switch (day) {
case MONDAY, WEDNESDAY, FRIDAY, SUNDAY -> 1;
case TUESDAY, THURSDAY, SATURDAY -> 2;
};
System.out.println(number);
switch (day) {
case MONDAY:
System.out.println("星期一");
break;
case TUESDAY:
System.out.println("星期二");
break;
case WEDNESDAY:
System.out.println("星期三");
break;
case THURSDAY:
System.out.println("星期四");
break;
case FRIDAY:
System.out.println("星期五");
break;
case SATURDAY:
System.out.println("星期六");
break;
case SUNDAY:
System.out.println("星期日");
break;
}
}
Java13整體上與Java12差不多,沒什麼變化:
唯一比較引人注目的就是模仿Python搞了一個三引號的文字塊(而且之前剛出來的時候還只能在idea中實驗):
然後再敲程式碼:
@SuppressWarnings("preview")
public static void main(String[] args) {
// 文字塊
String text = """
Lorem ipsum dolor sit amet, consectetur adipiscing
elit, sed do eiusmod tempor incididunt ut labore
et dolore magna aliqua.
""";
System.out.println(text);
}
Java14在Java13基礎上就更新的比較多了:
其中有一個可能會比較有用的特性:NullPointerExceptions增強(358):
例如碼農可能會寫這樣的程式碼:
通常會有這樣的程式碼:
User user = new User();
String cityname = user.getDetailInfo().getAddress().getCity().getName();
System.out.println(cityname);
在呼叫過程中,如果User、DetailInfo、Address、City中有任何一個是null,那麼就會丟擲NullPointerExceptions,但是比較難於確定倒底是哪一個物件為null。列印出來的異常資訊是:
但在Java14中,卻可以很準確地知道NPE發生在哪裡:
先通過JVM引數開啟這項特性:-XX:+ShowCodeDetailsInExceptionMessages
再次執行相同的程式碼,可以看到列印出的異常資訊變了:
不過有個條件:如果程式碼中已有捕獲的NullPointerExceptions,那麼就不會執行異常計算。也就是說如果使用了try...catch的話,那這項特性就沒用了。
final class Point {
public final int x;
public final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
// state-based implementations of equals, hashCode, toString
// nothing else
}
Java14另一個比較有用的特性是Record型別。對,你沒看錯,不是類,是型別,是和Integer、String一樣的型別,叫Record。那什麼是Record型別呢?
以前在定義一個JavaBean的時候,通常都會附帶定義一些建構函式、getter/setter、equals()、hashCode()以及toString()等無用且無聊的程式碼。所以出現了第三方類庫Lombok,它就可以自動生成這些程式碼。例如:
Record型別就是為了定義這種「純資料載體」而生的:
record Name(String firstname, String lastname) { }
record Address(String... address) { }
record User(Name name, Address address, int age, ...) {
static int x;
}
Java15在Java14基礎上又做了一系列更新:
Java15比較突出的是增加一個稱之為「封印類」(360,特性編號也是360,不會是巧合吧)的安全類。所謂封印類,其實就是告訴外界,只有哪些類或介面可以繼承或實現它。
// 這段程式碼宣告了一個Shape介面,而permits列表限制了只有「Circle」和「Rectangle」可以實現Shape
// 任何其他嘗試擴充套件Shape的類或介面都將收到編譯錯誤
sealed interface Shape permits Circle, Rectangle {
}
封印類常常和record一起使用:
// 只有「Circle」和「Rectangle」可以實現Shape
// 「Circle」需要一個座標和半徑才能確定
// 「Rectangle」需要兩個座標就能確定
sealed interface Shape permits Circle, Rectangle {
record Circle(Point center, int radius) implements Shape { }
record Rectangle(Point lowerLeft, Point upperRight) implements Shape { }
}
後續的Java更新就不再囉嗦了。還是之前的那個態度:Java8是一個非常重要的分水嶺,如果不把Lambda表示式和函數語言程式設計學好,後面可能會有很多騷操作都做不了了。
感謝您的大駕光臨!諮詢技術、產品、運營和管理相關問題,請關注後留言。歡迎騷擾,不勝榮幸~