JDK8.0新特性


連接轉載地址:http://www.2cto.com/kf/201609/544044.html

Eclipse:

http://aiyiupload.oss-cn-beijing.aliyuncs.com/blog/file/default/eclipse-jee-neon-R-win32-x86_64.zip

JDK8:

http://aiyiupload.oss-cn-beijing.aliyuncs.com/blog/file/default/jdk-8u91-windows-x64.exe

特性一,接口的默認方法

在JDK8中,允許給接口本身添加一個默認的實現。用“default”進行修飾。下面我創建一個MyCompute接口,並給他的sum方法一個默認的實現。

package com.aiyi.jdk.testinterface;

/**

* 我的Compute類

* @author 郭勝凱

* @emai 719348277@qq.com

* @time 2016年7月4日 下午1:07:42

*/

public interface MyCompute {

/**

* 定義加法運算並給他默認實現方法

* @param i1 加數

* @param i2 加數

* @return 和

*/

default int sum(int i1, int i2){

return i1 + i2;

}

/**

* 定義減法運算接口

* @param i1 減數

* @param i2 被減數

* @return 差

*/

int subtraction(int i1, int i2);

}

那么我來測試一下這個MyCompute,因為我已經給了他sum的默認實現,所以我只需要再實現 subtraction() 方法就行了:

public static void main(String[] args) {

MyCompute c = new MyCompute() {

@Override

public int subtraction(int i1, int i2) {

// TODO Auto-generated method stub

return i1 - i2;

}

};

//Test sum function, result = 2

int result = c.sum(1, 1);

//Test subtraction function, result2 = 0

int result2 = c.subtraction(1, -1);

}

特性二,靜態方法與構造函數的引用

這一點兒類似在C++中的《函數指針》的概念。我們可以這么理解(至少我是這么認為的),在Java中,方法和構造方法都看作是對象的一種,那么你要引用它(不是調用),則可以用::來引用。用來存儲這個引用的類型用@FunctionlaInterface注解來標識。

方法引用對象的創建

我繼續以上面的例子進行解釋,加入我要引用 MyCompute 中的 sun(int, int); 這個方法,可以就如下代碼

創建一個存儲方法的對象:

package com.aiyi.jdk.testinterface;

/**

* 方法引用類

* @author 郭勝凱

* @emai 719348277@qq.com

* @time 2016年7月4日 下午1:32:23

*/

public class MyFunction {

/**

* 指向某個Function的方法指針

* @author 郭勝凱

* @emai 719348277@qq.com

* @time 2016年7月4日 下午1:31:07

* @param 傳值類型

* @param 結果類型

*/

@FunctionalInterface

interface Fun {

T run(F from);

}

}

方法引用對象的使用

接下來我用這個Fun來引用一個方法。並執行他。(“Main::myMethod”表示 Main 類中的 myMethod() 方法)

輸出結果是”This is arg”

public static void main(String[] args) {

Fun fun = Main::myMethod;

String result = fun.run("This is arg");

System.out.println(result);

}

/**

* 指向某個Function的方法指針

* @author 郭勝凱

* @emai 719348277@qq.com

* @time 2016年7月4日 下午1:31:07

* @param 傳值類型

* @param 結果類型

*/

@FunctionalInterface

interface Fun {

T run(F from);

}

public static String myMethod(String arg){

return arg;

}

構造函數引用對象的創建及使用

大同小異,就不多說了,輸出結果“Creating”

public Main(String arg){

System.out.println(arg);

}

@FunctionalInterface

interface mainFactory{

M run(String arg);

}

public static void main(String[] args) {

mainFactory mainFun = Main::new;

mainFun.run("Creating");

}

特性三,玩死你不償命的Lambda表達式

在JDK8中,引入了Lambda(讀:了母的)表達式的概念,不得不說這Lambda實在是太強大了,強大了不止一點兒半點兒。看我一點兒一點兒慢慢的介紹它~

入門

(破天荒地用了一段兒英文注釋,因為我在鍛煉英文)

