Java8:Stream詳解

1. Stream概述?

JDK文檔:

A sequence of elements supporting sequential and parallel aggregate operations.

中文翻譯:

Stream是元素的集合到腥,可以支持順序和并行的對(duì)原Stream進(jìn)行匯聚的操作朵逝;

Stream代表數(shù)據(jù)流,流中的數(shù)據(jù)元素的數(shù)量可能是有限的乡范,也可能是無(wú)限的配名。

Java為什么要引入Stream?這個(gè)問題可以從側(cè)面更好的了解Stream的概念

  • 通過函數(shù)式編程的方式可以將將復(fù)雜的數(shù)據(jù)處理過程變得簡(jiǎn)單明了晋辆,那么這個(gè)和Stream有什么關(guān)系渠脉?本質(zhì)上Streams是Monads。

Monad就是一種設(shè)計(jì)模式瓶佳,表示將一個(gè)運(yùn)算過程芋膘,通過函數(shù)拆解成互相連接的多個(gè)步驟。你只要提供下一步運(yùn)算所需的函數(shù)霸饲,整個(gè)運(yùn)算就會(huì)自動(dòng)進(jìn)行下去为朋。

  • 提供串行和并行兩種模式進(jìn)行匯聚操作,并發(fā)模式能夠充分利用多核處理器的優(yōu)勢(shì)

Stream相關(guān)概念

  • 一系列元素:Stream對(duì)一組有特定類型的元素提供了一個(gè)接口厚脉。但是Stream并不真正存儲(chǔ)元素习寸,元素根據(jù)需求被計(jì)算出結(jié)果。
  • 源:Stream可以處理任何一種數(shù)據(jù)提供源傻工,比如結(jié)合霞溪、數(shù)組孵滞,或者I/O資源。
  • 聚合操作:Stream支持類似SQL一樣的操作鸯匹,常規(guī)的操作都是函數(shù)式編程語(yǔ)言坊饶,比如filter,map忽你,reduce幼东,find间狂,match蜒简,sorted店归,等等县昂。

Stream操作還具備兩個(gè)基本特性使它與集合操作不同:

  • 管道:許多Stream操作會(huì)返回一個(gè)stream對(duì)象本身特漩。這就允許所有操作可以連接起來(lái)形成一個(gè)更大的管道憔杨。這就就可以進(jìn)行特定的優(yōu)化了趁啸,比如懶加載和短回路巨缘,我們將在下面介紹尿赚。
  • 內(nèi)部迭代:和集合的顯式迭代(外部迭代)相比散庶,Stream操作不需要我們手動(dòng)進(jìn)行迭代。

總結(jié)Stream的特點(diǎn)

  • 不存儲(chǔ)數(shù)據(jù)凌净。流是基于數(shù)據(jù)源的對(duì)象悲龟,它本身不存儲(chǔ)數(shù)據(jù)元素,而是通過管道將數(shù)據(jù)源的元素傳遞給操作冰寻。
  • 函數(shù)式編程须教。對(duì)stream的任何修改都不會(huì)修改背后的數(shù)據(jù)源,比如對(duì)stream執(zhí)行過濾操作并不會(huì)刪除被過濾的元素斩芭,而是會(huì)產(chǎn)生一個(gè)不包含被過濾元素的新stream轻腺。
  • 延遲操作。流的很多操作如filter,map等中間操作是延遲執(zhí)行的划乖,只有到終點(diǎn)操作才會(huì)將操作順序執(zhí)行贬养。
  • 可以解綁。對(duì)于無(wú)限數(shù)量的流琴庵,有些操作是可以在有限的時(shí)間完成的误算,比如limit(n) 或 findFirst(),這些操作可是實(shí)現(xiàn)"短路"(Short-circuiting)迷殿,訪問到有限的元素后就可以返回尉桩。
  • 純消費(fèi)。流的元素只能訪問一次贪庙,類似Iterator蜘犁,操作沒有回頭路,如果你想從頭重新訪問流的元素止邮,需要重新生成一個(gè)新的流这橙。

2. Stream的使用

2.1 流的操作類型

