JAVA8函數(shù)式編程系列2--流(Stream)

????Jav8中,在核心類(lèi)庫(kù)中引入了新的概念,流(Stream)。流使得程序媛們得以站在更高的抽象層次上對(duì)集合進(jìn)行操作。
????今天,居士將主要介紹Steam類(lèi)中對(duì)應(yīng)集合上操作的幾個(gè)重要的方法。

1、 Steam舉例

????對(duì)使用Java的程序媛們,當(dāng)需要處理集合里的每一個(gè)數(shù)據(jù)時(shí),通常是使用迭代,再對(duì)每個(gè)返回的元素進(jìn)行處理。比如:

int count = 0;
  ArrayList<String> nameList = new ArrayList<>();
        nameList.add("仁昌居士");
        nameList.add("仁昌居士");
        nameList.add("痕無(wú)羽");
        nameList.add("羽無(wú)痕");
        for (String name: nameList) {
            if(name.equals("仁昌居士"))
               count++;
        }

????盡管這段代碼思想上 并不難理解,但是存在幾個(gè)問(wèn)題:
????(1) 從代碼量上來(lái)看,每一次的循環(huán)集合類(lèi),都需要重復(fù)寫(xiě)很多的樣板代碼。
????(2)對(duì)于for循環(huán)寫(xiě)的代碼塊,有些程序媛可能很難理解其編寫(xiě)意圖。需要閱讀整個(gè)循環(huán)體后,才能有一定的理解。假設(shè)只有一個(gè)for循環(huán),相對(duì)理解并不難,但是當(dāng)出現(xiàn)多層嵌套循環(huán),那理解所花費(fèi)的成本就大幅度提升了。
????分析一下for循環(huán)的實(shí)現(xiàn)原理,可知是通過(guò)調(diào)用了iterator()方法,產(chǎn)生了一個(gè)Iterator對(duì)象,通過(guò)while方法遍歷的顯式調(diào)用這個(gè)對(duì)象的hasNext()和next()方法。以實(shí)現(xiàn)需求。這種遍歷過(guò)程叫做外部遍歷,是一種串行化操作。

 Iterator<String> iterator = nameList.iterator();
        while(iterator.hasNext()){
            String name = iterator.next();
            if(name.equals("仁昌居士")){
                 count++;
            }
        }

????注意事項(xiàng):為什么對(duì)for循環(huán)叫他外部遍歷而不是外部迭代的原因?可見(jiàn)另一篇文章:還未寫(xiě),周末寫(xiě)。
????相對(duì)于外部遍歷,還有一種方法叫做內(nèi)部遍歷。通過(guò)內(nèi)部遍歷,將上述代碼實(shí)現(xiàn)為:

 long count = nameList.stream().filter(name -> name.equals("仁昌居士"))
                .count();

????上述代碼實(shí)際是三步,第一步:nameList創(chuàng)建了一個(gè)Stream實(shí)例,第二步:用fliter操作符過(guò)濾找出為“仁昌居士”的name,并轉(zhuǎn)換成另外一個(gè)Stream,第三步:把Stream的里面包含的內(nèi)容按照某種算法來(lái)成型成一個(gè)值,代碼中式用count操作符計(jì)算有幾個(gè)這樣的name。

2、 惰性求值和及早求值

????通常,在Java中調(diào)有一個(gè)方法,計(jì)算機(jī)會(huì)隨機(jī)執(zhí)行相應(yīng)的操作,比如通過(guò)println在終端上輸出一條信息。Stream里的方法則有些不同。比如說(shuō):

nameList.stream().filter(name -> name.equals("仁昌居士"));

????這行代碼并沒(méi)有通過(guò)fliter得到新的集合,只是對(duì)Stream進(jìn)行了描述,這種方法叫做“惰性求值”方法,而之后的“.count()”使Stream產(chǎn)生了值的方法,叫做“及早求值”方法。
????最好的驗(yàn)證方式就如下。
????單純的在filter中加入一條println語(yǔ)句:

   nameList.stream()
                .filter(name -> {
                  System.out.println(name);
                    return name.equals("仁昌居士");
                });

