為什么選擇Java11
- 容器環(huán)境支持创肥,GC等領(lǐng)域的增強(qiáng)唠叛。
- 進(jìn)行了瘦身绢慢,更輕量級灿渴,安裝包體積小。
- JDK11 是一個(gè)長期支持版胰舆。
特性介紹
由于直接從Java8跨越到Java11骚露,所以特性介紹就把Java9-Java11的部分特性一起介紹一下。
Jshell @since 9
Jshell在Java9中就被提出來了缚窿,可以直接在終端寫Java程序荸百,回車就可以執(zhí)行。Jshell默認(rèn)會(huì)導(dǎo)入下面的一些包,所以在Jshell環(huán)境中這些包的內(nèi)容都是可以使用的滨攻。
import java.lang.*;
import java.io.*;
import java.math.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;
import java.util.prefs.*;
import java.util.regex.*;
import java.util.stream.*;
1.什么是Jshell?
Jshell是在 Java 9 中引入的。它提供了一個(gè)交互式 shell蓝翰,用于快速原型光绕、調(diào)試、學(xué)習(xí) Java 及 Java API畜份,所有這些都不需要 public static void main 方法诞帐,也不需要在執(zhí)行之前編譯代碼。
2.Jshell的使用
打開終端爆雹,鍵入jshell進(jìn)入jshell環(huán)境停蕉,然后輸入/help intro可以查看Jshell的介紹。
lixiaoshuang@localhost ~ jshell
| 歡迎使用 JShell -- 版本 11.0.2
| 要大致了解該版本, 請鍵入: /help intro
jshell> /help intro
|
| intro
| =====
|
| 使用 jshell 工具可以執(zhí)行 Java 代碼钙态,從而立即獲取結(jié)果慧起。
| 您可以輸入 Java 定義(變量、方法册倒、類等等)蚓挤,例如:int x = 8
| 或 Java 表達(dá)式,例如:x + x
| 或 Java 語句或?qū)搿?| 這些小塊的 Java 代碼稱為“片段”。
|
| 這些 jshell 工具命令還可以讓您了解和
| 控制您正在執(zhí)行的操作灿意,例如:/list
|
| 有關(guān)命令的列表估灿,請執(zhí)行:/help
jshell>
Jshell確實(shí)是一個(gè)好用的小工具,這里不做過多介紹缤剧,我就舉一個(gè)例子馅袁,剩下的大家自己體會(huì)。比如我們現(xiàn)在就想隨機(jī)生成一個(gè)UUID荒辕,以前需要這么做:
- 創(chuàng)建一個(gè)類汗销。
- 創(chuàng)建一個(gè)main方法。
- 然后寫一個(gè)生成UUID的邏輯兄纺,執(zhí)行大溜。
現(xiàn)在只需要,進(jìn)入打開終端鍵入jshell,然后直接輸入var uuid = UUID.randomUUID()
回車。就可以看到uuid的回顯估脆,這樣我們就得到了一個(gè)uuid钦奋。并不需要public static void main(String[] args);
lixiaoshuang@localhost ~ jshell
| 歡迎使用 JShell -- 版本 11.0.2
| 要大致了解該版本, 請鍵入: /help intro
jshell> var uuid = UUID.randomUUID();
uuid ==> 9dac239e-c572-494f-b06d-84576212e012
jshell>
3.怎么退出Jshell?
在Jshell環(huán)境中鍵入/exit
就可以退出疙赠。
lixiaoshuang@localhost ~
lixiaoshuang@localhost ~ jshell
| 歡迎使用 JShell -- 版本 11.0.2
| 要大致了解該版本, 請鍵入: /help intro
jshell> var uuid = UUID.randomUUID();
uuid ==> 9dac239e-c572-494f-b06d-84576212e012
jshell> /exit
| 再見
lixiaoshuang@localhost ~
模塊化(Module)@since 9
1.什么是模塊化付材?
模塊化就是增加了更高級別的聚合,是Package的封裝體圃阳。Package是一些類路徑名字的約定厌衔,而模塊是一個(gè)或多個(gè)Package組成的封裝體。
java9以前 :package => class/interface捍岳。
java9以后 :module => package => class/interface富寿。
那么JDK被拆為了哪些模塊呢?打開終端執(zhí)行java --list-modules
查看锣夹。
lixiaoshuang@localhost ~ java --list-modules
java.base@11.0.2
java.compiler@11.0.2
java.datatransfer@11.0.2
java.desktop@11.0.2
java.instrument@11.0.2
java.logging@11.0.2
java.management@11.0.2
java.management.rmi@11.0.2
java.naming@11.0.2
java.net.http@11.0.2
java.prefs@11.0.2
java.rmi@11.0.2
java.scripting@11.0.2
java.se@11.0.2
java.security.jgss@11.0.2
java.security.sasl@11.0.2
java.smartcardio@11.0.2
java.sql@11.0.2
java.sql.rowset@11.0.2
java.transaction.xa@11.0.2
java.xml@11.0.2
java.xml.crypto@11.0.2
jdk.accessibility@11.0.2
jdk.aot@11.0.2
jdk.attach@11.0.2
jdk.charsets@11.0.2
jdk.compiler@11.0.2
jdk.crypto.cryptoki@11.0.2
jdk.crypto.ec@11.0.2
jdk.dynalink@11.0.2
jdk.editpad@11.0.2
jdk.hotspot.agent@11.0.2
jdk.httpserver@11.0.2
jdk.internal.ed@11.0.2
jdk.internal.jvmstat@11.0.2
jdk.internal.le@11.0.2
jdk.internal.opt@11.0.2
jdk.internal.vm.ci@11.0.2
jdk.internal.vm.compiler@11.0.2
jdk.internal.vm.compiler.management@11.0.2
jdk.jartool@11.0.2
jdk.javadoc@11.0.2
jdk.jcmd@11.0.2
jdk.jconsole@11.0.2
jdk.jdeps@11.0.2
jdk.jdi@11.0.2
jdk.jdwp.agent@11.0.2
jdk.jfr@11.0.2
jdk.jlink@11.0.2
jdk.jshell@11.0.2
jdk.jsobject@11.0.2
jdk.jstatd@11.0.2
jdk.localedata@11.0.2
jdk.management@11.0.2
jdk.management.agent@11.0.2
jdk.management.jfr@11.0.2
jdk.naming.dns@11.0.2
jdk.naming.rmi@11.0.2
jdk.net@11.0.2
jdk.pack@11.0.2
jdk.rmic@11.0.2
jdk.scripting.nashorn@11.0.2
jdk.scripting.nashorn.shell@11.0.2
jdk.sctp@11.0.2
jdk.security.auth@11.0.2
jdk.security.jgss@11.0.2
jdk.unsupported@11.0.2
jdk.unsupported.desktop@11.0.2
jdk.xml.dom@11.0.2
jdk.zipfs@11.0.2
2.為什么這么做页徐?
大家都知道JRE中有一個(gè)超級大的rt.jar(60多M),tools.jar也有幾十兆银萍,以前運(yùn)行一個(gè)hello world也需要上百兆的環(huán)境变勇。
- 讓Java SE程序更加容易輕量級部署。
- 強(qiáng)大的封裝能力贴唇。
- 改進(jìn)組件間的依賴管理搀绣,引入比jar粒度更大的Module。
- 改進(jìn)性能和安全性戳气。
3.怎么定義模塊?
模塊的是通過module-info.java進(jìn)行定義链患,編譯后打包后,就成為一個(gè)模塊的實(shí)體物咳。下面來看下最簡單的模塊定義锣险。
4.模塊的關(guān)鍵字
-
open
用來指定開放模塊,開放模塊的所有包都是公開的,public的可以直接引用使用,其他類型可以通過反射得到蹄皱。
open module module.one { //導(dǎo)入日志包 requires java.logging; }
-
opens
opens 用來指定開放的包,其中public類型是可以直接訪問的,其他類型可以通過反射得到。
module module.one { opens <package>; }
-
exports
exports用于指定模塊下的哪些包可以被其他模塊訪問芯肤。
module module.one { exports <package>; exports <package> to <module1>, <module2>...; }
-
requires
該關(guān)鍵字聲明當(dāng)前模塊與另一個(gè)模塊的依賴關(guān)系巷折。
module module.one { requires <package>; }
-
uses、provides…with…
uses語句使用服務(wù)接口的名字,當(dāng)前模塊就會(huì)發(fā)現(xiàn)它,使用java.util.ServiceLoader類進(jìn)行加載,必須是本模塊中的,不能是其他模塊中的.其實(shí)現(xiàn)類可以由其他模塊提供崖咨。
module module.one { //對外提供的接口服務(wù) ,下面指定的接口以及提供服務(wù)的impl锻拘,如果有多個(gè)實(shí)現(xiàn)類,用用逗號隔開 uses <接口名>; provides <接口名> with <接口實(shí)現(xiàn)類>,<接口實(shí)現(xiàn)類>; }
var關(guān)鍵字 @since 10
1.var是什么击蹲?
var是Java10中新增的局部類型變量推斷署拟。它會(huì)根據(jù)后面的值來推斷變量的類型,所以var必須要初始化歌豺。
例:
var a; ?
var a = 1; ?
2.var使用示例
-
var定義局部變量
var a = 1; 等于 int a = 1;
-
var接收方法返回時(shí)
var result = this.getResult(); 等于 String result = this.getResult();
-
var循環(huán)中定義局部變量
for (var i = 0; i < 5; i++) { System.out.println(i); } 等于 for (int i = 0; i < 5; i++) { System.out.println(i); }
-
var結(jié)合泛型
var list1 = new ArrayList<String>(); //在<>中指定了list類型為String 等于 List<String> list1 = new ArrayList<>(); var list2 = new ArrayList<>(); //<>里默認(rèn)會(huì)是Object
-
var在Lambda中使用(java11才可以使用)
Consumer<String> Consumer = (var i) -> System.out.println(i); 等于 Consumer<String> Consumer = (String i) -> System.out.println(i);
3.var不能再哪里使用推穷?
- 類成員變量類型。
- 方法返回值類型类咧。
- Java10中Lambda不能使用var馒铃,Java11中可以使用。
增強(qiáng)api
1.字符串增強(qiáng) @since 11
// 判斷字符串是否為空白
" ".isBlank(); // true
// 去除首尾空格
" Hello Java11 ".strip(); // "Hello Java11"
// 去除尾部空格
" Hello Java11 ".stripTrailing(); // " Hello Java11"
// 去除首部空格
" Hello Java11 ".stripLeading(); // "Hello Java11 "
// 復(fù)制字符串
"Java11".repeat(3); // "Java11Java11Java11"
// 行數(shù)統(tǒng)計(jì)
"A\nB\nC".lines().count(); // 3
2.集合增強(qiáng)
從Java 9 開始痕惋,jdk里面就為集合(List区宇、Set、Map)增加了of和copyOf方法值戳。它們用來創(chuàng)建不可變集合议谷。
- of() @since 9
- copyOf() @since 10
示例一:
var list = List.of("Java", "Python", "C"); //不可變集合
var copy = List.copyOf(list); //copyOf判斷是否是不可變集合類型,如果是直接返回
System.out.println(list == copy); // true
var list = new ArrayList<String>(); // 這里返回正常的集合
var copy = List.copyOf(list); // 這里返回一個(gè)不可變集合
System.out.println(list == copy); // false
示例二:
var set = Set.of("Java", "Python", "C");
var copy = Set.copyOf(set);
System.out.println(set == copy); // true
var set1 = new HashSet<String>();
var copy1 = List.copyOf(set1);
System.out.println(set1 == copy1); // false
示例三:
var map = Map.of("Java", 1, "Python", 2, "C", 3);
var copy = Map.copyOf(map);
System.out.println(map == copy); // true
var map1 = new HashMap<String, Integer>();
var copy1 = Map.copyOf(map1);
System.out.println(map1 == copy1); // false
注意:使用 of 和 copyOf 創(chuàng)建的集合為不可變集合堕虹,不能進(jìn)行添加卧晓、刪除、替換赴捞、排序等操作禀崖,不然會(huì)報(bào)java.lang.UnsupportedOperationException異常,使用Set.of()不能出現(xiàn)重復(fù)元素螟炫、Map.of()不能出現(xiàn)重復(fù)key,否則回報(bào)java.lang.IllegalArgumentException艺晴。
昼钻。
3.Stream增強(qiáng) @since 9
Stream是Java 8 中的特性,在Java 9 中為其新增了4個(gè)方法:
-
ofNullable(T t)
此方法可以接收null來創(chuàng)建一個(gè)空流
以前 Stream.of(null); //報(bào)錯(cuò) 現(xiàn)在 Stream.ofNullable(null);
-
takeWhile(Predicate<? super T> predicate)
此方法根據(jù)Predicate接口來判斷如果為true就
取出
來生成一個(gè)新的流,只要碰到false就終止封寞,不管后邊的元素是否符合條件然评。Stream<Integer> integerStream = Stream.of(6, 10, 11, 15, 20); Stream<Integer> takeWhile = integerStream.takeWhile(t -> t % 2 == 0); takeWhile.forEach(System.out::println); // 6,10
-
dropWhile(Predicate<? super T> predicate)
此方法根據(jù)Predicate接口來判斷如果為true就
丟棄
來生成一個(gè)新的流,只要碰到false就終止,不管后邊的元素是否符合條件狈究。Stream<Integer> integerStream = Stream.of(6, 10, 11, 15, 20); Stream<Integer> takeWhile = integerStream.dropWhile(t -> t % 2 == 0); takeWhile.forEach(System.out::println); //11,15,20
-
iterate重載
以前使用iterate方法生成無限流需要配合limit進(jìn)行截?cái)?/p>
Stream<Integer> limit = Stream.iterate(1, i -> i + 1).limit(5); limit.forEach(System.out::println); //1,2,3,4,5
現(xiàn)在重載后這個(gè)方法增加了個(gè)判斷參數(shù)
Stream<Integer> iterate = Stream.iterate(1, i -> i <= 5, i -> i + 1); iterate.forEach(System.out::println); //1,2,3,4,5
4.Optional增強(qiáng) @since 9
-
stream()
如果為空返回一個(gè)空流碗淌,如果不為空將Optional的值轉(zhuǎn)成一個(gè)流。
//返回Optional值的流 Stream<String> stream = Optional.of("Java 11").stream(); stream.forEach(System.out::println); // Java 11 //返回空流 Stream<Object> stream = Optional.ofNullable(null).stream(); stream.forEach(System.out::println); //
-
ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
個(gè)人感覺這個(gè)方法就是結(jié)合isPresent()對Else的增強(qiáng),ifPresentOrElse 方法的用途是亿眠,如果一個(gè) Optional 包含值碎罚,則對其包含的值調(diào)用函數(shù) action,即 action.accept(value)纳像,這與 ifPresent 一致荆烈;與 ifPresent 方法的區(qū)別在于,ifPresentOrElse 還有第二個(gè)參數(shù) emptyAction —— 如果 Optional 不包含值竟趾,那么 ifPresentOrElse 便會(huì)調(diào)用 emptyAction憔购,即 emptyAction.run()。
Optional<Integer> optional = Optional.of(1); optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() -> System.out.println("Not Present.")); //Value: 1 optional = Optional.empty(); optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() -> System.out.println("Not Present.")); //Not Present.
or(Supplier<? extends Optional<? extends T>> supplier)
Optional<String> optional1 = Optional.of("Java");
Supplier<Optional<String>> supplierString = () -> Optional.of("Not Present");
optional1 = optional1.or( supplierString);
optional1.ifPresent( x -> System.out.println("Value: " + x)); //Value: Java
optional1 = Optional.empty();
optional1 = optional1.or( supplierString);
optional1.ifPresent( x -> System.out.println("Value: " + x)); //Value: Not Present
5.InputStream增強(qiáng) @since 9
String lxs = "java";
try (var inputStream = new ByteArrayInputStream(lxs.getBytes());
var outputStream = new ByteArrayOutputStream()) {
inputStream.transferTo(outputStream);
System.out.println(outputStream); //java
}
HTTP Client API
改api支持同步和異步兩種方式岔帽,下面是兩種方式的示例:
var request = HttpRequest.newBuilder()
.uri(URI.create("https://www.baidu.com/"))
.build();
var client = HttpClient.newHttpClient();
// 同步
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
// 異步
CompletableFuture<HttpResponse<String>> sendAsync = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
//這里會(huì)阻塞
HttpResponse<String> response1 = sendAsync.get();
System.out.println(response1.body());
直接運(yùn)行java文件
我們都知道以前要運(yùn)行一個(gè).java文件玫鸟,首先要javac編譯成.class文件,然后在java執(zhí)行:
//編譯
javac Java11.java
//運(yùn)行
java Java11
在java11中犀勒,只需要通過java一個(gè)命令就可以搞定
java Java11.java
移除內(nèi)容
- 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 java10還尚未移除javafx 箱玷,而java11版本將javafx也移除了怨规。
- Java Mission Control,從JDK中移除之后锡足,需要自己單獨(dú)下載波丰。
- Root Certificates :Baltimore Cybertrust Code Signing CA,SECOM 舶得,AOL and Swisscom掰烟。
- 在java11中將java9標(biāo)記廢棄的Java EE及CORBA模塊移除掉。
完全支持Linux容器(包括docker)
許多運(yùn)行在Java虛擬機(jī)中的應(yīng)用程序(包括Apache Spark和Kafka等數(shù)據(jù)服務(wù)以及傳統(tǒng)的企業(yè)應(yīng)用程序)都可以在Docker容器中運(yùn)行沐批。但是在Docker容器中運(yùn)行Java應(yīng)用程序一直存在一個(gè)問題纫骑,那就是在容器中運(yùn)行JVM程序在設(shè)置內(nèi)存大小和CPU使用率后,會(huì)導(dǎo)致應(yīng)用程序的性能下降九孩。這是因?yàn)镴ava應(yīng)用程序沒有意識到它正在容器中運(yùn)行先馆。隨著Java 10的發(fā)布,這個(gè)問題總算得以解決躺彬,JVM現(xiàn)在可以識別由容器控制組(cgroups)設(shè)置的約束煤墙∶饭撸可以在容器中使用內(nèi)存和CPU約束來直接管理Java應(yīng)用程序,其中包括:
- 遵守容器中設(shè)置的內(nèi)存限制
- 在容器中設(shè)置可用的CPU
- 在容器中設(shè)置CPU約束
Java 10的這個(gè)改進(jìn)在Docker for Mac仿野、Docker for Windows以及Docker Enterprise Edition等環(huán)境均有效铣减。