Java 8 Stream使用

一. Stream的特性

Stream是Java 8新增的接口,Stream可以認為是一個高級版本的 Iterator走诞。它代表著數(shù)據(jù)流僻孝,流中的數(shù)據(jù)元素的數(shù)量可以是有限的,也可以是無限的堡称。

Stream跟Iterator的差別是
無存儲:Stream是基于數(shù)據(jù)源的對象,它本身不存儲數(shù)據(jù)元素艺演,而是通過管道將數(shù)據(jù)源的元素傳遞給操作却紧。
函數(shù)式編程:對Stream的任何修改都不會修改背后的數(shù)據(jù)源,比如對Stream執(zhí)行filter操作并不會刪除被過濾的元素胎撤,而是會產(chǎn)生一個不包含被過濾元素的新的Stream晓殊。
延遲執(zhí)行:Stream的操作由零個或多個中間操作(intermediate operation)和一個結(jié)束操作(terminal operation)兩部分組成。只有執(zhí)行了結(jié)束操作伤提,Stream定義的中間操作才會依次執(zhí)行巫俺,這就是Stream的延遲特性。
可消費性:Stream只能被“消費”一次肿男,一旦遍歷過就會失效介汹。就像容器的迭代器那樣,想要再次遍歷必須重新生成一個新的Stream舶沛。

二. Java 8新增的函數(shù)式接口

Stream的操作是建立在函數(shù)式接口的組合之上的嘹承。Java8中新增的函數(shù)式接口都在java.util.function包下。這些函數(shù)式接口可以有多種分類方式如庭。

Java

Java

2.1 Function

Function是從T到R的一元映射函數(shù)叹卷。將參數(shù)T傳遞給一個函數(shù),返回R坪它。即R = Function(T)
@FunctionalInterface
public interface Function<T, R> {

/**
 * Applies this function to the given argument.
 *
 * @param t the function argument
 * @return the function result
 */
R apply(T t);

/**
 * Returns a composed function that first applies the {@code before}
 * function to its input, and then applies this function to the result.
 * If evaluation of either function throws an exception, it is relayed to
 * the caller of the composed function.
 *
 * @param <V> the type of input to the {@code before} function, and to the
 *           composed function
 * @param before the function to apply before this function is applied
 * @return a composed function that first applies the {@code before}
 * function and then applies this function
 * @throws NullPointerException if before is null
 *
 * @see #andThen(Function)
 */
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
    Objects.requireNonNull(before);
    return (V v) -> apply(before.apply(v));
}

/**
 * Returns a composed function that first applies this function to
 * its input, and then applies the {@code after} function to the result.
 * If evaluation of either function throws an exception, it is relayed to
 * the caller of the composed function.
 *
 * @param <V> the type of output of the {@code after} function, and of the
 *           composed function
 * @param after the function to apply after this function is applied
 * @return a composed function that first applies this function and then
 * applies the {@code after} function
 * @throws NullPointerException if after is null
 *
 * @see #compose(Function)
 */
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
    Objects.requireNonNull(after);
    return (T t) -> after.apply(apply(t));
}

/**
 * Returns a function that always returns its input argument.
 *
 * @param <T> the type of the input and output objects to the function
 * @return a function that always returns its input argument
 */
static <T> Function<T, T> identity() {
    return t -> t;
}

}

Function默認實現(xiàn)了3個default方法骤竹,分別是compose、andThen和identity往毡。

方法名

對應(yīng)函數(shù)

描述

compose V=Function(ParamFunction(T)) 它體現(xiàn)了嵌套關(guān)系
andThen V= ParamFunction(Function(T)) 轉(zhuǎn)換了嵌套的順序
identity Function(T)=T 傳遞自身的函數(shù)調(diào)用

compose和andThen對于兩個函數(shù)f和g來說蒙揣,f.compose(g)等價于g.andThen(f)。

2.2 Predicate

Predicate是一個謂詞函數(shù)卖擅,主要作為一個謂詞演算推導(dǎo)真假值存在鸣奔,返回布爾值的函數(shù)墨技。Predicate等價于一個Function的boolean型返回值的子集。
@FunctionalInterface
public interface Predicate<T> {

/**
 * Evaluates this predicate on the given argument.
 *
 * @param t the input argument
 * @return {@code true} if the input argument matches the predicate,
 * otherwise {@code false}
 */
boolean test(T t);

/**
 * Returns a composed predicate that represents a short-circuiting logical
 * AND of this predicate and another.  When evaluating the composed
 * predicate, if this predicate is {@code false}, then the {@code other}
 * predicate is not evaluated.
 *
 * <p>Any exceptions thrown during evaluation of either predicate are relayed
 * to the caller; if evaluation of this predicate throws an exception, the
 * {@code other} predicate will not be evaluated.
 *
 * @param other a predicate that will be logically-ANDed with this
 *              predicate
 * @return a composed predicate that represents the short-circuiting logical
 * AND of this predicate and the {@code other} predicate
 * @throws NullPointerException if other is null
 */
default Predicate<T> and(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) && other.test(t);
}