對(duì)stream的操作分為為兩類奏窑,中間操作(intermediate operations)和結(jié)束操作(terminal operations)

  • 中間操作總是會(huì)惰式執(zhí)行,調(diào)用中間操作只會(huì)生成一個(gè)標(biāo)記了該操作的新stream屈扎,僅此而已埃唯。
  • 結(jié)束操作會(huì)觸發(fā)實(shí)際計(jì)算,計(jì)算發(fā)生時(shí)會(huì)把所有中間操作積攢的操作以pipeline的方式執(zhí)行鹰晨,這樣可以減少迭代次數(shù)墨叛。計(jì)算完成之后stream就會(huì)失效。

還有一種操作被稱為 short-circuiting模蜡。用以指:
對(duì)于一個(gè) intermediate 操作漠趁,如果它接受的是一個(gè)無(wú)限大(infinite/unbounded)的 Stream,但返回一個(gè)有限的新 Stream忍疾。對(duì)于一個(gè) terminal 操作闯传,如果它接受的是一個(gè)無(wú)限大的 Stream,但能在有限的時(shí)間計(jì)算出結(jié)果卤妒。

2.2 使用Stream的步驟

創(chuàng)建Stream -> 轉(zhuǎn)換Stream每次轉(zhuǎn)換原有Stream對(duì)象不改變甥绿,返回一個(gè)新的Stream對(duì)象(可以有多次轉(zhuǎn)換) ->對(duì)Stream進(jìn)行聚合(Reduce)操作,獲取想要的結(jié)果

2.3 Stream創(chuàng)建
  1. 通過Collection的stream()方法或者parallelStream()则披,比如Arrays.asList(1,2,3).stream()。
  2. 使用流的靜態(tài)方法骄呼,比如Stream.of(Object[]), IntStream.range(int, int) 或者 Stream.iterate(Object, UnaryOperator)澄峰,如Stream.iterate(0, n -> n * 2)堂竟,或者generate(Supplier<T> s)如Stream.generate(Math::random)席楚。
  3. BufferedReader.lines()從文件中獲得行的流垮斯。
  4. Files類的操作路徑的方法抛寝,如list晶府、find爷绘、walk等。
  5. 隨機(jī)數(shù)流Random.ints()
  6. 通過Arrays.stream(Object[])方法, 比如Arrays.stream(new int[]{1,2,3})。
  7. 其它一些類提供了創(chuàng)建流的方法,如BitSet.stream(), Pattern.splitAsStream(java.lang.CharSequence), 和 JarFile.stream()镣衡。

追蹤到底層其實(shí)都是使用StreamSupport類望浩,它提供了將Spliterator轉(zhuǎn)換成流的方法吆视。至于它的內(nèi)部細(xì)節(jié)在下片文章介紹搔弄。

2.4 中間操作

中間操作會(huì)返回一個(gè)新的流,但是操作是延遲執(zhí)行的(lazy),它不會(huì)修改原始的數(shù)據(jù)源顾彰,而且是由在終點(diǎn)操作開始的時(shí)候才真正開始執(zhí)行厕隧。
這個(gè)Scala集合的轉(zhuǎn)換操作不同吁讨,Scala集合轉(zhuǎn)換操作會(huì)生成一個(gè)新的中間集合髓迎,顯而易見Java的這種設(shè)計(jì)會(huì)減少中間對(duì)象的生成。

操作類型 方法
中間操作 concat() distinct() filter() flatMap() limit() map() peek() skip() sorted() parallel() sequential() unordered()

區(qū)分中間操作和結(jié)束操作最簡(jiǎn)單的方法建丧,就是看方法的返回值排龄,返回值為stream的大都是中間操作,否則是結(jié)束操作茶鹃。

distinct()

Stream<T> distinct();

對(duì)于Stream中包含的元素進(jìn)行去重操作(去重邏輯依賴元素的equals方法),新生成的Stream中沒有重復(fù)的元素艰亮;

filter()

Stream<T> filter(Predicate<? super T> predicate);

對(duì)于Stream中包含的元素使用給定的predicate過濾函數(shù)進(jìn)行過濾操作闭翩,新生成的Stream只包含符合條件的元素。

map()

    <R> Stream<R> map(Function<? super T, ? extends R> mapper);