???? 運(yùn)行結(jié)果是程序并沒(méi)有輸出對(duì)應(yīng)信息。
????再測(cè)試:在后面加入一個(gè)及早求值方法,如count(),將會(huì)得到輸出結(jié)果。

 nameList.stream()
                .filter(name -> {
                    System.out.println(name);
                    return name.equals("仁昌居士");
                })
                .count();
輸出結(jié)果

????想知道操作符是惰性求值操作符還是及早求值操作符,只需觀察其返回值,如果返回值是Stream,則是惰性求值操作符;如果返回值是另一個(gè)類(lèi)型或者是void,則是及早求值操作符。通過(guò)這種多個(gè)惰性求值操作符+一個(gè)及早求值操作符消費(fèi)為結(jié)尾的鏈來(lái)得到想要的值,這個(gè)過(guò)程和建造者Builder模式很相似。建造者Builder模式就是通過(guò)使用一系列操作設(shè)置屬性和配置,最后通過(guò)一個(gè)build方法,將對(duì)象真正創(chuàng)建出來(lái)。

3、 常用的Stream操作符

????現(xiàn)在講述幾個(gè)比較常用的Stream API。

3.1 創(chuàng)建Stream操作符

3.1.1 of

????Stream的of操作符,是將一組數(shù)據(jù)生成一個(gè)Stream。是一個(gè)惰性求值操作符。

Stream nameStream =  Stream.of("仁昌居士","痕無(wú)羽","羽無(wú)痕");

3.1.2 generate

????生成一個(gè)無(wú)限長(zhǎng)度的Stream,其元素的生成是通過(guò)給定的Supplier(這個(gè)接口可以看成一個(gè)對(duì)象的工廠,每次調(diào)用返回一個(gè)給定類(lèi)型的對(duì)象),也是一個(gè)惰性求值操作符。

Stream.generate(() -> Math.random());

????生成一個(gè)無(wú)限長(zhǎng)度的Stream,其中值是隨機(jī)的。這個(gè)無(wú)限長(zhǎng)度Stream是懶加載,一般這種無(wú)限長(zhǎng)度的Stream都會(huì)配合Stream的limit()方法來(lái)用。

3.1.3 iterate

????iterate操作符生成無(wú)限長(zhǎng)度的Stream,和generator不同的是,其元素的生成是重復(fù)對(duì)給定的種子值(seed)調(diào)用用戶(hù)指定函數(shù)來(lái)生成的。其中包含的元素可以認(rèn)為是:seed,f(seed),f(f(seed))無(wú)限循環(huán),也是惰性求值操作符

Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println);

????這段代碼就是先獲取一個(gè)無(wú)限長(zhǎng)度的正整數(shù)集合的Stream,然后取出前10個(gè)打印。千萬(wàn)注意:使用limit方法,不然會(huì)無(wú)限打印下去。

3.2 轉(zhuǎn)換Stream操作符

3.2.1 map

????map操作符的作用就是將Stream中的每個(gè)值進(jìn)行同一個(gè)操作的處理后,再將其轉(zhuǎn)換為一個(gè)新的Stream,所以是惰性求值操作符。

 List<String> list =  Stream.of(1,2,3)
                .map(integer -> String.valueOf(integer))
                .collect(Collectors.toList());

????看上面這段代碼可知,通過(guò)map操作符和Lambda表達(dá)式將一個(gè)Integer類(lèi)型的參數(shù)轉(zhuǎn)成了一個(gè)String的返回值。參數(shù)和返回值直接不必是同一種類(lèi)型,但是Lambda表達(dá)式,必須是Function接口(只包含一個(gè)參數(shù)的普通函數(shù)接口)的一個(gè)實(shí)例。
????注意事項(xiàng):用map操作符得到的還是Stream。

3.2.2 flatMap