/**
 * Returns a predicate that represents the logical negation of this
 * predicate.
 *
 * @return a predicate that represents the logical negation of this
 * predicate
 */
default Predicate<T> negate() {
    return (t) -> !test(t);
}

/**
 * Returns a composed predicate that represents a short-circuiting logical
 * OR of this predicate and another.  When evaluating the composed
 * predicate, if this predicate is {@code true}, then the {@code other}
 * predicate is not evaluated.
 *
 * <p>Any exceptions thrown during evaluation of either predicate are relayed
 * to the caller; if evaluation of this predicate throws an exception, the
 * {@code other} predicate will not be evaluated.
 *
 * @param other a predicate that will be logically-ORed with this
 *              predicate
 * @return a composed predicate that represents the short-circuiting logical
 * OR of this predicate and the {@code other} predicate
 * @throws NullPointerException if other is null
 */
default Predicate<T> or(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) || other.test(t);
}

/**
 * Returns a predicate that tests if two arguments are equal according
 * to {@link Objects#equals(Object, Object)}.
 *
 * @param <T> the type of arguments to the predicate
 * @param targetRef the object reference with which to compare for equality,
 *               which may be {@code null}
 * @return a predicate that tests if two arguments are equal according
 * to {@link Objects#equals(Object, Object)}
 */
static <T> Predicate<T> isEqual(Object targetRef) {
    return (null == targetRef)
            ? Objects::isNull
            : object -> targetRef.equals(object);
}

}

Predicate的默認方法是and挎狸、negate扣汪、or。

2.3 Consumer

Consumer是從T到void的一元函數(shù)锨匆,接受一個入?yún)⒌环祷厝魏谓Y(jié)果的操作崭别。
@FunctionalInterface
public interface Consumer<T> {

/**
 * Performs this operation on the given argument.
 *
 * @param t the input argument
 */
void accept(T t);

/**
 * Returns a composed {@code Consumer} that performs, in sequence, this
 * operation followed by the {@code after} operation. If performing either
 * operation throws an exception, it is relayed to the caller of the
 * composed operation.  If performing this operation throws an exception,
 * the {@code after} operation will not be performed.
 *
 * @param after the operation to perform after this operation
 * @return a composed {@code Consumer} that performs in sequence this
 * operation followed by the {@code after} operation
 * @throws NullPointerException if {@code after} is null
 */
default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
}

}

Consumer的默認方法是andThen。

2.4 Supplier

Supplier是表示結(jié)果的供應(yīng)者恐锣。
@FunctionalInterface
public interface Supplier<T> {

/**
 * Gets a result.
 *
 * @return a result
 */
T get();

}

Supplier的用法:
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return "hello suppiler";
}
};
System.out.println(supplier.get());

或者:
Supplier<User> userSupplier = User::new;
userSupplier.get(); // new User

Java 8新增了CompletableFuture茅主,它的很多方法的入?yún)⒍加玫搅薙upplier。

三. Stream用法

Stream操作.png

3.1 Stream的創(chuàng)建

Java 8有多種方式來創(chuàng)建Stream:
通過集合的stream()方法或者parallelStream()
使用流的靜態(tài)方法土榴,比如Stream.of(Object[]), IntStream.range(int, int) 或者 Stream.iterate(Object, UnaryOperator)诀姚。
通過Arrays.stream(Object[])方法。
BufferedReader.lines()從文件中獲得行的流玷禽。
Files類的操作路徑的方法赫段,如list、find矢赁、walk等糯笙。
隨機數(shù)流Random.ints()。
其它一些類提供了創(chuàng)建流的方法撩银,如BitSet.stream(), Pattern.splitAsStream(java.lang.CharSequence), 和 JarFile.stream()给涕。

其實最終都是依賴底層的StreamSupport類來完成Stream創(chuàng)建。

3.2 中間操作