我來用一個簡單的例子來講解lambda有多么逆天。在JDK7中如果要對一個list進行排序的話,或許你是這樣做的:

/**

* This is the sorting of ‘JDK7’

*/

public static void testSort1(){

List list = Arrays.asList("asd","dweas","aw","trs");

//Create a comparator

Comparator mySort = new Comparator() {

@Override

public int compare(String srt1, String str2) {

// TODO Auto-generated method stub

return srt1.compareTo(str2);

}

};

//Sorting...

Collections.sort(list, mySort);

}

假如用lambda來完成上面這個排序的話,你可以一行代碼搞定:

/**

* This is the sorting of ‘JDK8' s lambda’(了母的)

*/

public static void testSort2(){

List list = Arrays.asList("asd","dweas","aw","trs");

//Sorting...

Collections.sort(list, (str1, str2) -> str1.compareTo(str2));

}

沒錯,就是這么嗨!仔細看“->”后面是一個Integer值得表達式,假如我的運算比較復雜的話,那么我還可以把他變成一個代碼塊:

/**

* This is the sorting of ‘JDK8' s lambda’(了母的)

*/

public static void testSort2(){

List list = Arrays.asList("asd","dweas","aw","trs");

//Sorting...

Collections.sort(list, (str1, str2) -> {

return str1.compareTo(str2);

});

}

如果你以為lambda表達式就這么點兒含量的話,說出去會被人笑話的,上面只是舉一個簡單易懂的例子,這個例子運用的只是lambda表達式中的冰山一角!

Lambda表達式在Java中的定義:

每一個lambda表達式都對應一個類型,通常是接口類型。每一個Lambda表達式,都會匹配一個對應“函數式接口”的東西。

“函數式接口”是指僅僅只包含一個抽象方法的接口,即標注@FunctionalInterface的接口類。在上面剛剛就介紹了“函數式接口”了,請參閱《特性二》的說明

並且,你還可以給你的函數式接口添加默認方法。

我們重新創建一個MyFunction這個類

/**

* 方法類

* @author 郭勝凱

* @emai 719348277@qq.com

* @time 2016年7月4日 下午1:32:23

*/

public class MyFunction {

public static int sum(int i1, int i2){

return i1 + i2;

}

}

回到Main類中,我用Lambda表達式調用一下他,輸出結果:2,即1+1的和

public static void main(String[] args) {

Fun fun = (i1, i2) -> MyFunction.sum(i1, i2);

System.out.println(fun.run(1, 1));

}

/**

* 指向某個Function的方法指針

* @author 郭勝凱

* @emai 719348277@qq.com

* @time 2016年7月4日 下午1:31:07

* @param 參數1類型

* @param 參數2類型

*/

@FunctionalInterface

interface Fun {

int run(T arg1, U arg2);

}

深入理解lambda

為了深入理解lambda,繼續用之前的list排序案例來說,這次我們手動建立一個支持lambda的排序工具類。

1、new一個抽象的比較器

package com.aiyi.jdk.testilambda;

public interface MyComparator {

int sort(String str1, String str2);

}

2、new一個排序工具類

package com.aiyi.jdk.testilambda;

import java.util.List;

public class MySortUtil {

public static void sortList (List list, MyComparator comparator){

for (int i = 0; i < list.size(); i++) {

for (int j = i + 1; j < list.size(); j++) {

T temp = list.get(i);

if (comparator.sort(list.get(i), list.get(j)) > 0) {

list.set(i, list.get(j));

list.set(j, temp);

}

}

}

}

}

3、使用lambda調用這個排序工具類進行排序

public static void testSort3(){

List list = Arrays.asList("asd","dweas","aw","trs");

//Sorting...

MySortUtil.sortList(list, (str1, str2) -> {

return str1.compareTo(str2);

});

}

搞定,是不是呢上面那個入門代碼超級像?

lambda的作用域