????flatMap操作符不同于map操作符將Stream中的值轉(zhuǎn)換為新值,他能將多個(gè)Stream合成一個(gè)Stream,返回值也是Stream。是惰性求值操作符。

        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(1);
        arrayList1.add(2);
        ArrayList<Integer> arrayList2 = new ArrayList<>();
        arrayList2.add(3);
        arrayList2.add(4);
        List<Integer> list3 = Stream.of(arrayList1,arrayList2)
        .flatMap(numbers -> numbers.stream())
        .collect(Collectors.toList());

????通過(guò)stream()方法,將每個(gè)ArrayList轉(zhuǎn)換成了Stream對(duì)象,其余部分由flatMap操作符處理,得到的Stream是Stream.of(1,2,3,4)。

3.2.3 distinct

????distinct操作符,是對(duì)Stream中包含的元素進(jìn)行去重操作(去重邏輯依賴(lài)元素的equals方法),新生成的Stream中沒(méi)有重復(fù)的元素。是惰性求值操作符。

Stream stream = Stream.of(1, 2, 3, 4,1,2,2,3,4)
                .distinct();

????得到的Stream里面的元素只有1,2,3,4四個(gè)。重復(fù)的都被去掉了。

3.2.4 filter

????fliter操作符,上文已經(jīng)提及過(guò)了,是用于過(guò)濾的惰性求值操作符。

  List<Integer> list =  Stream.of(1,2,3)
                .filter(integer -> integer >1)
                .collect(Collectors.toList());

????和map操作符相似,filter操作符接受一個(gè)函數(shù)為參數(shù),該函數(shù)通過(guò)Lambda表達(dá)式表示,如這段代碼,Lambda表達(dá)式將會(huì)對(duì)大于1的返回true,否則返回false。這段代碼就是通過(guò)filter操作符過(guò)濾選擇Lambda表達(dá)式返回值為true的元素保留生成新的Stream,并通過(guò)collect操作符得到符合要求的List。

3.2.5 peek

????peek生成一個(gè)包含原Stream的所有元素的新Stream,同時(shí)會(huì)提供一個(gè)消費(fèi)函數(shù)(Consumer實(shí)例),當(dāng)最終用及早求值操作符消費(fèi)此Stream時(shí),新Stream每個(gè)元素都會(huì)執(zhí)行給定的消費(fèi)函數(shù)。是惰性求值操作符。

 nameList.stream()
                .filter(name -> name.equals("仁昌居士"))
                .peek(name -> System.out.println(name))
                .collect(Collectors.toList());

3.2.6 limit

????limit對(duì)一個(gè)Stream進(jìn)行截?cái)嗖僮鳎@取其前N個(gè)元素,如果原Stream中包含的元素個(gè)數(shù)小于N,那就獲取其所有的元素,是惰性求值操作符。

Stream stream = Stream.of(1, 2, 3, 4,5,6,7,8,9,10)
                .limit(3);

????得到的新的Stream的元素只有前3個(gè)。后面的被截?cái)嗔恕?/p>

3.2.7 skip

????返回一個(gè)跳過(guò)原Stream的前N個(gè)元素后剩下元素組成的新Stream,如果原Stream中包含的元素個(gè)數(shù)小于N,那么返回空Stream,是惰性求值操作符。

Stream stream = Stream.of(1, 2, 3, 4,5,6,7,8,9,10)
                .skip(3);

????得到的新的Stream的元素只有后7個(gè)。前面的3個(gè)被跳過(guò)不要了。

3.3 成型(Reduce)Stream操作符

???? 成型(Reduce)Stream操作符和.reduce()操作符是兩個(gè)東西。
????成型(Reduce)是個(gè)概念,我將其理解為將Stream在經(jīng)過(guò)多次轉(zhuǎn)換操作后確定最終成型得到一個(gè)特定的非Stream的結(jié)果。
????而成型(Reduce)Stream操作符就是對(duì)Stream反復(fù)使用某個(gè)合并操作,把序列中的元素合并成一個(gè)整合結(jié)果的操作符。比如:max操作符、min操作符、sum操作符、count操作符、reduce()操作符、collect操作符等等。
????注意事項(xiàng):其中collect操作符和其他幾個(gè)操作符不同。他最終成型的結(jié)果是一個(gè)可變的容器,比如Collection或者StringBuilder。