中間操作又可以分為無狀態(tài)的(Stateless)和有狀態(tài)的(Stateful)额获,無狀態(tài)中間操作是指元素的處理不受前面元素的影響够庙,而有狀態(tài)的中間操作必須等到所有元素處理之后才知道最終結(jié)果。

Stream的中間操作只是一種標記咪啡,只有執(zhí)行了結(jié)束操作才會觸發(fā)實際計算首启。
熟悉RxJava暮屡、Scala的同學可以看到撤摸,Stream中間操作的各個方法在RxJava、Scala中都可以找到熟悉的身影褒纲。

3.3 結(jié)束操作

3.3.1 短路操作

短路操作是指不用處理全部元素就可以返回結(jié)果准夷。短路操作必須一個元素處理一次。

3.3.1 非短路操作

非短路操作可以批量處理數(shù)據(jù)莺掠,但是需要處理完全部元素才會返回結(jié)果衫嵌。

四. 并行流

在創(chuàng)建Stream時,默認是創(chuàng)建串行流彻秆。但是可以使用parallelStream()來創(chuàng)建并行流或者parallel()將串行流轉(zhuǎn)換成并行流楔绞。并行流也可以通過sequential()轉(zhuǎn)換成串行流结闸。

Java 8 Stream的并行流,本質(zhì)上還是使用Fork/Join模型酒朵。

五. 總結(jié)

在Java開發(fā)中桦锄,如果使用了Java 8,那么強烈建議使用Stream蔫耽。因為Stream的每個操作都可以依賴Lambda表達式结耀,它是一種聲明式的數(shù)據(jù)處理方式,并且Stream提高了數(shù)據(jù)處理效率和開發(fā)效率匙铡。

作者:fengzhizi715
鏈接:https://www.imooc.com/article/23473?block_id=tuijian_wz
來源:慕課網(wǎng)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末图甜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鳖眼,更是在濱河造成了極大的恐慌黑毅,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钦讳,死亡現(xiàn)場離奇詭異博肋,居然都是意外死亡,警方通過查閱死者的電腦和手機蜂厅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門匪凡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人掘猿,你說我怎么就攤上這事病游。” “怎么了稠通?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵衬衬,是天一觀的道長。 經(jīng)常有香客問我改橘,道長滋尉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任飞主,我火速辦了婚禮狮惜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碌识。我一直安慰自己碾篡,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布筏餐。 她就那樣靜靜地躺著开泽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪魁瞪。 梳的紋絲不亂的頭發(fā)上穆律,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天惠呼,我揣著相機與錄音,去河邊找鬼峦耘。 笑死罢杉,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的贡歧。 我是一名探鬼主播滩租,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼利朵!你這毒婦竟也來了律想?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤绍弟,失蹤者是張志新(化名)和其女友劉穎技即,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體樟遣,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡而叼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了豹悬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片葵陵。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖瞻佛,靈堂內(nèi)的尸體忽然破棺而出脱篙,到底是詐尸還是另有隱情,我是刑警寧澤伤柄,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布绊困,位于F島的核電站,受9級特大地震影響适刀,放射性物質(zhì)發(fā)生泄漏秤朗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一笔喉、第九天 我趴在偏房一處隱蔽的房頂上張望取视。 院中可真熱鬧,春花似錦然遏、人聲如沸贫途。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至姨裸,卻和暖如春秧倾,著一層夾襖步出監(jiān)牢的瞬間怨酝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工那先, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留农猬,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓售淡,卻偏偏與公主長得像斤葱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子揖闸,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

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

  • 第一章 為什么要關(guān)心Java 8 使用Stream庫來選擇最佳低級執(zhí)行機制可以避免使用Synchronized(同...
    謝隨安閱讀 1,494評論 0 4
  • JDK8中首次引入Stream的操作(不是IO的stream)揍堕,可以讓你聲明式的方式處理數(shù)據(jù)。 Stream 使用...
    Real_man閱讀 350評論 0 3
  • Java函數(shù)式設(shè)計 實現(xiàn)方法: @FunctionalInterface接口 Lambda語法 方法引用 接口de...
    我可能是個假開發(fā)閱讀 26,367評論 2 55
  • Java8 in action 沒有共享的可變數(shù)據(jù)汤纸,將方法和函數(shù)即代碼傳遞給其他方法的能力就是我們平常所說的函數(shù)式...
    鐵牛很鐵閱讀 1,235評論 1 2
  • 轉(zhuǎn)自: Java 8 中的 Streams API 詳解 為什么需要 Stream Stream 作為 Java ...
    普度眾生的面癱青年閱讀 2,920評論 0 11