lambda的作用域和內部類的作用於差不多,訪問局部變量必須由final進行修飾。即不可更改。訪問成員變量或者靜態字段的話,則不需要final修飾,並且可以對其進行修改。

JDK8中lambda支持的其他接口

Predicate

predicate接收一個變量,並返回一個boolean值,predicate接口是一個簡單的比進行較運算操作的接口,但一般不使用。例如:

Predicate p = (str) -> str.equls("321aiyi.com");

sysout(p.test("321aiyi.com")); //true

sysout(p.test("321aiyi.com").negate()) //false

Function

這個接口其實就是一個單純的最簡單的實現了@FunctionalInterface的接口類,一般對一個方法進行引用時,可以直接使用該接口。

Function fun = String::valueOf;

String str = fun.apply(1);

Supplier

這個就更簡單了,他就相當於類的Factory,用它獲取任意一個帶有空參構造的類。

Supplier s = StringBuffer::new;

StringBuffer sb = s.get();

Consumer

給定一個參數,並對其進行操作

Consumer c = (str) -> System.out.pringln(str + "~~~");

c.accept("woca"); //"woca~~~"

另外,還有好多之前的接口也做了對lambda的支持,比如之前所說的Comparator接口等等,這里就不一一訴說了,喜歡鑽研的朋友們可以拔源碼或者閱讀相關文檔慢慢看。

特性四、反射的加強

JDK8加強了反射,它允許你直接通過反射獲取參數的名字

很長一段時間里,Java程序員一直在發明不同的方式使得方法參數的名字能保留在Java字節碼中,並且能夠在運行時獲取它們(比如,Paranamer類庫)。最終,在Java 8中把這個強烈要求的功能添加到語言層面(通過反射API與Parameter.getName()方法)與字節碼文件(通過新版的javac的–parameters選項)中。

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() );

}

}

}

如果不使用–parameters參數來編譯這個類,然后運行這個類,會得到下面的輸出:

Parameter: arg0

如果使用–parameters參數來編譯這個類,程序的結構會有所不同(參數的真實名字將會顯示出來):

Parameter: args

對於有經驗的Maven用戶,通過maven-compiler-plugin的配置可以將-parameters參數添加到編譯器中去。

針對Java 8最新發布的Eclipse Kepler SR2提供了非常實用的配置選項,可以通過下圖的配置方式來控制編譯器行為,在這里,阿海在前面提到的Eclipse-Neon(目前最新的版本)版本同樣具有這樣的配置項,以下是開啟該項的配置圖:

 

Eclipse開啟Parameter.getName()支持

 

設置步驟:Window->Preferences->Java->Compiler

此外,Parameter類有一個很方便的方法isNamePresent()來驗證是否可以獲取參數的名字。

下面的是我從網絡上copy的,需要記得東西太多,copy下來慢慢消化。。。

Java 類庫的新特性(copy)

Java 8 通過增加大量新類,擴展已有類的功能的方式來改善對並發編程、函數式編程、日期/時間相關操作以及其他更多方面的支持。

4.1 Optional

到目前為止,臭名昭著的空指針異常是導致Java應用程序失敗的最常見原因。以前,為了解決空指針異常,Google公司著名的Guava項目引入了Optional類,Guava通過使用檢查空值的方式來防止代碼污染,它鼓勵程序員寫更干凈的代碼。受到Google Guava的啟發,Optional類已經成為Java 8類庫的一部分。

Optional實際上是個容器:它可以保存類型T的值,或者僅僅保存null。Optional提供很多有用的方法,這樣我們就不用顯式進行空值檢測。更多詳情請參考官方文檔。

我們下面用兩個小例子來演示如何使用Optional類:一個允許為空值,一個不允許為空值。

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!" ) );

如果Optional類的實例為非空值的話,isPresent()返回true,否從返回false。

為了防止Optional為空值,orElseGet()方法通過回調函數來產生一個默認值。map()函數對當前Optional的值進行轉化,然后返回一個新的Optional實例。orElse()方法和orElseGet()方法類似,但是orElse接受一個默認值而不是一個回調函數。