對(duì)于Stream中包含的元素使用給定的轉(zhuǎn)換函數(shù)進(jìn)行轉(zhuǎn)換操作迄埃,對(duì)每個(gè)元素按照某種操作進(jìn)行轉(zhuǎn)換疗韵,轉(zhuǎn)換前后Stream中元素的個(gè)數(shù)不會(huì)改變,但元素的類型取決于轉(zhuǎn)換之后的類型侄非。

這個(gè)方法有三個(gè)對(duì)于原始類型的變種方法蕉汪,分別是:mapToInt流译,mapToLong和mapToDouble。比如mapToInt就是把原始Stream轉(zhuǎn)換成一個(gè)新的Stream者疤,這個(gè)新生成的Stream中的元素都是int類型福澡。之所以會(huì)有這樣三個(gè)變種方法,可以免除自動(dòng)裝箱/拆箱的額外消耗驹马;

flatMap()

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

和map類似革砸,不同的是其每個(gè)元素轉(zhuǎn)換得到的是Stream對(duì)象,會(huì)把子Stream中的元素壓縮到父集合中糯累;

peek()

Stream<T> peek(Consumer<? super T> action);

生成一個(gè)包含原Stream的所有元素的新Stream算利,同時(shí)會(huì)提供一個(gè)消費(fèi)函數(shù)(Consumer實(shí)例),新Stream每個(gè)元素被消費(fèi)的時(shí)候都會(huì)執(zhí)行給定的消費(fèi)函數(shù)

skip()

Stream<T> skip(long n);

返回一個(gè)丟棄原Stream的前N個(gè)元素后剩下元素組成的新Stream泳姐,如果原Stream中包含的元素個(gè)數(shù)小于N效拭,那么返回空Stream;

limit()
對(duì)一個(gè)Stream進(jìn)行截?cái)嗖僮髋置耄@取其前N個(gè)元素缎患。如果原Stream中包含的元素個(gè)數(shù)小于N,那就獲取其所有的元素扒怖,這是一個(gè)short-circuiting 操作较锡。

下面統(tǒng)一實(shí)例代碼:

Arrays.asList(1, 1, null, 2, 3, 4, null, 5, 6, 7, 8, 9, 10)
       .stream()
       .distinct()
       .filter(t -> t != null && t > 9)
       .map(t -> t * 10)
       .flatMap(t -> Stream.of(t, t + 1))
       .skip(1)
       .forEach(System.out::println);
2.5 終結(jié)操作
操作類型 方法
結(jié)束操作 allMatch() anyMatch() collect() count() findAny() findFirst() forEach() forEachOrdered() max() min() noneMatch() reduce() toArray()

Match

public boolean  allMatch(Predicate<? super T> predicate)
public boolean  anyMatch(Predicate<? super T> predicate)
public boolean  noneMatch(Predicate<? super T> predicate)

這一組方法用來(lái)檢查流中的元素是否滿足斷言。

  • allMatch只有在所有的元素都滿足斷言時(shí)才返回true,否則flase,流為空時(shí)總是返回true
  • anyMatch只有在任意一個(gè)元素滿足斷言時(shí)就返回true,否則flase,
  • noneMatch只有在所有的元素都不滿足斷言時(shí)才返回true,否則flase

count

count方法返回流中的元素的數(shù)量盗痒。它實(shí)現(xiàn)為:

forEach/forEachOrdered

forEach遍歷流的每一個(gè)元素蚂蕴,執(zhí)行指定的action。和peek方法不同俯邓。這個(gè)方法不擔(dān)保按照流的encounter order順序執(zhí)行骡楼,如果對(duì)于有序流按照它的encounter order順序執(zhí)行,你可以使用forEachOrdered方法稽鞭。

max/min

max返回流中的最大值鸟整,
min返回流中的最小值。

toArray()

將流中的元素放入到一個(gè)數(shù)組中朦蕴。

總結(jié):
終結(jié)操作也叫匯聚操作篮条,它接受一個(gè)元素序列為輸入,反復(fù)使用某個(gè)合并操作吩抓,把序列中的元素合并成一個(gè)匯總的結(jié)果涉茧。比如查找一個(gè)數(shù)字列表的總和或者最大值,或者把這些數(shù)字累積成一個(gè)List對(duì)象疹娶。Stream接口有一些通用的匯聚操作伴栓,比如reduce()和collect();也有一些特定用途的匯聚操作,比如sum(),max()和count()钳垮。

