一個小糾結
很多初學Java的小伙伴經(jīng)常咨詢:
- 到底該安裝哪個版本的JDK比較好么伯?
- Java 8到底還夠不夠用疟暖?
- Java 11究竟有什么改進?
- 是不是Java版本越新越好?
- ……
是這樣俐巴,官網(wǎng)現(xiàn)在其實都已經(jīng)出到Java 13版本了骨望,并且提供下載使用。
但目前市場上主流的穩(wěn)定版當然還得屬Java 8和Java 11欣舵,而目前大部分公司的生產(chǎn)環(huán)境還是Java 8
居多擎鸠。所以如果從自學角度出發(fā),我覺得這兩個版本都OK缘圈,其他中間的一些比如Java 9
劣光、Java 10
這些非穩(wěn)定版就不用考慮了。
Java11 vs Java8
Java 11相對于Java 8確實有一部分進化糟把,除了有很多內(nèi)部的升級(比如開銷和時延更低的GC绢涡、TLS1.3加持等等)之外,對于初學使用者來說也有一些語言使用層面的進化遣疯。
正好最近我在自己的個人小項目上嘗試升級使用了一下Java 11
(公司項目咱也不敢動雄可、也不敢問,只好動自己的個人項目)缠犀,因此本文從實際代碼編寫角度來大致體驗一下我個人使用Java 11
之后相對Java 8
所感覺到的一些比較深刻的進化数苫,官方文檔里說得也非常清楚了:https://docs.oracle.com/en/java/javase/11/
我這次實驗裝的Java 11
版本是11.0.6
:
下文將要實驗驗證的一些新特性其實也并非
Java 11
才引入,很多其實在Java 9
和Java 10
時就已經(jīng)引入辨液,只不過到了Java 11
這個穩(wěn)定版才沉淀下來虐急。
變量類型推斷
新版Java引入了一個全新的類型關鍵字var
,用var
來定義的變量不用寫具體類型室梅,編譯器能根據(jù)=
右邊的實際賦值來自動推斷出變量的類型:
1戏仓、普通局部變量
var name = "codesheep"; // 自動推斷name為String類型
System.out.println(name);
怎么樣?是不是有一種在使用類似JavaScript這種弱類型語言的錯覺亡鼠?
2赏殃、for循環(huán)中使用
var upList1 = List.of( "劉能", "趙四", "謝廣坤" );
var upList2 = List.of( "永強", "玉田", "劉英" );
var upList3 = List.of( "謝飛機", "蘭妮", "蘭娜" );
var upListAll = List.of( upList1, upList2, upList3 );
for( var i : upListAll ) { // 用var接受局部變量的確非常簡潔!
for( var j : i ) {
System.out.println(j);
}
}
這地方就能看出用var
定義局部變量的優(yōu)勢了间涵,假如這個例子中集合里的元素類型更為復雜仁热,是類似List<List<String>>
這種嵌套類型的話,var
定義就非常簡潔明了勾哩!
3抗蠢、當然,有些情況是不能使用的
var
類型變量一旦賦值后思劳,重新賦不同類型的值是不行的迅矛,比如:
var name = "codesheep";
name = 666; // 此時編譯會提示不兼容的類型
定義var
類型變量沒有初始化是不行的,比如:
var foo; // 此時編譯會提示無法推斷類型
foo = "Foo";
另外潜叛,像類的成員變量類型
秽褒、方法入?yún)㈩愋?/code>壶硅、
返回值類型
等是不能使用var
的,比如:
public class Test {
private var name; // 會提示不允許使用var
public void setName( var name ) { // 會提示不允許使用var
this.name = name;
}
public var getName() { // 會提示不允許使用var
return name;
}
}
官方HTTP Client加持
是的销斟!
現(xiàn)在JDK
官方就自帶HTTP Client
了庐椒,位于java.net.http
包下,支持發(fā)送同步蚂踊、異步的HTTP
請求约谈,這樣一來,以前咱們常用的HTTP請求客戶端諸如:OKHttp
犁钟、HttpClient
這種現(xiàn)在都可以退下了棱诱!
發(fā)送同步請求:
var request = HttpRequest.newBuilder()
.uri( URI.create("https://www.codesheep.cn") )
.GET()
.build();
// 同步請求方式,拿到結果前會阻塞當前線程
var httpResponse = HttpClient.newHttpClient()
.send( request, HttpResponse.BodyHandlers.ofString());
System.out.println( httpResponse.body() ); // 打印獲取到的網(wǎng)頁內(nèi)容
發(fā)送異步請求:
CompletableFuture<String> future = HttpClient.newHttpClient().
sendAsync( request, HttpResponse.BodyHandlers.ofString() )
.thenApply( HttpResponse::body );
System.out.println("我先繼續(xù)干點別的事情...");
System.out.println( future.get() ); // 打印獲取到的網(wǎng)頁內(nèi)容
當然你也可以自定義請求頭涝动,比如攜帶JWT Token
權限信息去請求等:
var requestWithAuth = HttpRequest.newBuilder()
.uri( URI.create("http://www.xxxxxx.com/sth") )
.header("Authorization", "Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxNTIwNTE2MTE5NiIsImNyZWF0ZWQiOjE1ODMzMTA2ODk0MzYsImV4cCI6MTU4MzM5NzA4OSwidXNlcmlkIjoxMDAwNH0.OE9R5PxxsvtVJZn8ne-ksTb2aXXi7ipzuW9kbCiQ0uNoW0fJJr_wckLFmgDzxmBs3IdzIhWDAtaSIvmTshK_RQ")
.GET()
.build();
var response = HttpClient.newHttpClient()
.send( requestWithAuth, HttpResponse.BodyHandlers.ofString() );
System.out.println( response.body() ); // 打印獲取到的接口返回內(nèi)容
String處理增強
新版字符串String
類型增加了諸如:isBlank()
军俊、strip()
、repeat()
等方便的字符串處理方法
String myName = " codesheep ";
System.out.println( " ".isBlank() ); // 打优醮妗:true
System.out.println( " ".isEmpty() ); // 打印:false
System.out.println( myName.strip() ); // 打印codesheep担败,前后空格均移除
System.out.println( myName.stripLeading() ); // 打印codesheep 昔穴,僅頭部空格移除
System.out.println( myName.stripTrailing() ); // 打印 codesheep,僅尾部空格移除
System.out.println( myName.repeat(2) ); // 打印 codesheep codesheep
集合增強
主要是增加了諸如of()
和copyOf()
等方法用于更加方便的創(chuàng)建和復制集合類型
var upList = List.of( "劉能", "趙四", "謝廣坤" );
var upListCopy = List.copyOf( upList );
System.out.println(upList); // 打印 [劉能, 趙四, 謝廣坤]
System.out.println(upListCopy); // 打印 [劉能, 趙四, 謝廣坤]
var upSet = Set.of("劉能","趙四");
var upSetCopy = Set.copyOf( upSet );
System.out.println(upSet); // 打印 [趙四, 劉能]
System.out.println(upSetCopy); // 打印 [趙四, 劉能]
var upMap = Map.of("劉能","58歲","趙四","59歲");
var upMapCopy = Map.copyOf( upMap );
System.out.println(upMap); // 打印 {劉能=58歲, 趙四=59歲}
System.out.println(upMapCopy); // 打印 {劉能=58歲, 趙四=59歲}
函數(shù)式編程增強
我印象最深的是對Stream
流增加了諸如takeWhile()
和dropWhile()
的截止結算方法:
var upList = List.of( "劉能", "趙四", "謝廣坤" );
// 從集合中依次刪除滿足條件的元素提前,直到不滿足條件為止
var upListSub1 = upList.stream()
.dropWhile( item -> item.equals("劉能") )
.collect( Collectors.toList() );
System.out.println(upListSub1); // 打印 [趙四, 謝廣坤]
// 從集合中依次獲取滿足條件的元素吗货,知道不滿足條件為止
var upListSub2 = upList.stream()
.takeWhile( item -> item.equals("劉能") )
.collect( Collectors.toList() );
System.out.println( upListSub2 ); // 打印 [劉能]
文件讀寫增強
1、Files類增強
我們以前心心念的直接能把文件內(nèi)容讀取到String
以及String
回寫到文件的功能終于支持了,可以通過Files
類的靜態(tài)方法writeString()
和readString()
完成:
Path path = Paths.get("/Users/CodeSheep/test.txt");
String content = Files.readString(path, StandardCharsets.UTF_8);
System.out.println(content);
Files.writeString( path, "王老七", StandardCharsets.UTF_8 );
2狈网、InputStream增強
InputStream
則增加了一個transferTo()
方法宙搬,直接將數(shù)據(jù)丟到OutputStream
去:
InputStream inputStream = new FileInputStream( "/Users/CodeSheep/test.txt" );
OutputStream outputStream = new FileOutputStream( "/Users/CodeSheep/test2.txt" );
inputStream.transferTo( outputStream );
支持源文件直接運行(666!)
比如我寫一個最簡單的Hello World
程序:
public class Hello {
public static void main( String[] args ) {
System.out.println("hello world");
}
}
并保存為hello.java
文件拓哺,這時候可以直接用java
指令去運行這個Java源文件勇垛,直接省去以前javac
編譯源文件的過程:
java hello.java
怎么樣?是不是和python源文件的運行有點像士鸥?這個信息量就有點大了闲孤,大家可以自行腦補一下
小結
Java 11確有很多改進,但還是那句話烤礁,對于初學者來說Java 8了讼积,沒必要刻意求新,穩(wěn)才是最重要的脚仔!