3.3.1 max和min

????Stream中進(jìn)行大小比較是比較常用的操作,所以有了max和min操作符,返回值類(lèi)型是Optional,這是Java8防止出現(xiàn)NPE的一種可行方法,后面的文章會(huì)詳細(xì)介紹,這里就簡(jiǎn)單的認(rèn)為是一個(gè)容器,其中可能會(huì)包含0個(gè)或者1個(gè)對(duì)象。。
????查找Stream中的最大或最小元素,就要考慮是用什么作為排序的指標(biāo)。

   Integer integer3 = Stream.of(1, 2, 3, 4)
                .min((x,y) -> x.compareTo(y))
                .get();

????通過(guò)比較兩個(gè)對(duì)象的值的大小,來(lái)得到最小值。對(duì)于這個(gè)指標(biāo),也可以通過(guò)Comparator對(duì)象。

 Integer integer = Stream.of(1, 2, 3, 4)
                .min(Comparator.naturalOrder())
                .get();

????max和min方法同理,意思也一目了然,所以不用過(guò)多描述,都是及早求值操作符。

3.3.2 sum

????sum操作符不是所有的Stream對(duì)象都有的,只有IntStream、LongStream和DoubleStream是實(shí)例才有。

 int sum = IntStream.of(1, 2, 3, 4,5,6,7,8,9,10)
                .sum ();

????sum為55。求和的及早求值操作符。

3.3.3 count

????count操作符不是求Stream中元素的數(shù)量。

long count= Stream.of(0,1, 2, 3, 4,5,6,7,8,9)
                .count();

????count為10。求元素個(gè)數(shù)的及早求值操作符。

3.3.4 reduce

????reduce操作符是及早求值操作符,接受一個(gè)元素序列為輸入,反復(fù)使用某個(gè)合并操作,把序列中的元素合并成一個(gè)匯總的結(jié)果,其生成的值不是隨意的,而是根據(jù)指定的計(jì)算模型。像之前的count、min、max操作符都是reduce操作。
????reduce方法有三個(gè)override的方法。

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

???? 先來(lái)看reduce方法的第一種形式,其方法定義如下:

Optional<T> reduce(BinaryOperator<T> accumulator);

????接受一個(gè)BinaryOperator類(lèi)型的參數(shù),在使用的時(shí)候我們可以用lambda表達(dá)式來(lái)。

Stream.of(1,2,3,4,5,6,7,8,9,10).reduce((sum, item) -> sum + item).get();

????結(jié)果都為55。
???? 可以看到reduce方法接受一個(gè)函數(shù),這個(gè)函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)是上次函數(shù)執(zhí)行的返回值(也稱(chēng)為中間結(jié)果),第二個(gè)參數(shù)是stream中的元素,這個(gè)函數(shù)把這兩個(gè)值相加,得到的和會(huì)被賦值給下次執(zhí)行這個(gè)函數(shù)的第一個(gè)參數(shù)。要注意的是:第一次執(zhí)行的時(shí)候第一個(gè)參數(shù)的值是Stream的第一個(gè)元素,第二個(gè)參數(shù)是Stream的第二個(gè)元素。這個(gè)方法返回值類(lèi)型是Optional。
????再來(lái)看reduce方法的第二種形式,其方法定義如下:

T reduce(T identity, BinaryOperator<T> accumulator);

????與第一種變形相同的是都會(huì)接受一個(gè)BinaryOperator函數(shù)接口,不同的是其會(huì)接受一個(gè)identity參數(shù),用來(lái)指定Stream循環(huán)的初始值。如果Stream為空,就直接返回該值。另一方面,該方法不會(huì)返回Optional,因?yàn)樵摲椒ú粫?huì)出現(xiàn)null。