下面是這個程序的輸出:

Full Name is set? false Full

Name: [none]

Hey Stranger!

讓我們來看看另一個例子:

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();

下面是程序輸出

First Name is set? true

First Name: Tom

Hey Tom!

更多詳情請參考官方文檔(http://docs.oracle.com/javase/8/docs/api/java/util/Optional.html)

Stream

最新添加的Stream API(java.util.stream) 把真正的函數式編程風格引入到Java中。這是目前為止對Java類庫最好的補充,因為Stream API可以極大提供Java程序員的生產力,讓程序員寫出高效率、干凈、簡潔的代碼。

Stream API極大簡化了集合框架的處理(但它的處理的范圍不僅僅限於集合框架的處理,這點后面我們會看到)。讓我們以一個簡單的Task類為例進行介紹:

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 );

}

}

}

Task類有一個分數的概念(或者說是偽復雜度),其次是還有一個值可以為OPEN或CLOSED的狀態.讓我們引入一個Task的小集合作為演示例子:

final Collection< Task > tasks = Arrays.asList(

new Task( Status.OPEN, 5 ),

new Task( Status.OPEN, 13 ),

new Task( Status.CLOSED, 8 )

);

我們下面要討論的第一個問題是所有狀態為OPEN的任務一共有多少分數?在Java 8以前,一般的解決方式用foreach循環,但是在Java 8里面我們可以使用stream:一串支持連續、並行聚集操作的元素。

// 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 );

程序在控制台上的輸出如下:

Total points: 18

這里有幾個注意事項。第一,task集合被轉換化為其相應的stream表示。然后,filter操作過濾掉狀態為CLOSED的task。下一步,mapToInt操作通過Task::getPoints這種方式調用每個task實例的getPoints方法把Task的stream轉化為Integer的stream。最后,用sum函數把所有的分數加起來,得到最終的結果。

在繼續講解下面的例子之前,關於stream有一些需要注意的地方(詳情在這里).stream操作被分成了中間操作與最終操作這兩種。

中間操作返回一個新的stream對象。中間操作總是采用惰性求值方式,運行一個像filter這樣的中間操作實際上沒有進行任何過濾,相反它在遍歷元素時會產生了一個新的stream對象,這個新的stream對象包含原始stream

中符合給定謂詞的所有元素。

像forEach、sum這樣的最終操作可能直接遍歷stream,產生一個結果或副作用。當最終操作執行結束之后,stream管道被認為已經被消耗了,沒有可能再被使用了。在大多數情況下,最終操作都是采用及早求值方式,及早完成底層數據源的遍歷。

stream另一個有價值的地方是能夠原生支持並行處理。讓我們來看看這個算task分數和的例子。

// 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 );

這個例子和第一個例子很相似,但這個例子的不同之處在於這個程序是並行運行的,其次使用reduce方法來算最終的結果。

下面是這個例子在控制台的輸出:

Total points (all tasks): 26.0

經常會有這個一個需求:我們需要按照某種准則來對集合中的元素進行分組。Stream也可以處理這樣的需求,下面是一個例子:

// Group tasks by their status

final Map< Status, List< Task > > map = tasks

.stream()

.collect( Collectors.groupingBy( Task::getStatus ) );

System.out.println( map );

這個例子的控制台輸出如下:

{CLOSED=[[CLOSED, 8]], OPEN=[[OPEN, 5], [OPEN, 13]]}

讓我們來計算整個集合中每個task分數(或權重)的平均值來結束task的例子。

// 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 );

輸出結果

[19%, 50%, 30%]

最后,就像前面提到的,Stream API不僅僅處理Java集合框架。像從文本文件中逐行讀取數據這樣典型的I/O操作也很適合用Stream API來處理。下面用一個例子來應證這一點。

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 );

}

對一個stream對象調用onClose方法會返回一個在原有功能基礎上新增了關閉功能的stream對象,當對stream對象調用close()方法時,與關閉相關的處理器就會執行。