注意:sum方法不是所有的Stream對(duì)象都有的惑淳,只有IntStream、LongStream和DoubleStream是實(shí)例才有饺窿。

匯聚操作可以分為以下兩類

  • 可變匯聚:把輸入的元素們累積到一個(gè)可變的容器中歧焦,如collect。

  • 其他匯聚:除去可變匯聚剩下的短荐,一般都不是通過反復(fù)修改某個(gè)可變對(duì)象倚舀,而是通過把前一次的匯聚結(jié)果當(dāng)成下一次的入?yún)ⅲ磸?fù)如此忍宋。比如reduce痕貌,count,allMatch糠排。

collect和ruduce比較重要舵稠,單獨(dú)一節(jié)講述。

3. reduce

作用是把 Stream 元素組合起來(lái)入宦。它提供一個(gè)起始值(種子)哺徊,然后依照運(yùn)算規(guī)則(BinaryOperator),和前面 Stream 的第一個(gè)乾闰、第二個(gè)落追、第 n 個(gè)元素組合。從這個(gè)意義上說涯肩,字符串拼接轿钠、數(shù)值的 sum、min病苗、max疗垛、average 都是特殊的 reduce。例如 Stream 的 sum 就相當(dāng)于

Integer sum = integers.reduce(0, (a, b) -> a+b); 
//或者
Integer sum = integers.reduce(0, Integer::sum);

下面看它的定義:

Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)

舉個(gè)例子

Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
        .stream()
        .reduce((a, b) -> a + b)
        .ifPresent(System.out::println);
System.out.println(Stream.of("A", "B", "C", "D")
        .reduce("Str", (a, b) -> a + "-" + b));
Stream.of("I", "love", "you")
        .reduce(0,// 初始值 
                (sum, str) -> sum + str.length(),// 累加操作
                (a, b) -> 0); //并行stream才會(huì)用到

4. collect

可變匯聚對(duì)應(yīng)的只有一個(gè)方法:collect硫朦,正如其名字顯示的贷腕,它可以把Stream中的要有元素收集到一個(gè)結(jié)果容器中(比如Collection)∫д梗看一下它的定義:

 <R> R collect(Supplier<R> supplier,
                 ObjIntConsumer<R> accumulator,
                 BiConsumer<R, R> combiner)

先來(lái)看看這三個(gè)參數(shù)的含義: supplier是一個(gè)工廠函數(shù)泽裳,用來(lái)生成一個(gè)新的容器, accumulator用來(lái)把Stream中的元素添加到結(jié)果容器中破婆,BiConsumer<R, R> combiner參數(shù)用來(lái)把中間狀態(tài)的多個(gè)結(jié)果容器合并成為一個(gè)(并行的時(shí)候會(huì)用到)
還有一個(gè)重載函數(shù),參數(shù)是Collector類型涮总,三個(gè)參數(shù)太麻煩,收集器Collector就是對(duì)這三個(gè)參數(shù)的簡(jiǎn)單封裝荠割。Collectors工具類可通過靜態(tài)方法生成各種常用的Collector妹卿。

<R, A> R collect(Collector<? super T, A, R> collector);

舉個(gè)例子:

List list1 = Stream.of(1,2,3,4,5,6,7,8,9,10)
        .collect(() -> new ArrayList<Integer>(),.//生成一個(gè)新的ArrayList實(shí)例
                //接受兩個(gè)參數(shù),第一個(gè)是前面生成的ArrayList對(duì)象蔑鹦,
                //二個(gè)是stream中包含的元素夺克,函數(shù)體就是把stream中的元素加入ArrayList對(duì)象中。
                //此函數(shù)被反復(fù)調(diào)用直到原stream的元素被消費(fèi)完畢嚎朽;
                (list, item) -> list.add(item),
               //接受兩個(gè)參數(shù)铺纽,這兩個(gè)都是ArrayList類型的,函數(shù)體就是把第二個(gè)ArrayList全部加入到第一個(gè)中哟忍;
                (lista, listb) -> lista.addAll(listb));
