鏈接轉載地址:http://www.2cto.com/kf/201609/544044.htmlphp
Eclipse:html
http://aiyiupload.oss-cn-beijing.aliyuncs.com/blog/file/default/eclipse-jee-neon-R-win32-x86_64.zipjava
JDK8:程序員
http://aiyiupload.oss-cn-beijing.aliyuncs.com/blog/file/default/jdk-8u91-windows-x64.exespring
特性一,接口的默認方法apache
在JDK8中,容許給接口自己添加一個默認的實現。用「default」進行修飾。下面我建立一個MyCompute接口,並給他的sum方法一個默認的實現。編程
package com.aiyi.jdk.testinterface;canvas
/**windows
* 個人Compute類api
* @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的排序工具類。
一、new一個抽象的比較器
package com.aiyi.jdk.testilambda;
public interface MyComparator {
int sort(String str1, String str2);
}
二、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);
}
}
}
}
}
三、使用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接口等等,這裏就不一一訴說了,喜歡鑽研的朋友們能夠拔源碼或者閱讀相關文檔慢慢看。
特性4、反射的增強
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(目前最新的版本)版本一樣具備這樣的配置項,如下是開啓該項的配置圖:
設置步驟: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所代替。