Stream.of(1,2,3,4,5,6,7,8,9,10).reduce(1, (sum, item) -> sum + item)).get();

????結(jié)果都為56。
????變形1,未定義初始值,從而第一次執(zhí)行的時(shí)候第一個(gè)參數(shù)的值是Stream的第一個(gè)元素,第二個(gè)參數(shù)是Stream的第二個(gè)元素。
???? 變形2,定義了初始值,從而第一次執(zhí)行的時(shí)候第一個(gè)參數(shù)的值是初始值,第二個(gè)參數(shù)是Stream的第一個(gè)元素。

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

????對(duì)于第三種變形,我們先看各個(gè)參數(shù)的含義,第一個(gè)參數(shù)類(lèi)型是實(shí)際返回實(shí)例的數(shù)據(jù)類(lèi)型,同時(shí)其為一個(gè)泛型也就是意味著該變形的可以返回任意類(lèi)型的數(shù)據(jù),第二個(gè)參數(shù)累加器accumulator,可以使用二元?表達(dá)式(即二元lambda表達(dá)式),聲明你在u上累加你的數(shù)據(jù)來(lái)源t的邏輯,例如(u,t)->u.sum(t),此時(shí)lambda表達(dá)式的行參列表是返回實(shí)例u和遍歷的集合元素t,函數(shù)體是在u上累加t,第三個(gè)參數(shù)組合器combiner,同樣是二元?表達(dá)式,(u,t)->u, 是用來(lái)處理并發(fā)操作的。因?yàn)镾tream是支持并發(fā)操作的,為了避免競(jìng)爭(zhēng),對(duì)于reduce線(xiàn)程都會(huì)有獨(dú)立的result,combiner的作用在于合并每個(gè)線(xiàn)程的result得到最終結(jié)果。這也說(shuō)明了了第三個(gè)函數(shù)參數(shù)的數(shù)據(jù)類(lèi)型必須為返回?cái)?shù)據(jù)類(lèi)型了。代碼并不好舉例,先不距離,在以后的講解中會(huì)提及。

3.3.5 collect

???? collect操作符:是一個(gè)及早求值操作符。它可以把Stream中的要有元素收集到一個(gè)結(jié)果容器中(比如Collection)。先看一下最通用的collect方法的定義(還有其他override方法)。

<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);

????先來(lái)看看這三個(gè)參數(shù)的含義:Supplier supplier是一個(gè)工廠函數(shù),用來(lái)生成一個(gè)新的容器;BiConsumer accumulator也是一個(gè)函數(shù),用來(lái)把Stream中的元素添加到結(jié)果容器中;BiConsumer combiner還是一個(gè)函數(shù),用來(lái)把中間狀態(tài)的多個(gè)結(jié)果容器合并成為一個(gè)(并發(fā)的時(shí)候會(huì)用到)。

List<Integer> numsWithoutNull = Stream.of(1,2,3,4,5,6,7,8,9,10)
                    .collect(() -> new ArrayList<Integer>(),(list, item) -> list.add(item),(list1, list2) -> list1.addAll(list2));

????上面這段代碼就是把一個(gè)元素是Integer類(lèi)型的List收集到一個(gè)新的List中。進(jìn)一步看一下collect方法的三個(gè)參數(shù),都是lambda形式的函數(shù)。
???? 第一個(gè)函數(shù)生成一個(gè)新的ArrayList實(shí)例;
????第二個(gè)函數(shù)接受兩個(gè)參數(shù),第一個(gè)是前面生成的ArrayList對(duì)象,二個(gè)是stream中包含的元素,函數(shù)體就是把stream中的元素加入ArrayList對(duì)象中。第二個(gè)函數(shù)被反復(fù)調(diào)用直到原stream的元素被消費(fèi)完畢;
????第三個(gè)函數(shù)也是接受兩個(gè)參數(shù),這兩個(gè)都是ArrayList類(lèi)型的,函數(shù)體就是把多個(gè)ArrayList容器合并成為一個(gè)。
???? 但是上面的collect方法調(diào)用有些復(fù)雜了,有更簡(jiǎn)單的override方法,其依賴(lài)Collector

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