Stream API、Lambda表達式與方法引用在接口默認方法與靜態方法的配合下是Java 8對現代軟件開發范式的回應。更多詳情請參考官方文檔(http://docs.oracle.com/javase/tutorial/collections/streams/index.html)。

Date/Time API (JSR 310)

Java 8通過發布新的Date-Time API (JSR 310)來進一步加強對日期與時間的處理。對日期與時間的操作一直是Java程序員最痛苦的地方之一。標准的 java.util.Date以及后來的java.util.Calendar一點沒有改善這種情況(可以這么說,它們一定程度上更加復雜)。

這種情況直接導致了Joda-Time——一個可替換標准日期/時間處理且功能非常強大的Java API的誕生。Java 8新的Date-Time API (JSR 310)在很大程度上受到Joda-Time的影響,並且吸取了其精髓。新的java.time包涵蓋了所有處理日期,時間,日期/時間,時區,時刻(instants),過程(during)與時鍾(clock)的操作。在設計新版API時,十分注重與舊版API的兼容性:不允許有任何的改變(從java.util.Calendar中得到的深刻教訓)。如果需要修改,會返回這個類的一個新實例。

讓我們用例子來看一下新版API主要類的使用方法。第一個是Clock類,它通過指定一個時區,然后就可以獲取到當前的時刻,日期與時間。Clock可以替換System.currentTimeMillis()與TimeZone.getDefault()。

// Get the system clock as UTC offset

final Clock clock = Clock.systemUTC();

System.out.println( clock.instant() );

System.out.println( clock.millis() );

下面是控制台的輸出

2014-04-12T15:19:29.282Z

1397315969360

我們需要關注的其他類是LocaleDate與LocalTime。LocaleDate只持有ISO-8601格式且無時區信息的日期部分。相應的,LocaleTime只持有ISO-8601格式且無時區信息的時間部分。LocaleDate與LocalTime都可以從Clock中得到。

// 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 );

程序運行結果:

2014-04-12

2014-04-12

11:25:54.568

15:25:54.568

LocaleDateTime把LocaleDate與LocaleTime的功能合並起來,它持有的是ISO-8601格式無時區信息的日期與時間。下面是一個快速入門的例子。

// Get the local date/time

final LocalDateTime datetime = LocalDateTime.now();

final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );

System.out.println( datetime );

System.out.println( datetimeFromClock );

控制台的輸出

2014-04-12T11:37:52.309

2014-04-12T15:37:52.309

如果你需要特定時區的日期/時間,那么ZonedDateTime是你的選擇。它持有ISO-8601格式具具有時區信息的日期與時間。下面是一些不同時區的例子:

// 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 );

下面是程序在控制台的輸出

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]

最后,讓我們看一下Duration類:在秒與納秒級別上的一段時間。Duration使計算兩個日期間的不同變的十分簡單。下面讓我們看一個這方面的例子。

// 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() );

上面的例子計算了兩個日期2014年4月16號與2014年4月16號之間的過程。下面是程序在控制台上的輸出:

Duration in days: 365

Duration in hours: 8783

對Java 8在日期/時間API的改進整體印象是非常非常好的。一部分原因是因為它建立在“久戰殺場”的Joda-Time基礎上,另一方面是因為用來大量的時間來設計它,並且這次程序員的聲音得到了認可。更多詳情請參考官方文檔(http://docs.oracle.com/javase/tutorial/datetime/index.html)。

JavaScript引擎Nashorn

Nashorn,一個新的JavaScript引擎隨着Java 8一起公諸於世,它允許在JVM上開發運行某些JavaScript應用。Nashorn就是javax.script.ScriptEngine的另一種實現,並且它們倆遵循相同的規則,允許Java與JavaScript相互調用。下面看一個例子:

ScriptEngineManager manager = new ScriptEngineManager();

ScriptEngine engine = manager.getEngineByName( "JavaScript" );

System.out.println(engine.getClass().getName());

//Run JS

System.out.println("Result:" + engine.eval("function f() { return 1; }; f() + 1;"));

控制台的輸出:

jdk.nashorn.api.scripting.NashornScriptEngineResult: 2

Base64

在Java 8中,Base64編碼已經成為Java類庫的標准。它的使用十分簡單,下面讓我們看一個例子:

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 );

}

}

