作者: 一字馬胡
轉載標志 【2017-11-03】
更新日志
日期 | 更新內容 | 備注 |
---|---|---|
2017-11-03 | 添加轉載標志 | 持續(xù)更新 |
pre-reade&本文涉及的內容
首先,你可以在Java 9 Download下載java 9抱虐,然后就可以體驗java 9了。本文是對java 9新特性的概覽而不是詳解茬缩,因為要詳解的話需要收集大量的信息庙睡,而且有可能還不能覆蓋所有特性,還有一點是本人才疏學淺砰逻,未免對新事物的理解過于遲鈍,所以不太可能很快理解java 9中的新特性泛鸟,比如java 9為什么要有某個特性蝠咆,為什么增加這個特性,為什么刪除了某個東西北滥,這些都需要長期的技術積累和實踐刚操,從實際項目中來發(fā)現(xiàn)這些需求。本文涉及的java 9的新特性有一些會多講一些篇幅再芋,有一些會一帶而過菊霜,比如本文比較在意的新增的API,會寫一些示例代碼來體驗济赎,而對于比較底層的JVM優(yōu)化等內容不會涉及太多(無能為力鉴逞,慢慢補上吧!)联喘。下面先將本文的主要內容做一下索引华蜒。
- Java Modular System
- Enhance Process API
- Enhance Collection API
- Enhance Streams API
- Enhance Optional API
- Reactive API Support(RxJava)
- Private Methods of Interface
- Java Shell Support(REPL)
- Enhance Javadoc(search)
- Other Details
本文將基于上面提到的10點內容對java 9的新特性進行淺讀解讀,Java 8已經(jīng)足夠強大豁遭,但是java 9應該比java 8 要更強大叭喜,并且java的發(fā)版在未來會加快速度,需要快速學習啊蓖谢。對于java 9 更為詳細的描述應該參考更多的資料捂蕴,最好可以結合jdk源碼(或者openjdk源碼)來看更好。
Java 9 新特性
Java Modular System
Java 9 一個比較大的改動就是增加了模塊系統(tǒng)闪幽,基于 Jigsaw [?d??gs?:] 項目啥辨,這是一個較為龐大復雜的項目,它的目標主要是下面兩點:
- 可靠的配置:明確模塊邊界和模塊之間的依賴關系
- 強封裝性:通過封裝模塊內部私有細節(jié)盯腌,來避免不希望發(fā)生的依賴關系溉知,也能避免一些安全問題等。
而Jigsaw被拆分為下面幾個具體的項目:
- JEP 261: Module System腕够,實現(xiàn)模塊化系統(tǒng)级乍;
- JEP 200: The Modular JDK,將JDK自身進行模塊化帚湘;
- JEP 201: Modular Source Code玫荣,按照模塊化的形式,重構源代碼,因為現(xiàn)有代碼并不是劃分到一個一個的模塊里的大诸。
- JEP 220: Modular Run-Time Images捅厂,重新設計JDK和JRE的結構贯卦,定義新的URI scheme操作模塊,類和資源(jrt)焙贷。
- JEP 260: Encapsulate Most Internal APIs撵割,按照模塊化封裝性的要求,將不希望暴露的內部API封裝起來盈厘,如果確實證明是廣泛需要的睁枕,就作為公共API公開出來。
- JEP 282: jlink: The Java Linker沸手。新的link工具
所謂JEP(JDK Enhancement Proposals)外遇,是java 9 中為了管理新特性而引入的代號。為了快速了解Jigsaw 項目在java 9 中的具體體現(xiàn)契吉,下面先看一張圖:
這是jdk現(xiàn)在的模塊依賴關系圖跳仿,可以發(fā)現(xiàn)所有的模塊都是依賴一個模塊叫做java.base,而java.base中包含了java語言層面的一些基礎包捐晶,具體的java.base的詳情可以參考Module java.base菲语。介于該部分內容是java 9中的主要特性,但過于復雜惑灵,以至于都有專門的書籍來介紹這部分內容山上,所以更為細節(jié)的內容可以參考書籍Java 9 Modularity。下面來看一看如何在我們自己的項目中使用模塊化編程呢英支。
比如兜看,我們有三個模塊蔽介,一個模塊叫做com.hujian.base晒奕,提供一些基礎信息內容揍鸟,而第二個模塊叫做com.hujian.extra,提供一些擴展信息池凄,第三個模塊叫做com.hujian.info抡驼,來提供較為全面的信息,他們之間的依賴關系為:com.hujian.extra依賴于com.hujian.base肿仑,而com.hujian.info依賴了com.hujian.base和com.hujian.extra致盟。在java 9中,我們需要在每個模塊中寫一個module-info.java文件尤慰,里面描述模塊的依賴關系勾邦,并且只有在模塊暴露了出去,其他模塊才能引用該模塊「钤瘢現(xiàn)在來看看上面三個模塊的module-info.java應該怎么寫:
對于com.hujian.base來說,它沒有依賴其他模塊萎河,所以不需要依賴荔泳,但是蕉饼,它需要提供服務,也就是
其他模塊會引用該模塊玛歌,所以他需要將自己的模塊暴露出去昧港,下面是它的module-info.java文件的內容:
module com.hujian.base {
exports com.hujian.base; //將模塊暴露出去
}
而對于com.hujian.extra來說,它需要依賴com.hujian.base模塊支子,并且com.hujian.info模塊
會引用該模塊创肥,所以它的module-info.java是這樣的:
module com.hujian.extra {
requires com.hujian.base;
exports com.hujian.extra;
}
最后是com.hujian.info模塊,它的module-info.java應該這樣寫:
module com.hujian.info {
requires com.hujian.base;
require com.hujian.extra值朋;
}
當然叹侄,這只是編寫了module-info.java文件,實際的工作要比這個更多昨登,但是我們可以借助IDE來實現(xiàn)這種模塊編程趾代,比如在
IDEA中,就可以很方便的實現(xiàn)丰辣。java 9中的模塊系統(tǒng)也沒有這么簡單撒强,介于還沒有完全理解,該特性的描述就到此結束吧笙什。
Enhance Process API
Process API提供了一種java程序和操作系統(tǒng)交互的能力飘哨,我們可以在代碼中來獲取關于進程的一些信息,java 9中新增了一個類ProcessHandle琐凭,使用這個類可以很方便的查詢進程的一些信息芽隆。下面是該類的使用示例:
package com.hujian.java9;
import java.util.function.Consumer;
/**
* Created by hujian06 on 2017/10/28.
*
* ProcessHandle demo
*/
public class ProcessHandleDemo {
public static void main(String ... args) {
long pid = ProcessHandle.current().pid();
ProcessHandle.allProcesses()
.forEach(new Consumer<ProcessHandle>() {
@Override
public void accept(ProcessHandle processHandle) {
if (processHandle.pid() == pid) {
System.out.println("Current Process:" + pid + "\n" +
processHandle.info());
}
}
});
}
}
上面的例子僅僅是獲取了當前進程的進程id,更為有趣的應用可以參考ProcessHandle類的具體實現(xiàn)淘正。
Enhance Collection API
在java 9中摆马,分別為List、Set鸿吆、Map增加了of靜態(tài)工廠方法囤采,來獲取一個不可變的List、Set惩淳、Map蕉毯。下面展示了java 9為List提供的of靜態(tài)工廠方法集,Set和Map都是類似的就不贅述了:
static <E> List<E> of()
static <E> List<E> of(E e1)
static <E> List<E> of(E e1, E e2)
static <E> List<E> of(E e1, E e2, E e3)
static <E> List<E> of(E e1, E e2, E e3, E e4)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static <E> List<E> of(E... elements)
在java 9之前思犁,如果我們想要獲取一個不可變的List的話代虾,可以使用下面的方法來實現(xiàn):
List<String> emptyList = Collections.emptyList();
List<String> list = Collections.singletonList("java 9");
而在java 9中,只需要使用of就可以獲取一個不可變的List激蹲,使用方法如下:
List<String> emptyStringList = List.of();
List<String> stringList = List.of("java 7", "java 8", "java 9");
Enhance Streams API
java 8中新增的Stream API可以讓java開發(fā)者方便的使用計算機的并行能力來快速計算棉磨,關于java 8中的Stream的分析總結,可以參考文章Java Streams API学辱,以及Java Stream的并行實現(xiàn)乘瓤。Stream API的并行實現(xiàn)借助了Fork/Join并行框架环形,關于Fork/Join的介紹,可以參考文章Java Fork/Join并行框架衙傀。而在java 9中抬吟,Stream API新增了幾個方法,下面展示了這些新增的方法:
default Stream<T> dropWhile(Predicate<? super T> predicate)
default Stream<T> takeWhile(Predicate<? super T> predicate)
static <T> Stream<T> ofNullable(T t)
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
dropWhile方法和takeWhile方法是一對類似的方法统抬,這兩個方法適合用在有序流火本,而對于無序流來說,使用這兩個方法會造成不可預料的結果聪建。而ofNullable靜態(tài)方法的作用非常有限钙畔,它將對元素T進行判斷,如果是null妆偏,則返回一個空流刃鳄,否則,返回一個只包含一個元素T的流钱骂。而新增的iterate方法類似于for循環(huán)叔锐,類似于下面的代碼:
for (T index=seed; hasNext.test(index); index = next.apply(index)) {
//todo...
}
下面是使用iterate這個新方法來生成一個流的示例代碼:
Stream.iterate( 0, n -> (n <= 100), n -> n + 1 )
.forEach(System.out::println);
需要注意的是,只要test返回false见秽,那么就會停止向前愉烙,這一點需要特別注意。下面來看一下dropWhile方法和takeWhile方法的使用示例以及他們的注意事項:
Stream.of(1, 2, 3, 4)
.takeWhile(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer < 4;
}
}).forEach(System.out::println);
對于takeWhile來說解取,它會從第一個元素進行test步责,如果第一個元素test返回false,那么就會立刻返回整個流禀苦。
否則蔓肯,會一直test到第一個返回false的元素,然后截取前面這一段返回振乏。
Stream.of(1, 2, 3, 4)
.dropWhile(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer < 4;
}
}).forEach(System.out::println);
dropWhile類似于是takeWhile的互補操作蔗包,對于同一個有序流,同一個test條件來說慧邮,他們兩個方法返回的內容正好
是整個流的內容调限,他們的區(qū)別在于,takeWhile是返回滿足條件的流內容误澳,而dropWhile將丟棄滿足條件的流耻矮,返回的
正是不滿足條件的流。
Enhance Optional API
Optional類也是java 8新增的類忆谓,在java 9中對他有一些增強裆装,新增了三個方法:
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
public Stream<T> stream()
首先是ifPresentOrElse方法,這個方法是對原來的方法ifPresent的增強,下面是ifPresentOrElse方法的具體實現(xiàn):
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
if (value != null) {
action.accept(value);
} else {
emptyAction.run();
}
}
可以看到哨免,ifPresentOrElse方法在value為null的時候提供了例外的操作勾扭,這也是orElse的語義。接下來看新增的or方法铁瞒,下面是整個方法的實現(xiàn),以及對這個方法的描述:
/**
* If a value is present, returns an {@code Optional} describing the value,
* otherwise returns an {@code Optional} produced by the supplying function.
*
* @param supplier the supplying function that produces an {@code Optional}
* to be returned
* @return returns an {@code Optional} describing the value of this
* {@code Optional}, if a value is present, otherwise an
* {@code Optional} produced by the supplying function.
* @throws NullPointerException if the supplying function is {@code null} or
* produces a {@code null} result
* @since 9
*/
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
Objects.requireNonNull(supplier);
if (isPresent()) {
return this;
} else {
@SuppressWarnings("unchecked")
Optional<T> r = (Optional<T>) supplier.get();
return Objects.requireNonNull(r);
}
}
最為激動人心的應該是第三個方法stream桅滋,它提供了將Optional轉換為Stream的實現(xiàn)慧耍,在java 9中,你已經(jīng)可以將一個Optional直接轉換為一個Stream了丐谋,下面是它的實現(xiàn)細節(jié):
public Stream<T> stream() {
if (!isPresent()) {
return Stream.empty();
} else {
return Stream.of(value);
}
}
Reactive API Support(RxJava)
如果你接觸過RxJava芍碧,那么就很好理解java 9中新增的Reactive內容了,下面首先展示了一個非常簡單的使用示例:
package com.hujian.java9;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.Flow.Subscription;
import java.util.concurrent.SubmissionPublisher;
public class FlowDemo2 {
private static final ExecutorService SERVICE = Executors.newFixedThreadPool(1);
private static final int CAPATIAL = 1024;
public static void main(String[] args) {
// Create a publisher.
SubmissionPublisher<String> publisher = new SubmissionPublisher<>(SERVICE, CAPATIAL);
// Create a subscriber and register it with the publisher.
MySubscriber<String> subscriber = new MySubscriber<>();
publisher.subscribe(subscriber);
// Publish several data items and then close the publisher.
List.of("Java 7", "Java 8", "Java 9")
.forEach(item -> publisher.submit(item));
publisher.close();
SERVICE.submit(() -> {
//wait the publish job~
});
SERVICE.shutdownNow();
}
static class MySubscriber<T> implements Subscriber<T> {
@Override
public void onSubscribe(Subscription subscription) {
subscription.request(3);
System.out.println("<start to publish item>");
}
@Override
public void onNext(T item) {
System.out.println("<Received>:" + item);
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("<onComplete>");
}
}
}
下面是涉及Reactive的幾個新增的類号俐,需要說明的一點是泌豆,這些內容出自java并發(fā)大師Doug Lea,所以性能問題不需要擔心吏饿,例外一點是踪危,因為這些Reactive的內容添加到了java 語言中,所以比起第三方類庫(比如RxJava)來說更為安全和穩(wěn)定猪落,來看看涉及的幾個類:
Flow
Publisher
Subscriber
Subscription
Processor
SubmissionPublisher
更為具體和深入的分析將在例外的文章中進行贞远。本文點到為止,還有笨忌,畢竟出自并發(fā)大師之手蓝仲,日后值得研究一番啊官疲!
Private Methods of Interface
在java 8中袱结,接口中可以有默認方法和靜態(tài)方法的實現(xiàn),但是還不支持private方法的實現(xiàn)途凫,而在java 9中垢夹,我們可以在接口中實現(xiàn)private方法了,先看下面的示例:
package com.hujian.java9;
/**
* Created by hujian06 on 2017/10/28.
*
* demo of interface
*
*/
public class InterfeaceDemo {
public static void main(String ... args) {
A a = new A() {
@Override
public void af() {
f();
}
};
a.af();
}
}
interface A {
String finalString = "Tag";
void af();
default void f() {
f1();
}
private void f1() {
System.out.println(finalString + ":f1");
}
}
f1是接口A中的默認實現(xiàn)颖榜。private方法和default和靜態(tài)方法的區(qū)別在于棚饵,default方法和靜態(tài)方法都是對外暴露的接口方法,而private方法是私有的掩完,外部調用方是沒有權限知道的噪漾。關于接口的不斷更新,需要更為深入的討論且蓬,再次先不做總結描述欣硼。
Java Shell Support(REPL)
現(xiàn)在,java語言也支持REPL了恶阴,就像下面展示的圖片一樣:
Enhance Javadoc(search)
參考:Java? Platform, Standard Edition & Java Development Kit
Version 9 API Specification
以及java 8版本的javadoc:Java? Platform, Standard Edition 8
API Specification
區(qū)別還是很明顯的诈胜,java 9開始javadoc支持查找了豹障,這一點是很明智的!下面看一下搜索效果圖焦匈,這樣是不是很快可以找到我們需要查找的類信息呢:
Other Details
- 對CompletableFuture類的增強血公,細節(jié)看代碼吧!
- "_"不再可以是一個標志符缓熟,在java 9中已經(jīng)升級為一個關鍵字了累魔!
- HTTP/2 Client API(孵化,目前來看還是用不了啊够滑,好像需要重新編譯openjdk垦写?),據(jù)說比Apache的HttpClients性能還要好啊彰触,這一點很有吸引力啊梯投,還是比較期待的
- 其他更改,可以參考
本文簡單分析了java 9的新特性况毅,更為完整深入的java 9的特性應該搜集更多的資料來總結分蓖,關于是否要將目前的java版本升級到java 9,我的想法是俭茧,應該等等咆疗,一個原因是java 9和java 8比起來貌似沒有太多性能優(yōu)化方面的考慮(不包括我沒有提到了jvm層面的優(yōu)化,那些優(yōu)化任何一個版本的java升級都會做大量的優(yōu)化的)母债,僅類庫層面來說午磁,java 9貌似沒有太多的兩點,新增的類好像不多毡们,多數(shù)是對原有類的增強迅皇,但是貌似這些增強可有可無啊(個人覺得)衙熔。還有一個原因是登颓,未來java的發(fā)版周期將更短,而java 9才剛發(fā)布不久红氯,應該做一些深入的調研測試框咙,等時機成熟再升級java 8到java 9也不遲~但是,如果目前還在使用java 8以前版本的javaer來說痢甘,我強烈建議升級到java 8喇嘱,因為這個版本的java亮點很多,并且各方面表現(xiàn)都是很不錯的塞栅,至于java 9者铜,看各自的調研結論吧!