List list2 = Stream.of(1,2,3,4,5,6,7,8,9,10)
        .collect(ArrayList::new,
                ArrayList::add,
                ArrayList::addAll);
List list3 =  Stream.of(1,2,3,4,5,6,7,8,9,10)
        .collect(Collectors.toList());
System.out.println(list3);

5. 總結(jié)

Stream的常用API基本介紹完畢狡门,應(yīng)該有了一個(gè)初步的認(rèn)識(shí)」埽總結(jié)一下Stream 的特性:

  • 不是數(shù)據(jù)結(jié)構(gòu)其馏,它沒有內(nèi)部存儲(chǔ),它只是用操作管道從 source(數(shù)據(jù)結(jié)構(gòu)爆安、數(shù)組叛复、generator function、IO channel)抓取數(shù)據(jù)扔仓。它也絕不修改自己所封裝的底層數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)褐奥。例如 Stream 的 filter 操作會(huì)產(chǎn)生一個(gè)不包含被過濾元素的新 Stream,而不是從 source 刪除那些元素翘簇。所以也不支持索引訪問撬码。

  • 所有 Stream 的操作必須以 lambda 表達(dá)式為參數(shù)

  • 惰性化,很多 Stream 操作是向后延遲的版保,一直到它弄清楚了最后需要多少數(shù)據(jù)才會(huì)開始呜笑。
    Intermediate 操作永遠(yuǎn)是惰性化的。

  • 并行能力找筝,當(dāng)一個(gè) Stream 是并行化的蹈垢,就不需要再寫多線程代碼,所有對(duì)它的操作會(huì)自動(dòng)并行進(jìn)行的袖裕。

  • 可以是無(wú)限的曹抬,集合有固定大小,Stream 則不必急鳄。limit(n) 和 findFirst() 這類的 short-circuiting 操作可以對(duì)無(wú)限的 Stream 進(jìn)行運(yùn)算并很快完成谤民。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市疾宏,隨后出現(xiàn)的幾起案子张足,更是在濱河造成了極大的恐慌,老刑警劉巖坎藐,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件为牍,死亡現(xiàn)場(chǎng)離奇詭異哼绑,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)碉咆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門抖韩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人疫铜,你說我怎么就攤上這事茂浮。” “怎么了壳咕?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵席揽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我谓厘,道長(zhǎng)幌羞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任竟稳,我火速辦了婚禮新翎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘住练。我一直安慰自己地啰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布讲逛。 她就那樣靜靜地躺著亏吝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盏混。 梳的紋絲不亂的頭發(fā)上蔚鸥,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音许赃,去河邊找鬼止喷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛混聊,可吹牛的內(nèi)容都是我干的弹谁。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼句喜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼预愤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起咳胃,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤植康,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后展懈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體销睁,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡供璧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冻记。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嗜傅。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖檩赢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情违寞,我是刑警寧澤贞瞒,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站趁曼,受9級(jí)特大地震影響军浆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜挡闰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一乒融、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧摄悯,春花似錦赞季、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至瘪阁,卻和暖如春撒遣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背管跺。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工义黎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人豁跑。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓廉涕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親艇拍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子火的,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)淑倾,斷路器馏鹤,智...
    卡卡羅2017閱讀 134,638評(píng)論 18 139
  • 這篇關(guān)于java stream的文章寫的特別好,轉(zhuǎn)載一下娇哆,以備自己查看湃累。轉(zhuǎn)載自Java 8 中的 Streams ...
    小白小白啦閱讀 510評(píng)論 0 2
  • 1. Stream初體驗(yàn) 我們先來(lái)看看Java里面是怎么定義Stream的: A sequence of elem...
    kechao8485閱讀 1,236評(píng)論 0 9
  • =========================================================...
    高速路邊數(shù)車車閱讀 1,650評(píng)論 0 1
  • 冰山古竹字生光勃救, 小魚問佛意昂揚(yáng)。 憂羅獨(dú)憐美人老治力, 寒舟一桿釣大江蒙秒。 下面是我手繪…請(qǐng)嚴(yán)肅點(diǎn)
    閻浮小學(xué)僧閱讀 281評(píng)論 15 7