程序在控制台上輸出了編碼后的字符與解碼后的字符:

QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ==

Base64 finally in Java 8!

Base64類同時還提供了對URL、MIME友好的編碼器與解碼器

(Base64.getUrlEncoder() / Base64.getUrlDecoder(), Base64.getMimeEncoder() / Base64.getMimeDecoder())。

並行(parallel)數組

Java 8增加了大量的新方法來對數組進行並行處理。可以說,最重要的是parallelSort()方法,因為它可以在多核機器上極大提高數組排序的速度。下面的例子展示了新方法(parallelXxx)的使用。

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();

}

}

上面的代碼片段使用了parallelSetAll()方法來對一個有20000個元素的數組進行隨機賦值。然后,調用parallelSort方法。這個程序首先打印出前10個元素的值,之后對整個數組排序。這個程序在控制台上的輸出如下(請注意數組元素是隨機生產的):

Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378

Sorted: 39 220 263 268 325 607 655 678 723 793

並發(Concurrency)

在新增Stream機制與lambda的基礎之上,在java.util.concurrent.ConcurrentHashMap中加入了一些新方法來支持聚集操作。同時也在java.util.concurrent.ForkJoinPool類中加入了一些新方法來支持共有資源池(common pool)(請查看我們關於Java 並發的免費課程)。

新增的java.util.concurrent.locks.StampedLock類提供一直基於容量的鎖,這種鎖有三個模型來控制讀寫操作(它被認為是不太有名的java.util.concurrent.locks.ReadWriteLock類的替代者)。

在java.util.concurrent.atomic包中還增加了下面這些類:

DoubleAccumulator DoubleAdder LongAccumulator LongAdder

新的Java工具

Java 8也帶來了一些新的命令行工具。在這節里我們將會介紹它們中最有趣的部分。

Nashorn引擎: jjs

jjs是個基於Nashorn引擎的命令行工具。它接受一些JavaScript源代碼為參數,並且執行這些源代碼。例如,我們創建一個具有如下內容的func.js文件:

function f() {

return 1;

};

print( f() + 1 );

我們可以把這個文件作為參數傳遞給jjs使得這個文件可以在命令行中執行:

jjs func.js

得到程序運行結果:

2

類依賴分析器jdeps

jdeps是一個很有用的命令行工具。它可以顯示Java類的包級別或類級別的依賴。它接受一個.class文件,一個目錄,或者一個jar文件作為輸入。jdeps默認把結果輸出到系統輸出(控制台)上。

下面我們查看現階段較流行的Spring框架類庫的依賴報告,為了簡化這個例子,我們只分析一個jar文件:org.springframework.core-3.0.5.RELEASE.jar

org.springframework.core-3.0.5.RELEASE.jar -> C:\Program Files\Java\jdk1.8.0\jre\lib\rt.jar

org.springframework.core (org.springframework.core-3.0.5.RELEASE.jar)

-> java.io

-> java.lang

-> java.lang.annotation

-> java.lang.ref

-> java.lang.reflect

-> java.util

-> java.util.concurrent

-> org.apache.commons.logging not found

-> org.springframework.asm not found

-> org.springframework.asm.commons not found

org.springframework.core.annotation (org.springframework.core-3.0.5.RELEASE.jar)

-> java.lang

-> java.lang.annotation

-> java.lang.reflect

-> java.util

Java虛擬機(JVM)的新特性

PermGen空間被移除了,取而代之的是Metaspace(JEP 122)。JVM選項-XX:PermSize與-XX:MaxPermSize分別被-XX:MetaSpaceSize與-XX:MaxMetaspaceSize所代替。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM