[Java8]Streams

定義

A sequence of elements supporting sequential and parallel aggregate operations.


這個定義包含下面兩層意思

(1)Stream是元素的集合咒林;
(2)可以支持順序和并行的對原Stream進行匯聚的操作;

初體驗

以集合為例倾鲫,看Steam API如何極大的簡化了集合操作(當然召衔,Streams不止可以作用在集合上)

/**
 * Created by haicheng.lhc on 17/04/2017.
 *
 * @author haicheng.lhc
 * @date 2017/04/17
 */
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有一個狀態(tài):OPEN或是CLOSED慨灭,及該狀態(tài)對應的數(shù)目纳猫。如果我們有如下一個數(shù)組户盯,現(xiàn)在需要統(tǒng)計里面OPEN狀態(tài)的數(shù)目屯伞。

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

按照傳統(tǒng)做法需要遍歷數(shù)組,然后計算出OPEN狀態(tài)的數(shù)目和挣磨。
但是在JAVA8里面雇逞,使用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 );

Stream使用說明

  • 官方文檔
  • Stream操作分為中間操作(intermediate operations )晚期操作(terminal operations)
  • 中間操作(intermediate operations )(例如Filter)會返回一個新的stream,它會根據(jù)條件從源stream里面過濾出符合的項放到新的stream里茁裙,不會影響源stream喝峦。這個過濾動作是延遲發(fā)生的,直到晚期操作(terminal operations)才會真正執(zhí)行呜达。

Intermediate operations return a new stream. They are always lazy; executing an intermediate operation such as filter() does not actually perform any filtering, but instead creates a new stream that, when traversed, contains the elements of the initial stream that match the given predicate. Traversal of the pipeline source does not begin until the terminal operation of the pipeline is executed.

  • 中間操作(intermediate operations )分為有狀態(tài)操作(stateful operations )無狀態(tài)兩種(stateless operations)

Intermediate operations are further divided into stateless and stateful operations. Stateless operations, such as filter and map, retain no state from previously seen element when processing a new element -- each element can be processed independently of operations on other elements. Stateful operations, such as distinct and sorted, may incorporate state from previously seen elements when processing new elements.

-晚期操作(terminal operations)(如forEach 或sum)會遍歷stream并得出結(jié)果。在執(zhí)行晚期操作后粟耻,stream已經(jīng)被處理完了查近,不能再次被使用了。

Terminal operations, such as Stream.forEach or IntStream.sum, may traverse the stream to produce a result or a side-effect. After the terminal operation is performed, the stream pipeline is considered consumed, and can no longer be used; if you need to traverse the same data source again, you must return to the data source to get a new stream. In almost all cases, terminal operations are eager, completing their traversal of the data source and processing of the pipeline before returning. Only the terminal operations iterator() and spliterator() are not; these are provided as an "escape hatch" to enable arbitrary client-controlled pipeline traversals in the event that the existing operations are not sufficient to the task.

  • 延遲處理stream是出于性能考慮

Processing streams lazily allows for significant efficiencies; in a pipeline such as the filter-map-sum example above, filtering, mapping, and summing can be fused into a single pass on the data, with minimal intermediate state. Laziness also allows avoiding examining all the data when it is not necessary; for operations such as "find the first string longer than 1000 characters", it is only necessary to examine just enough strings to find one that has the desired characteristics without examining all of the strings available from the source. (This behavior becomes even more important when the input stream is infinite and not merely large.)

Stream語法

List<Integer> nums = Lists.newArrayList(1,null,3,4,null,6);
nums.stream().filter(num -> num != null).count();

這段代碼是獲取一個List中挤忙,元素不為null的個數(shù),可以看出語法為

紅色框中的語句是一個Stream的生命開始的地方霜威,負責創(chuàng)建一個Stream實例;
綠色框中的語句是賦予Stream靈魂的地方册烈,把一個Stream轉(zhuǎn)換成另外一個Stream戈泼,紅框的語句生成的是一個包含所有nums變量的Stream,進過綠框的filter方法以后赏僧,重新生成了一個過濾掉原nums列表所有null以后的Stream大猛;
藍色框中的語句是豐收的地方,把Stream的里面包含的內(nèi)容按照某種算法來匯聚成一個值淀零,例子中是獲取Stream中包含的元素個數(shù)

如何創(chuàng)建Stream

1挽绩、通過 Collection的stream() 或是parallelStream() 方法

public interface Collection<E> extends Iterable<E> {
//其他方法省略
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
}

2、通過Arrays.stream(Object[]) 方法

3驾中、使用Stream靜態(tài)方法來創(chuàng)建Stream

Stream<Integer> integerStream = Stream.of(1, 2, 3, 5);
Stream<String> stringStream = Stream.of("taobao");

轉(zhuǎn)換Stream[中間操作(intermediate operations )]

轉(zhuǎn)換Stream就是通過某種方法將原來的Stream轉(zhuǎn)換成另外一種Stream唉堪,但是源Stream不變模聋。常用的方法有:

1、map:

對于Stream中包含的元素使用給定的轉(zhuǎn)換函數(shù)進行轉(zhuǎn)換操作唠亚,新生成的Stream只包含轉(zhuǎn)換生成的元素链方。這個方法有三個對于原始類型的變種方法,分別是:mapToInt灶搜,mapToLong和mapToDouble祟蚀。這三個方法也比較好理解,比如mapToInt就是把原始Stream轉(zhuǎn)換成一個新的Stream占调,這個新生成的Stream中的元素都是int類型暂题。之所以會有這樣三個變種方法,可以免除自動裝箱/拆箱的額外消耗

2究珊、filter:

對于Stream中包含的元素使用給定的過濾函數(shù)進行過濾操作薪者,新生成的Stream只包含符合條件的元素

3、 distinct:

對于Stream中包含的元素進行去重操作(去重邏輯依賴元素的equals方法)剿涮,新生成的Stream中沒有重復的元素

4言津、 limit:

對一個Stream進行截斷操作,獲取其前N個元素取试,如果原Stream中包含的元素個數(shù)小于N悬槽,那就獲取其所有的元素;

5瞬浓、skip:

返回一個丟棄原Stream的前N個元素后剩下元素組成的新Stream初婆,如果原Stream中包含的元素個數(shù)小于N,那么返回空Stream猿棉;

6磅叛、peek:

生成一個包含原Stream的所有元素的新Stream,同時會提供一個消費函數(shù)(Consumer實例)萨赁,新Stream每個元素被消費的時候都會執(zhí)行給定的消費函數(shù)弊琴;

This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline:

IntStream.of(1, 2, 3, 4)
            .filter(e -> e > 2)
            .peek(e -> System.out.println("Filtered value: " + e))
            .map(e -> e * e)
            .peek(e -> System.out.println("Mapped value: " + e))
            .sum();

這個例子的輸出為

7、對一個stream執(zhí)行上面操作的組合

        List<Integer> nums = Arrays.asList(1, 1, null, 2, 3, 4, null, 5, 6, 7, 8, 9, 10);
        System.out.println("sum is:" + nums.stream()
            .filter(num -> num != null)
            .distinct()
            .mapToInt(num -> num * 2)
            .peek(System.out::println)
            .skip(2)
            .limit(4)
            .sum());

輸出結(jié)果為

匯聚(Reduce)Stream[晚期操作(terminal operations)]

官方定義

A reduction operation (also called a fold) takes a sequence of input elements and combines them into a single summary result by repeated application of a combining operation, such as finding the sum or maximum of a set of numbers, or accumulating elements into a list. The streams classes have multiple forms of general reduction operations, called reduce()
and collect()
, as well as multiple specialized reduction forms such as sum()
, max()
, or count()
.

collect

  • 定義
 <R, A> R collect(Collector<? super T, A, R> collector);
  • 使用例子
 List<Integer> nums = Arrays.asList(1, 1, null, 2, 3, 4, null, 5, 6, 7, 8, 9, 10);
        List<Integer> numsWithoutNull = nums.stream().filter(num -> num != null).
            collect(Collectors.toList());

reduce

max和min:

使用給定的比較器(Operator)杖爽,返回Stream中的最大|最小值

參考文檔

http://ifeve.com/stream/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末敲董,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子慰安,更是在濱河造成了極大的恐慌腋寨,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泻帮,死亡現(xiàn)場離奇詭異精置,居然都是意外死亡,警方通過查閱死者的電腦和手機锣杂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進店門脂倦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來番宁,“玉大人,你說我怎么就攤上這事赖阻〉海” “怎么了?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵火欧,是天一觀的道長棋电。 經(jīng)常有香客問我,道長苇侵,這世上最難降的妖魔是什么赶盔? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮榆浓,結(jié)果婚禮上于未,老公的妹妹穿的比我還像新娘。我一直安慰自己陡鹃,他們只是感情好烘浦,可當我...
    茶點故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著萍鲸,像睡著了一般闷叉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上脊阴,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天握侧,我揣著相機與錄音,去河邊找鬼嘿期。 笑死藕咏,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的秽五。 我是一名探鬼主播,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼饥悴,長吁一口氣:“原來是場噩夢啊……” “哼坦喘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起西设,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤瓣铣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后贷揽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體棠笑,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年禽绪,在試婚紗的時候發(fā)現(xiàn)自己被綠了蓖救。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洪规。...
    茶點故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖循捺,靈堂內(nèi)的尸體忽然破棺而出斩例,到底是詐尸還是另有隱情,我是刑警寧澤从橘,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布念赶,位于F島的核電站,受9級特大地震影響恰力,放射性物質(zhì)發(fā)生泄漏叉谜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一踩萎、第九天 我趴在偏房一處隱蔽的房頂上張望停局。 院中可真熱鬧,春花似錦驻民、人聲如沸翻具。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽裆泳。三九已至,卻和暖如春柠硕,著一層夾襖步出監(jiān)牢的瞬間工禾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工蝗柔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留闻葵,地道東北人。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓癣丧,卻偏偏與公主長得像槽畔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子胁编,可洞房花燭夜當晚...
    茶點故事閱讀 43,576評論 2 349

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