【轉(zhuǎn)】Java 8 新增的 Stream 類學習


聲明:本篇轉(zhuǎn)自《【譯】Java 8的新特性—終極版》中的 Streams 相關(guān)部分。這里只是為了方便查閱學習耸三。其他詳細信息乱陡,可參見原文或官方文檔


Stream

新增的Stream API(java.util.stream)將生成環(huán)境的函數(shù)式編程引入了Java庫中仪壮。這是目前為止最大的一次對Java庫的完善憨颠,以便開發(fā)者能夠?qū)懗龈佑行А⒏雍啙嵑途o湊的代碼积锅。
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類有一個分數(shù)(或偽復(fù)雜度)的概念,另外還有兩種狀態(tài):OPEN或者CLOSED》Ψ校現(xiàn)在假設(shè)有一個task集合:

final Collection< Task > tasks = Arrays.asList(
 new Task( Status.OPEN, 5 ),
 new Task( Status.OPEN, 13 ),
 new Task( Status.CLOSED, 8 )
 );

首先看一個問題:在這個task集合中一共有多少個OPEN狀態(tài)的點淫茵?在Java 8之前爪瓜,要解決這個問題蹬跃,則需要使用foreach循環(huán)遍歷task集合;但是在Java 8中可以利用steams解決:包括一系列元素的列表,并且支持順序和并行處理蝶缀。

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

這里有很多知識點值得說丹喻。首先,tasks集合被轉(zhuǎn)換成stream表示翁都;其次碍论,在stream上的filter操作會過濾掉所有CLOSED的task;第三柄慰,mapToInt操作基于每個task實例的Task::getPoints方法將task流轉(zhuǎn)換成Integer集合鳍悠;最后,通過sum方法計算總和坐搔,得出最后的結(jié)果藏研。

在學習下一個例子之前,還需要記住一些streams(點此更多細節(jié))的知識點概行。Stream之上的操作可分為中間操作和晚期操作蠢挡。

中間操作會返回一個新的steam——執(zhí)行一個中間操作(例如filter)并不會執(zhí)行實際的過濾操作,而是創(chuàng)建一個新的stream凳忙,并將原stream中符合條件的元素放入新創(chuàng)建的stream业踏。

晚期操作(例如forEach或者sum),會遍歷stream并得出結(jié)果或者附帶結(jié)果涧卵;在執(zhí)行晚期操作之后勤家,stream處理線已經(jīng)處理完畢,就不能使用了柳恐。在幾乎所有情況下却紧,晚期操作都是立刻對steam進行遍歷。

stream的另一個價值是創(chuàng)造性地支持并行處理(parallel processing)胎撤。對于上述的tasks集合晓殊,我們可以用下面的代碼計算所有任務(wù)的點數(shù)之和:

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

這里我們使用parallel方法并行處理所有的task,并使用reduce方法計算最終的結(jié)果伤提∥装常控制臺輸出如下:

Total points(all tasks): 26.0

對于一個集合,經(jīng)常需要根據(jù)某些條件對其中的元素分組肿男。利用steam提供的API可以很快完成這類任務(wù)介汹,代碼如下:

// 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]]}

最后一個關(guān)于tasks集合的例子問題是:如何計算集合中每個任務(wù)的點數(shù)在集合中所占的比重,具體處理的代碼如下:

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

控制臺輸出結(jié)果如下:

[19%, 50%, 30%]

最后舶沛,正如之前所說嘹承,Steam API不僅可以作用于Java集合,傳統(tǒng)的IO操作(從文件或者網(wǎng)絡(luò)一行一行得讀取數(shù)據(jù))可以受益于steam處理如庭,這里有一個小例子:

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()方法被調(diào)用的時候這個句柄會被執(zhí)行。Stream API、Lambda表達式還有接口默認方法和靜態(tài)方法支持的方法引用骤竹,是Java 8對軟件開發(fā)的現(xiàn)代范式的響應(yīng)帝牡。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蒙揣,隨后出現(xiàn)的幾起案子靶溜,更是在濱河造成了極大的恐慌,老刑警劉巖懒震,帶你破解...
    沈念sama閱讀 212,294評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件罩息,死亡現(xiàn)場離奇詭異,居然都是意外死亡个扰,警方通過查閱死者的電腦和手機扣汪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锨匆,“玉大人崭别,你說我怎么就攤上這事】致啵” “怎么了茅主?”我有些...
    開封第一講書人閱讀 157,790評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長土榴。 經(jīng)常有香客問我诀姚,道長,這世上最難降的妖魔是什么玷禽? 我笑而不...
    開封第一講書人閱讀 56,595評論 1 284
  • 正文 為了忘掉前任赫段,我火速辦了婚禮,結(jié)果婚禮上矢赁,老公的妹妹穿的比我還像新娘糯笙。我一直安慰自己,他們只是感情好撩银,可當我...
    茶點故事閱讀 65,718評論 6 386
  • 文/花漫 我一把揭開白布给涕。 她就那樣靜靜地躺著,像睡著了一般额获。 火紅的嫁衣襯著肌膚如雪够庙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,906評論 1 290
  • 那天抄邀,我揣著相機與錄音耘眨,去河邊找鬼。 笑死境肾,一個胖子當著我的面吹牛剔难,可吹牛的內(nèi)容都是我干的胆屿。 我是一名探鬼主播,決...
    沈念sama閱讀 39,053評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼钥飞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了衫嵌?” 一聲冷哼從身側(cè)響起读宙,我...
    開封第一講書人閱讀 37,797評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎楔绞,沒想到半個月后结闸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,250評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡酒朵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,570評論 2 327
  • 正文 我和宋清朗相戀三年桦锄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔫耽。...
    茶點故事閱讀 38,711評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡结耀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出匙铡,到底是詐尸還是另有隱情图甜,我是刑警寧澤,帶...
    沈念sama閱讀 34,388評論 4 332
  • 正文 年R本政府宣布鳖眼,位于F島的核電站黑毅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏钦讳。R本人自食惡果不足惜矿瘦,卻給世界環(huán)境...
    茶點故事閱讀 40,018評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望愿卒。 院中可真熱鬧缚去,春花似錦、人聲如沸琼开。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,796評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稠通。三九已至衬衬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間改橘,已是汗流浹背滋尉。 一陣腳步聲響...
    開封第一講書人閱讀 32,023評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留飞主,地道東北人狮惜。 一個月前我還...
    沈念sama閱讀 46,461評論 2 360
  • 正文 我出身青樓高诺,卻偏偏與公主長得像,于是被迫代替她去往敵國和親碾篡。 傳聞我的和親對象是個殘疾皇子虱而,可洞房花燭夜當晚...
    茶點故事閱讀 43,595評論 2 350

推薦閱讀更多精彩內(nèi)容