????進(jìn)一步,Java8還給我們提供了Collector的工具類(lèi)–Collectors,其中已經(jīng)定義了一些靜態(tài)工廠方法,比如:Collectors.toCollection()收集到Collection中, Collectors.toList()收集到List中和Collectors.toSet()收集到Set中,等等。這樣的靜態(tài)方法還有很多,這里就不一一介紹了,大家可以直接去看文檔。下面看看使用Collectors對(duì)于代碼的簡(jiǎn)化:


List<Integer> numsWithoutNull = Stream.of(1,2,3,4,5,6,7,8,9,10)
                .collect(Collectors.toList());

????這段代碼將of()操作符得到的Stream,用collect(Collectors.toList())操作符從Stream中生成一個(gè)List。

4、 性能問(wèn)題

????完成了上述的講解,會(huì)發(fā)現(xiàn)在使用操作符時(shí),會(huì)出現(xiàn)對(duì)于一個(gè)Stream進(jìn)行多次轉(zhuǎn)換操作,每次都對(duì)Stream的每個(gè)元素進(jìn)行轉(zhuǎn)換,而且是執(zhí)行多次,這樣時(shí)間復(fù)雜度就是一個(gè)for循環(huán)里把所有操作都做掉的N(轉(zhuǎn)換的次數(shù))倍啊。其實(shí)不是這樣的,轉(zhuǎn)換操作都是lazy的,多個(gè)轉(zhuǎn)換操作只會(huì)在成型(Reduce)操作的時(shí)候融合起來(lái),一次循環(huán)完成。我們可以這樣簡(jiǎn)單的理解,Stream里有個(gè)操作函數(shù)的集合,每次轉(zhuǎn)換操作就是把轉(zhuǎn)換函數(shù)放入這個(gè)集合中,在成型(Reduce)操作的時(shí)候循環(huán)Stream對(duì)應(yīng)的集合,然后對(duì)每個(gè)元素一次性執(zhí)行所有的操作。

5、總結(jié)

????對(duì)于Stream,單純的書(shū)面理解是很難明白的,碼字看方法才是最好的學(xué)習(xí)方法。所以我的御姐兒,你還是多碼碼代碼吧。本居士很忙的啊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,071評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,409評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,569評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,360評(píng)論 6 404
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,895評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,123評(píng)論 0 286
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,643評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,559評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,742評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評(píng)論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,981評(píng)論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,363評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,622評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,354評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,707評(píng)論 2 370

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,776評(píng)論 18 139
  • Java8 in action 沒(méi)有共享的可變數(shù)據(jù),將方法和函數(shù)即代碼傳遞給其他方法的能力就是我們平常所說(shuō)的函數(shù)式...
    鐵牛很鐵閱讀 1,249評(píng)論 1 2
  • 3.4 說(shuō)說(shuō)相等和內(nèi)部表示 在Lisp中主要有5種相等斷言,因?yàn)椴皇撬械膶?duì)象被創(chuàng)建的時(shí)候都是相等意義上的相等。數(shù)...
    geoeee閱讀 1,839評(píng)論 0 6
  • 這是一篇我關(guān)于 GCD 的使用以及學(xué)習(xí)的總結(jié)文章。持續(xù)更新。感謝諸多大神在此之前寫(xiě)的各類(lèi)文章,如果可以,我會(huì)盡量把...
    黃穆斌閱讀 344評(píng)論 0 1
  • 好的節(jié)目總會(huì)給人帶來(lái)感動(dòng)。看朗讀者,每一個(gè)故事每一個(gè)人都讓我敬佩。今天更是有一份震驚。 盡管他們不是青春靚麗的年紀(jì)...
    zzzoou閱讀 263評(píng)論 0 0