目錄結(jié)構(gòu)
-
2.2 接口的默認與靜態(tài)方法
2.3 方法引用
2.4 重復(fù)注解
2.5 更好的類型推測機制
2.6 擴展注解的支持
-
3.1 參數(shù)名字
-
4.1 Optional
4.2 Streams
4.5 Base64
-
5.1 Nashorn引擎: jjs
5.2 類依賴分析器: jdeps
1.介紹
毫無疑問坑雅,Java 8發(fā)行版是自Java 5(發(fā)行于2004缝左,已經(jīng)過了相當(dāng)一段時間了)以來最具革命性的版本皇帮。Java 8 為Java語言巩梢、編譯器、類庫首尼、開發(fā)工具與JVM(Java虛擬機)帶來了大量新特性耙替。在這篇教程中,我們將一一探索這些變化胶逢,并用真實的例子說明它們適用的場景厅瞎。
這篇教程由以下幾部分組成饰潜,它們分別涉及到Java平臺某一特定方面的內(nèi)容:
- Java語言
- 編譯器
- 類庫
- 工具
- Java運行時(JVM)
2.Java語言的新特性
不管怎么說,Java 8都是一個變化巨大的版本和簸。你可能認為Java 8耗費了大量的時間才得以完成是為了實現(xiàn)了每個Java程序員所期待的特性彭雾。在這個小節(jié)里,我們將會涉及到這些特性的大部分锁保。
2.1 Lambda表達式與Functional接口
Lambda表達式(也稱為閉包)是整個Java 8發(fā)行版中最受期待的在Java語言層面上的改變薯酝,Lambda允許把函數(shù)作為一個方法的參數(shù)(函數(shù)作為參數(shù)傳遞進方法中),或者把代碼看成數(shù)據(jù):函數(shù)式程序員對這一概念非常熟悉爽柒。在JVM平臺上的很多語言(Groovy吴菠,Scala,……)從一開始就有Lambda浩村,但是Java程序員不得不使用毫無新意的匿名類來代替lambda橄务。
關(guān)于Lambda設(shè)計的討論占用了大量的時間與社區(qū)的努力⊙鳎可喜的是蜂挪,最終找到了一個平衡點,使得可以使用一種即簡潔又緊湊的新方式來構(gòu)造Lambdas嗓化。在最簡單的形式中棠涮,一個lambda可以由用逗號分隔的參數(shù)列表、–>符號與函數(shù)體三部分表示刺覆。例如:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );
</pre>
請注意參數(shù)e的類型是由編譯器推測出來的严肪。同時,你也可以通過把參數(shù)類型與參數(shù)包括在括號中的形式直接給出參數(shù)的類型:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );
</pre>
在某些情況下lambda的函數(shù)體會更加復(fù)雜谦屑,這時可以把函數(shù)體放到在一對花括號中驳糯,就像在Java中定義普通函數(shù)一樣。例如:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Arrays.asList( "a", "b", "d" ).forEach( e -> {
System.out.print( e );
System.out.print( e );
} );
</pre>
Lambda可以引用類的成員變量與局部變量(如果這些變量不是final的話氢橙,它們會被隱含的轉(zhuǎn)為final酝枢,這樣效率更高)。例如悍手,下面兩個代碼片段是等價的:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(
( String e ) -> System.out.print( e + separator ) );
</pre>
和:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">final String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(
( String e ) -> System.out.print( e + separator ) );
</pre>
Lambda可能會返回一個值帘睦。返回值的類型也是由編譯器推測出來的。如果lambda的函數(shù)體只有一行的話坦康,那么沒有必要顯式使用return語句竣付。下面兩個代碼片段是等價的:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );
</pre>
和:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
int result = e1.compareTo( e2 );
return result;
} );
</pre>
語言設(shè)計者投入了大量精力來思考如何使現(xiàn)有的函數(shù)友好地支持lambda。最終采取的方法是:增加函數(shù)式接口的概念滞欠。函數(shù)式接口就是一個具有一個方法的普通接口古胆。像這樣的接口,可以被隱式轉(zhuǎn)換為lambda表達式筛璧。java.lang.Runnable與java.util.concurrent.Callable是函數(shù)式接口最典型的兩個例子逸绎。在實際使用過程中妖滔,函數(shù)式接口是容易出錯的:如有某個人在接口定義中增加了另一個方法,這時桶良,這個接口就不再是函數(shù)式的了座舍,并且編譯過程也會失敗。為了克服函數(shù)式接口的這種脆弱性并且能夠明確聲明接口作為函數(shù)式接口的意圖陨帆,Java 8增加了一種特殊的注解@FunctionalInterface(Java 8中所有類庫的已有接口都添加了@FunctionalInterface注解)曲秉。讓我們看一下這種函數(shù)式接口的定義:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">@FunctionalInterface
public interface Functional {
void method();
}
</pre>
需要記住的一件事是:默認方法與靜態(tài)方法并不影響函數(shù)式接口的契約,可以任意使用:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">@FunctionalInterface
public interface FunctionalDefaultMethods {
void method();
default void defaultMethod() {
}
}
</pre>
Lambda是Java 8最大的賣點疲牵。它具有吸引越來越多程序員到Java平臺上的潛力承二,并且能夠在純Java語言環(huán)境中提供一種優(yōu)雅的方式來支持函數(shù)式編程。更多詳情可以參考官方文檔纲爸。
2.2 接口的默認方法與靜態(tài)方法
Java 8用默認方法與靜態(tài)方法這兩個新概念來擴展接口的聲明亥鸠。默認方法使接口有點像Traits(Scala中特征(trait)類似于Java中的Interface,但它可以包含實現(xiàn)代碼识啦,也就是目前Java8新增的功能)负蚊,但與傳統(tǒng)的接口又有些不一樣,它允許在已有的接口中添加新方法颓哮,而同時又保持了與舊版本代碼的兼容性家妆。
默認方法與抽象方法不同之處在于抽象方法必須要求實現(xiàn),但是默認方法則沒有這個要求冕茅。相反伤极,每個接口都必須提供一個所謂的默認實現(xiàn),這樣所有的接口實現(xiàn)者將會默認繼承它(如果有必要的話姨伤,可以覆蓋這個默認實現(xiàn))哨坪。讓我們看看下面的例子:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">private interface Defaulable {
// Interfaces now allow default methods, the implementer may or
// may not implement (override) them.
default String notRequired() {
return "Default implementation";
}
}
private static class DefaultableImpl implements Defaulable {
}
private static class OverridableImpl implements Defaulable {
@Override
public String notRequired() {
return "Overridden implementation";
}
}
</pre>
Defaulable接口用關(guān)鍵字default聲明了一個默認方法notRequired(),Defaulable接口的實現(xiàn)者之一DefaultableImpl實現(xiàn)了這個接口乍楚,并且讓默認方法保持原樣当编。Defaulable接口的另一個實現(xiàn)者OverridableImpl用自己的方法覆蓋了默認方法。
Java 8帶來的另一個有趣的特性是接口可以聲明(并且可以提供實現(xiàn))靜態(tài)方法炊豪。例如:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">private interface DefaulableFactory {
// Interfaces now allow static methods
static Defaulable create( Supplier< Defaulable > supplier ) {
return supplier.get();
}
}
</pre>
下面的一小段代碼片段把上面的默認方法與靜態(tài)方法黏合到一起凌箕。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">public static void main( String[] args ) {
Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new );
System.out.println( defaulable.notRequired() );
defaulable = DefaulableFactory.create( OverridableImpl::new );
System.out.println( defaulable.notRequired() );
}
</pre>
這個程序的控制臺輸出如下:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Default implementation
Overridden implementation
</pre>
在JVM中,默認方法的實現(xiàn)是非常高效的词渤,并且通過字節(jié)碼指令為方法調(diào)用提供了支持。默認方法允許繼續(xù)使用現(xiàn)有的Java接口串绩,而同時能夠保障正常的編譯過程缺虐。這方面好的例子是大量的方法被添加到j(luò)ava.util.Collection接口中去:stream(),parallelStream()礁凡,forEach()高氮,removeIf(),……
盡管默認方法非常強大剪芍,但是在使用默認方法時我們需要小心注意一個地方:在聲明一個默認方法前塞淹,請仔細思考是不是真的有必要使用默認方法,因為默認方法會帶給程序歧義罪裹,并且在復(fù)雜的繼承體系中容易產(chǎn)生編譯錯誤饱普。更多詳情請參考官方文檔
2.3 方法引用
方法引用提供了非常有用的語法,可以直接引用已有Java類或?qū)ο螅▽嵗┑姆椒ɑ驑?gòu)造器状共。與lambda聯(lián)合使用套耕,方法引用可以使語言的構(gòu)造更緊湊簡潔,減少冗余代碼峡继。
下面冯袍,我們以定義了4個方法的Car這個類作為例子,區(qū)分Java中支持的4種不同的方法引用碾牌。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">public static class Car {
public static Car create( final Supplier< Car > supplier ) {
return supplier.get();
}
public static void collide( final Car car ) {
System.out.println( "Collided " + car.toString() );
}
public void follow( final Car another ) {
System.out.println( "Following the " + another.toString() );
}
public void repair() {
System.out.println( "Repaired " + this.toString() );
}
}
</pre>
第一種方法引用是構(gòu)造器引用康愤,它的語法是Class::new,或者更一般的Class< T >::new舶吗。請注意構(gòu)造器沒有參數(shù)翘瓮。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );
</pre>
第二種方法引用是靜態(tài)方法引用,它的語法是Class::static_method裤翩。請注意這個方法接受一個Car類型的參數(shù)资盅。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">cars.forEach( Car::collide );
</pre>
第三種方法引用是特定類的任意對象的方法引用廷蓉,它的語法是Class::method俯渤。請注意饲化,這個方法沒有參數(shù)癌蓖。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">cars.forEach( Car::repair );
</pre>
最后哪痰,第四種方法引用是特定對象的方法引用搀捷,它的語法是instance::method茂装。請注意怎诫,這個方法接受一個Car類型的參數(shù)
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">final Car police = Car.create( Car::new );
cars.forEach( police::follow );
</pre>
運行上面的Java程序在控制臺上會有下面的輸出(Car的實例可能不一樣):
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Collided com.javacodegeeks.java8.method.references.MethodReferencesCar@7a81197d
Following the com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
</pre>
關(guān)于方法引用的更多詳情請參考官方文檔伦籍。
2.4 重復(fù)注解
自從Java 5引入了注解機制蓝晒,這一特性就變得非常流行并且廣為使用。然而帖鸦,使用注解的一個限制是相同的注解在同一位置只能聲明一次芝薇,不能聲明多次。Java 8打破了這條規(guī)則作儿,引入了重復(fù)注解機制洛二,這樣相同的注解可以在同一地方聲明多次。
重復(fù)注解機制本身必須用@Repeatable注解。事實上晾嘶,這并不是語言層面上的改變妓雾,更多的是編譯器的技巧,底層的原理保持不變垒迂。讓我們看一個快速入門的例子:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">package com.javacodegeeks.java8.repeatable.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class RepeatingAnnotations {
@Target( ElementType.TYPE )
@Retention( RetentionPolicy.RUNTIME )
public @interface Filters {
Filter[] value();
}
@Target( ElementType.TYPE )
@Retention( RetentionPolicy.RUNTIME )
@Repeatable( Filters.class )
public @interface Filter {
String value();
};
@Filter( "filter1" )
@Filter( "filter2" )
public interface Filterable {
}
public static void main(String[] args) {
for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) {
System.out.println( filter.value() );
}
}
}
</pre>
正如我們看到的械姻,這里有個使用@Repeatable( Filters.class )注解的注解類Filter,F(xiàn)ilters僅僅是Filter注解的數(shù)組机断,但Java編譯器并不想讓程序員意識到Filters的存在楷拳。這樣,接口Filterable就擁有了兩次Filter(并沒有提到Filter)注解毫缆。
同時唯竹,反射相關(guān)的API提供了新的函數(shù)getAnnotationsByType()來返回重復(fù)注解的類型(請注意Filterable.class.getAnnotation( Filters.class )經(jīng)編譯器處理后將會返回Filters的實例)。
程序輸出結(jié)果如下:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">filter1
filter2
</pre>
更多詳情請參考官方文檔
2.5 更好的類型推測機制
Java 8在類型推測方面有了很大的提高苦丁。在很多情況下浸颓,編譯器可以推測出確定的參數(shù)類型,這樣就能使代碼更整潔旺拉。讓我們看一個例子:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">package com.javacodegeeks.java8.type.inference;
public class Value< T > {
public static< T > T defaultValue() {
return null;
}
public T getOrDefault( T value, T defaultValue ) {
return ( value != null ) ? value : defaultValue;
}
}
</pre>
這里是Value< String >類型的用法产上。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">package com.javacodegeeks.java8.type.inference;
public class TypeInference {
public static void main(String[] args) {
final Value< String > value = new Value<>();
value.getOrDefault( "22", Value.defaultValue() );
}
}
</pre>
Value.defaultValue()的參數(shù)類型可以被推測出,所以就不必明確給出蛾狗。在Java 7中晋涣,相同的例子將不會通過編譯,正確的書寫方式是 Value.< String >defaultValue()沉桌。
2.6 擴展注解的支持
Java 8擴展了注解的上下文⌒蝗担現(xiàn)在幾乎可以為任何東西添加注解:局部變量、泛型類留凭、父類與接口的實現(xiàn)佃扼,就連方法的異常也能添加注解。下面演示幾個例子:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">package com.javacodegeeks.java8.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Collection;
public class Annotations {
@Retention( RetentionPolicy.RUNTIME )
@Target( { ElementType.TYPE_USE, ElementType.TYPE_PARAMETER } )
public @interface NonEmpty {
}
public static class Holder< @NonEmpty T > extends @NonEmpty Object {
public void method() throws @NonEmpty Exception {
}
}
@SuppressWarnings( "unused" )
public static void main(String[] args) {
final Holder< String > holder = new @NonEmpty Holder< String >();
@NonEmpty Collection< @NonEmpty String > strings = new ArrayList<>();
}
}
</pre>
ElementType.TYPE_USE和ElementType.TYPE_PARAMETER是兩個新添加的用于描述適當(dāng)?shù)淖⒔馍舷挛牡脑仡愋桶埂T贘ava語言中兼耀,注解處理API也有小的改動來識別新增的類型注解。
3. Java編譯器的新特性
3.1 參數(shù)名字
很長一段時間里求冷,Java程序員一直在發(fā)明不同的方式使得方法參數(shù)的名字能保留在Java字節(jié)碼中瘤运,并且能夠在運行時獲取它們(比如,Paranamer類庫)匠题。最終拯坟,在Java 8中把這個強烈要求的功能添加到語言層面(通過反射API與Parameter.getName()方法)與字節(jié)碼文件(通過新版的javac的–parameters選項)中。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">package com.javacodegeeks.java8.parameter.names;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
public class ParameterNames {
public static void main(String[] args) throws Exception {
Method method = ParameterNames.class.getMethod( "main", String[].class );
for( final Parameter parameter: method.getParameters() ) {
System.out.println( "Parameter: " + parameter.getName() );
}
}
}
</pre>
如果不使用–parameters參數(shù)來編譯這個類梧躺,然后運行這個類似谁,會得到下面的輸出:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Parameter: arg0
</pre>
如果使用–parameters參數(shù)來編譯這個類傲绣,程序的結(jié)構(gòu)會有所不同(參數(shù)的真實名字將會顯示出來):
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Parameter: args
</pre>
對于有經(jīng)驗的Maven用戶掠哥,通過maven-compiler-plugin的配置可以將-parameters參數(shù)添加到編譯器中去巩踏。
<pre class="brush: xml; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;"><plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<compilerArgument>-parameters</compilerArgument>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</pre>
針對Java 8最新發(fā)布的Eclipse Kepler SR2(請檢查這里的下載說明)提供了非常實用的配置選項,可以通過下圖的配置方式來控制編譯器行為
圖1. 配置Eclipse工程使之支持Java 8編譯器的新特性——parameters參數(shù)
此外续搀,Parameter類有一個很方便的方法isNamePresent()來驗證是否可以獲取參數(shù)的名字塞琼。
4. Java 類庫的新特性
Java 8 通過增加大量新類,擴展已有類的功能的方式來改善對并發(fā)編程禁舷、函數(shù)式編程彪杉、日期/時間相關(guān)操作以及其他更多方面的支持。
4.1 Optional
到目前為止牵咙,臭名昭著的空指針異常是導(dǎo)致Java應(yīng)用程序失敗的最常見原因派近。以前,為了解決空指針異常洁桌,Google公司著名的Guava項目引入了Optional類渴丸,Guava通過使用檢查空值的方式來防止代碼污染,它鼓勵程序員寫更干凈的代碼另凌。受到Google Guava的啟發(fā)谱轨,Optional類已經(jīng)成為Java 8類庫的一部分。
Optional實際上是個容器:它可以保存類型T的值吠谢,或者僅僅保存null土童。Optional提供很多有用的方法,這樣我們就不用顯式進行空值檢測工坊。更多詳情請參考官方文檔献汗。
我們下面用兩個小例子來演示如何使用Optional類:一個允許為空值,一個不允許為空值王污。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Optional< String > fullName = Optional.ofNullable( null );
System.out.println( "Full Name is set? " + fullName.isPresent() );
System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) );
System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
</pre>
如果Optional類的實例為非空值的話罢吃,isPresent()返回true,否從返回false玉掸。為了防止Optional為空值刃麸,orElseGet()方法通過回調(diào)函數(shù)來產(chǎn)生一個默認值。map()函數(shù)對當(dāng)前Optional的值進行轉(zhuǎn)化司浪,然后返回一個新的Optional實例泊业。orElse()方法和orElseGet()方法類似,但是orElse接受一個默認值而不是一個回調(diào)函數(shù)啊易。下面是這個程序的輸出:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Full Name is set? false
Full Name: [none]
Hey Stranger!
</pre>
讓我們來看看另一個例子:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Optional< String > firstName = Optional.of( "Tom" );
System.out.println( "First Name is set? " + firstName.isPresent() );
System.out.println( "First Name: " + firstName.orElseGet( () -> "[none]" ) );
System.out.println( firstName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
System.out.println();
</pre>
下面是程序的輸出:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">First Name is set? true
First Name: Tom
Hey Tom!
</pre>
更多詳情請參考官方文檔
4.2 Stream
最新添加的Stream API(java.util.stream) 把真正的函數(shù)式編程風(fēng)格引入到Java中吁伺。這是目前為止對Java類庫最好的補充,因為Stream API可以極大提供Java程序員的生產(chǎn)力租谈,讓程序員寫出高效率篮奄、干凈捆愁、簡潔的代碼。
Stream API極大簡化了集合框架的處理(但它的處理的范圍不僅僅限于集合框架的處理窟却,這點后面我們會看到)昼丑。讓我們以一個簡單的Task類為例進行介紹:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">public class Streams {
private enum Status {
OPEN, CLOSED
};
private static final class Task {
private final Status status;
private final Integer points;
Task( final Status status, final Integer points ) {
this.status = status;
this.points = points;
}
public Integer getPoints() {
return points;
}
public Status getStatus() {
return status;
}
@Override
public String toString() {
return String.format( "[%s, %d]", status, points );
}
}
}
</pre>
Task類有一個分數(shù)的概念(或者說是偽復(fù)雜度),其次是還有一個值可以為OPEN或CLOSED的狀態(tài).讓我們引入一個Task的小集合作為演示例子:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">final Collection< Task > tasks = Arrays.asList(
new Task( Status.OPEN, 5 ),
new Task( Status.OPEN, 13 ),
new Task( Status.CLOSED, 8 )
);
</pre>
我們下面要討論的第一個問題是所有狀態(tài)為OPEN的任務(wù)一共有多少分數(shù)夸赫?在Java 8以前菩帝,一般的解決方式用foreach循環(huán),但是在Java 8里面我們可以使用stream:一串支持連續(xù)茬腿、并行聚集操作的元素呼奢。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">// Calculate total points of all active tasks using sum()
final long totalPointsOfOpenTasks = tasks
.stream()
.filter( task -> task.getStatus() == Status.OPEN )
.mapToInt( Task::getPoints )
.sum();
System.out.println( "Total points: " + totalPointsOfOpenTasks );
</pre>
程序在控制臺上的輸出如下:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Total points: 18
</pre>
這里有幾個注意事項。第一切平,task集合被轉(zhuǎn)換化為其相應(yīng)的stream表示握础。然后,filter操作過濾掉狀態(tài)為CLOSED的task悴品。下一步禀综,mapToInt操作通過Task::getPoints這種方式調(diào)用每個task實例的getPoints方法把Task的stream轉(zhuǎn)化為Integer的stream。最后他匪,用sum函數(shù)把所有的分數(shù)加起來菇存,得到最終的結(jié)果。
在繼續(xù)講解下面的例子之前邦蜜,關(guān)于stream有一些需要注意的地方(詳情在這里).stream操作被分成了中間操作與最終操作這兩種依鸥。
中間操作返回一個新的stream對象。中間操作總是采用惰性求值方式悼沈,運行一個像filter這樣的中間操作實際上沒有進行任何過濾贱迟,相反它在遍歷元素時會產(chǎn)生了一個新的stream對象,這個新的stream對象包含原始stream
中符合給定謂詞的所有元素絮供。
像forEach衣吠、sum這樣的最終操作可能直接遍歷stream,產(chǎn)生一個結(jié)果或副作用壤靶。當(dāng)最終操作執(zhí)行結(jié)束之后缚俏,stream管道被認為已經(jīng)被消耗了,沒有可能再被使用了贮乳。在大多數(shù)情況下忧换,最終操作都是采用及早求值方式,及早完成底層數(shù)據(jù)源的遍歷向拆。
stream另一個有價值的地方是能夠原生支持并行處理亚茬。讓我們來看看這個算task分數(shù)和的例子。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">// Calculate total points of all tasks
final double totalPoints = tasks
.stream()
.parallel()
.map( task -> task.getPoints() ) // or map( Task::getPoints )
.reduce( 0, Integer::sum );
System.out.println( "Total points (all tasks): " + totalPoints );
</pre>
這個例子和第一個例子很相似浓恳,但這個例子的不同之處在于這個程序是并行運行的刹缝,其次使用reduce方法來算最終的結(jié)果碗暗。
下面是這個例子在控制臺的輸出:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Total points (all tasks): 26.0
</pre>
經(jīng)常會有這個一個需求:我們需要按照某種準(zhǔn)則來對集合中的元素進行分組。Stream也可以處理這樣的需求梢夯,下面是一個例子:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">// Group tasks by their status
final Map< Status, List< Task > > map = tasks
.stream()
.collect( Collectors.groupingBy( Task::getStatus ) );
System.out.println( map );
</pre>
這個例子的控制臺輸出如下:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">{CLOSED=[[CLOSED, 8]], OPEN=[[OPEN, 5], [OPEN, 13]]}
</pre>
讓我們來計算整個集合中每個task分數(shù)(或權(quán)重)的平均值來結(jié)束task的例子言疗。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">// Calculate the weight of each tasks (as percent of total points)
final Collection< String > result = tasks
.stream() // Stream< String >
.mapToInt( Task::getPoints ) // IntStream
.asLongStream() // LongStream
.mapToDouble( points -> points / totalPoints ) // DoubleStream
.boxed() // Stream< Double >
.mapToLong( weigth -> ( long )( weigth * 100 ) ) // LongStream
.mapToObj( percentage -> percentage + "%" ) // Stream< String>
.collect( Collectors.toList() ); // List< String >
System.out.println( result );
</pre>
下面是這個例子的控制臺輸出:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">[19%, 50%, 30%]
</pre>
最后,就像前面提到的厨疙,Stream API不僅僅處理Java集合框架洲守。像從文本文件中逐行讀取數(shù)據(jù)這樣典型的I/O操作也很適合用Stream API來處理疑务。下面用一個例子來應(yīng)證這一點沾凄。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">final Path path = new File( filename ).toPath();
try( Stream< String > lines = Files.lines( path, StandardCharsets.UTF_8 ) ) {
lines.onClose( () -> System.out.println("Done!") ).forEach( System.out::println );
}
</pre>
對一個stream對象調(diào)用onClose方法會返回一個在原有功能基礎(chǔ)上新增了關(guān)閉功能的stream對象,當(dāng)對stream對象調(diào)用close()方法時知允,與關(guān)閉相關(guān)的處理器就會執(zhí)行撒蟀。
Stream API、Lambda表達式與方法引用在接口默認方法與靜態(tài)方法的配合下是Java 8對現(xiàn)代軟件開發(fā)范式的回應(yīng)温鸽。更多詳情請參考官方文檔保屯。
4.3 Date/Time API (JSR 310)
Java 8通過發(fā)布新的Date-Time API (JSR 310)來進一步加強對日期與時間的處理。對日期與時間的操作一直是Java程序員最痛苦的地方之一涤垫。標(biāo)準(zhǔn)的 java.util.Date以及后來的java.util.Calendar一點沒有改善這種情況(可以這么說姑尺,它們一定程度上更加復(fù)雜)。
這種情況直接導(dǎo)致了Joda-Time——一個可替換標(biāo)準(zhǔn)日期/時間處理且功能非常強大的Java API的誕生蝠猬。Java 8新的Date-Time API (JSR 310)在很大程度上受到Joda-Time的影響切蟋,并且吸取了其精髓。新的java.time包涵蓋了所有處理日期榆芦,時間柄粹,日期/時間,時區(qū)匆绣,時刻(instants)驻右,過程(during)與時鐘(clock)的操作。在設(shè)計新版API時崎淳,十分注重與舊版API的兼容性:不允許有任何的改變(從java.util.Calendar中得到的深刻教訓(xùn))堪夭。如果需要修改,會返回這個類的一個新實例拣凹。
讓我們用例子來看一下新版API主要類的使用方法森爽。第一個是Clock類,它通過指定一個時區(qū)咐鹤,然后就可以獲取到當(dāng)前的時刻拗秘,日期與時間。Clock可以替換System.currentTimeMillis()與TimeZone.getDefault()祈惶。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">// Get the system clock as UTC offset
final Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );
System.out.println( clock.millis() );
</pre>
下面是程序在控制臺上的輸出:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">2014-04-12T15:19:29.282Z
1397315969360
</pre>
我們需要關(guān)注的其他類是LocaleDate與LocalTime雕旨。LocaleDate只持有ISO-8601格式且無時區(qū)信息的日期部分扮匠。相應(yīng)的,LocaleTime只持有ISO-8601格式且無時區(qū)信息的時間部分凡涩。LocaleDate與LocalTime都可以從Clock中得到棒搜。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">// Get the local date and local time
final LocalDate date = LocalDate.now();
final LocalDate dateFromClock = LocalDate.now( clock );
System.out.println( date );
System.out.println( dateFromClock );
// Get the local date and local time
final LocalTime time = LocalTime.now();
final LocalTime timeFromClock = LocalTime.now( clock );
System.out.println( time );
System.out.println( timeFromClock );
</pre>
下面是程序在控制臺上的輸出:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">2014-04-12
2014-04-12
11:25:54.568
15:25:54.568
</pre>
LocaleDateTime把LocaleDate與LocaleTime的功能合并起來,它持有的是ISO-8601格式無時區(qū)信息的日期與時間活箕。下面是一個快速入門的例子力麸。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">// Get the local date/time
final LocalDateTime datetime = LocalDateTime.now();
final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );
System.out.println( datetime );
System.out.println( datetimeFromClock );
</pre>
下面是程序在控制臺上的輸出:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">2014-04-12T11:37:52.309
2014-04-12T15:37:52.309
</pre>
如果你需要特定時區(qū)的日期/時間,那么ZonedDateTime是你的選擇育韩。它持有ISO-8601格式具具有時區(qū)信息的日期與時間克蚂。下面是一些不同時區(qū)的例子:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">// Get the zoned date/time
final ZonedDateTime zonedDatetime = ZonedDateTime.now();
final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now( clock );
final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) );
System.out.println( zonedDatetime );
System.out.println( zonedDatetimeFromClock );
System.out.println( zonedDatetimeFromZone );
</pre>
下面是程序在控制臺上的輸出:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">2014-04-12T11:47:01.017-04:00[America/New_York]
2014-04-12T15:47:01.017Z
2014-04-12T08:47:01.017-07:00[America/Los_Angeles]
</pre>
最后,讓我們看一下Duration類:在秒與納秒級別上的一段時間筋讨。Duration使計算兩個日期間的不同變的十分簡單埃叭。下面讓我們看一個這方面的例子。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">// Get duration between two dates
final LocalDateTime from = LocalDateTime.of( 2014, Month.APRIL, 16, 0, 0, 0 );
final LocalDateTime to = LocalDateTime.of( 2015, Month.APRIL, 16, 23, 59, 59 );
final Duration duration = Duration.between( from, to );
System.out.println( "Duration in days: " + duration.toDays() );
System.out.println( "Duration in hours: " + duration.toHours() );
</pre>
上面的例子計算了兩個日期2014年4月16號與2014年4月16號之間的過程悉罕。下面是程序在控制臺上的輸出:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Duration in days: 365
Duration in hours: 8783
</pre>
對Java 8在日期/時間API的改進整體印象是非常非常好的赤屋。一部分原因是因為它建立在“久戰(zhàn)殺場”的Joda-Time基礎(chǔ)上,另一方面是因為用來大量的時間來設(shè)計它壁袄,并且這次程序員的聲音得到了認可类早。更多詳情請參考官方文檔。
4.4 JavaScript引擎Nashorn
Nashorn嗜逻,一個新的JavaScript引擎隨著Java 8一起公諸于世涩僻,它允許在JVM上開發(fā)運行某些JavaScript應(yīng)用。Nashorn就是javax.script.ScriptEngine的另一種實現(xiàn)变泄,并且它們倆遵循相同的規(guī)則令哟,允許Java與JavaScript相互調(diào)用。下面看一個例子:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace;">ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName( "JavaScript" );
System.out.println( engine.getClass().getName() );
System.out.println( "Result:" + engine.eval( "function f() { return 1; }; f() + 1;" ) );
</pre>
下面是程序在控制臺上的輸出:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace;">jdk.nashorn.api.scripting.NashornScriptEngine
Result: 2
</pre>
我們在后面的Java新工具章節(jié)會再次談到Nashorn妨蛹。
4.5 Base64
在Java 8中屏富,Base64編碼已經(jīng)成為Java類庫的標(biāo)準(zhǔn)。它的使用十分簡單蛙卤,下面讓我們看一個例子:
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">package com.javacodegeeks.java8.base64;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class Base64s {
public static void main(String[] args) {
final String text = "Base64 finally in Java 8!";
final String encoded = Base64
.getEncoder()
.encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
System.out.println( encoded );
final String decoded = new String(
Base64.getDecoder().decode( encoded ),
StandardCharsets.UTF_8 );
System.out.println( decoded );
}
}
</pre>
程序在控制臺上輸出了編碼后的字符與解碼后的字符:
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ==
Base64 finally in Java 8!
</pre>
Base64類同時還提供了對URL狠半、MIME友好的編碼器與解碼器(Base64.getUrlEncoder() / Base64.getUrlDecoder(), Base64.getMimeEncoder() / Base64.getMimeDecoder())。
4.6 并行(parallel)數(shù)組
Java 8增加了大量的新方法來對數(shù)組進行并行處理颤难∩衲辏可以說,最重要的是parallelSort()方法行嗤,因為它可以在多核機器上極大提高數(shù)組排序的速度已日。下面的例子展示了新方法(parallelXxx)的使用。
<pre class="brush: java; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">package com.javacodegeeks.java8.parallel.arrays;
import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;
public class ParallelArrays {
public static void main( String[] args ) {
long[] arrayOfLong = new long [ 20000 ];
Arrays.parallelSetAll( arrayOfLong,
index -> ThreadLocalRandom.current().nextInt( 1000000 ) );
Arrays.stream( arrayOfLong ).limit( 10 ).forEach(
i -> System.out.print( i + " " ) );
System.out.println();
Arrays.parallelSort( arrayOfLong );
Arrays.stream( arrayOfLong ).limit( 10 ).forEach(
i -> System.out.print( i + " " ) );
System.out.println();
}
}
</pre>
上面的代碼片段使用了parallelSetAll()方法來對一個有20000個元素的數(shù)組進行隨機賦值栅屏。然后飘千,調(diào)用parallelSort方法堂鲜。這個程序首先打印出前10個元素的值,之后對整個數(shù)組排序护奈。這個程序在控制臺上的輸出如下(請注意數(shù)組元素是隨機生產(chǎn)的):
<pre class="brush:shell; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378
Sorted: 39 220 263 268 325 607 655 678 723 793
</pre>
4.7 并發(fā)(Concurrency)
在新增Stream機制與lambda的基礎(chǔ)之上缔莲,在java.util.concurrent.ConcurrentHashMap中加入了一些新方法來支持聚集操作。同時也在java.util.concurrent.ForkJoinPool類中加入了一些新方法來支持共有資源池(common pool)(請查看我們關(guān)于Java 并發(fā)的免費課程)霉旗。
新增的java.util.concurrent.locks.StampedLock類提供一直基于容量的鎖痴奏,這種鎖有三個模型來控制讀寫操作(它被認為是不太有名的java.util.concurrent.locks.ReadWriteLock類的替代者)。
在java.util.concurrent.atomic包中還增加了下面這些類:
- DoubleAccumulator
- DoubleAdder
- LongAccumulator
- LongAdder
5. 新的Java工具
Java 8也帶來了一些新的命令行工具厌秒。在這節(jié)里我們將會介紹它們中最有趣的部分读拆。
5.1 Nashorn引擎: jjs
jjs是個基于Nashorn引擎的命令行工具。它接受一些JavaScript源代碼為參數(shù)简僧,并且執(zhí)行這些源代碼建椰。例如,我們創(chuàng)建一個具有如下內(nèi)容的func.js文件:
<pre class="brush: javascript; gutter: true; first-line: 1; highlight: []; html-script: false" style="border: 0px; margin: 0px 0px 20px; padding: 0px; font-size: 14px; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">function f() {
return 1;
};
print( f() + 1 );
</pre>
我們可以把這個文件作為參數(shù)傳遞給jjs使得這個文件可以在命令行中執(zhí)行:
https://blog.csdn.net/liubenlong007/article/details/62039628