作者: 一字馬胡
轉載標志 【2017-11-03】
更新日志
日期 | 更新內容 | 備注 |
---|---|---|
2017-11-03 | 添加轉載標志 | 持續更新 |
pre-reade&本文涉及的內容
首先,你可以在Java 9 Download下載java 9,然后就可以體驗java 9了。本文是對java 9新特性的概覽而不是詳解,因為要詳解的話需要收集大量的信息,而且有可能還不能覆蓋所有特性,還有一點是本人才疏學淺,未免對新事物的理解過于遲鈍,所以不太可能很快理解java 9中的新特性,比如java 9為什么要有某個特性,為什么增加這個特性,為什么刪除了某個東西,這些都需要長期的技術積累和實踐,從實際項目中來發現這些需求。本文涉及的java 9的新特性有一些會多講一些篇幅,有一些會一帶而過,比如本文比較在意的新增的API,會寫一些示例代碼來體驗,而對于比較底層的JVM優化等內容不會涉及太多(無能為力,慢慢補上吧!)。下面先將本文的主要內容做一下索引。
- 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已經足夠強大,但是java 9應該比java 8 要更強大,并且java的發版在未來會加快速度,需要快速學習啊。對于java 9 更為詳細的描述應該參考更多的資料,最好可以結合jdk源碼(或者openjdk源碼)來看更好。
Java 9 新特性
Java Modular System
Java 9 一個比較大的改動就是增加了模塊系統,基于 Jigsaw [?d??gs?:] 項目,這是一個較為龐大復雜的項目,它的目標主要是下面兩點:
- 可靠的配置:明確模塊邊界和模塊之間的依賴關系
- 強封裝性:通過封裝模塊內部私有細節,來避免不希望發生的依賴關系,也能避免一些安全問題等。
而Jigsaw被拆分為下面幾個具體的項目:
- JEP 261: Module System,實現模塊化系統;
- JEP 200: The Modular JDK,將JDK自身進行模塊化;
- JEP 201: Modular Source Code,按照模塊化的形式,重構源代碼,因為現有代碼并不是劃分到一個一個的模塊里的。
- 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 中的具體體現,下面先看一張圖:
這是jdk現在的模塊依賴關系圖,可以發現所有的模塊都是依賴一個模塊叫做java.base,而java.base中包含了java語言層面的一些基礎包,具體的java.base的詳情可以參考Module java.base。介于該部分內容是java 9中的主要特性,但過于復雜,以至于都有專門的書籍來介紹這部分內容,所以更為細節的內容可以參考書籍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文件,里面描述模塊的依賴關系,并且只有在模塊暴露了出去,其他模塊才能引用該模塊。現在來看看上面三個模塊的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來實現這種模塊編程,比如在
IDEA中,就可以很方便的實現。java 9中的模塊系統也沒有這么簡單,介于還沒有完全理解,該特性的描述就到此結束吧。
Enhance Process API
Process API提供了一種java程序和操作系統交互的能力,我們可以在代碼中來獲取關于進程的一些信息,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類的具體實現。
Enhance Collection API
在java 9中,分別為List、Set、Map增加了of靜態工廠方法,來獲取一個不可變的List、Set、Map。下面展示了java 9為List提供的of靜態工廠方法集,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的話,可以使用下面的方法來實現:
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開發者方便的使用計算機的并行能力來快速計算,關于java 8中的Stream的分析總結,可以參考文章Java Streams API,以及Java Stream的并行實現。Stream API的并行實現借助了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進行判斷,如果是null,則返回一個空流,否則,返回一個只包含一個元素T的流。而新增的iterate方法類似于for循環,類似于下面的代碼:
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條件來說,他們兩個方法返回的內容正好
是整個流的內容,他們的區別在于,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方法的具體實現:
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
if (value != null) {
action.accept(value);
} else {
emptyAction.run();
}
}
可以看到,ifPresentOrElse方法在value為null的時候提供了例外的操作,這也是orElse的語義。接下來看新增的or方法,下面是整個方法的實現,以及對這個方法的描述:
/**
* 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的實現,在java 9中,你已經可以將一個Optional直接轉換為一個Stream了,下面是它的實現細節:
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并發大師Doug Lea,所以性能問題不需要擔心,例外一點是,因為這些Reactive的內容添加到了java 語言中,所以比起第三方類庫(比如RxJava)來說更為安全和穩定,來看看涉及的幾個類:
Flow
Publisher
Subscriber
Subscription
Processor
SubmissionPublisher
更為具體和深入的分析將在例外的文章中進行。本文點到為止,還有,畢竟出自并發大師之手,日后值得研究一番啊!
Private Methods of Interface
在java 8中,接口中可以有默認方法和靜態方法的實現,但是還不支持private方法的實現,而在java 9中,我們可以在接口中實現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中的默認實現。private方法和default和靜態方法的區別在于,default方法和靜態方法都是對外暴露的接口方法,而private方法是私有的,外部調用方是沒有權限知道的。關于接口的不斷更新,需要更為深入的討論,再次先不做總結描述。
Java Shell Support(REPL)
現在,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
區別還是很明顯的,java 9開始javadoc支持查找了,這一點是很明智的!下面看一下搜索效果圖,這樣是不是很快可以找到我們需要查找的類信息呢:
Other Details
- 對CompletableFuture類的增強,細節看代碼吧!
- "_"不再可以是一個標志符,在java 9中已經升級為一個關鍵字了!
- HTTP/2 Client API(孵化,目前來看還是用不了啊,好像需要重新編譯openjdk?),據說比Apache的HttpClients性能還要好啊,這一點很有吸引力啊,還是比較期待的
- 其他更改,可以參考
本文簡單分析了java 9的新特性,更為完整深入的java 9的特性應該搜集更多的資料來總結,關于是否要將目前的java版本升級到java 9,我的想法是,應該等等,一個原因是java 9和java 8比起來貌似沒有太多性能優化方面的考慮(不包括我沒有提到了jvm層面的優化,那些優化任何一個版本的java升級都會做大量的優化的),僅類庫層面來說,java 9貌似沒有太多的兩點,新增的類好像不多,多數是對原有類的增強,但是貌似這些增強可有可無啊(個人覺得)。還有一個原因是,未來java的發版周期將更短,而java 9才剛發布不久,應該做一些深入的調研測試,等時機成熟再升級java 8到java 9也不遲~但是,如果目前還在使用java 8以前版本的javaer來說,我強烈建議升級到java 8,因為這個版本的java亮點很多,并且各方面表現都是很不錯的,至于java 9,看各自的調研結論吧!