4. JDK8的集合流

之前寫了JDK8集合流的入門以及篩選,也就是集合流使用的打開和中間操作。這次帶來的是不同的收集數(shù)據(jù)的方式。

本節(jié)代碼GitHub地址:https://github.com/WeidanLi/Java-jdk8-collect

一、準(zhǔn)備:

還是老規(guī)矩杜跷,使用菜單進(jìn)行示例。(代碼的話建議拷貝這部分)

二矫夷、收集器簡(jiǎn)介

收集器即收集東西的容器葛闷,它用于使用集合流的時(shí)候的終端操作,即我們?cè)谌粘5臉I(yè)務(wù)邏輯中把流進(jìn)行過濾也好口四,進(jìn)行篩選也好孵运,然后我們總該要有一個(gè)容器可以存放這些過濾后的元素。這時(shí)候的收集器就派上用場(chǎng)了蔓彩。如代碼所示一個(gè)最簡(jiǎn)單的收集器的使用實(shí)例(當(dāng)然我感覺平時(shí)應(yīng)該沒人這么無聊)

 /**
 * 收集器是可以收集一個(gè)流中的數(shù)據(jù)的一個(gè)容器
 * cn.liweidan.collect.Demo01#demo01
 */
@Test
public void demo01(){
    List<Dish> collect = dishList.stream().collect(Collectors.toList());
    System.out.println(collect);
}

三治笨、JDK8提供的預(yù)定義收集器

官方為我們提供了預(yù)定義的收集器的一些常用的必要功能驳概,分別有:

  • 元素規(guī)約與匯總
  • 元素分組
  • 元素分區(qū)

1. 計(jì)算元素的個(gè)數(shù)counting()

counting()用于總結(jié)流中元素的個(gè)數(shù),有兩種寫法旷赖,分別如代碼所示顺又。counting()使用起來還是比較簡(jiǎn)單的。

/**
 * cn.liweidan.collect.Demo01#demo02()
 * counting()使用
 */
@Test
public void demo02(){
    /* 查詢卡路里大于400的菜單的個(gè)數(shù) */
    Long count = dishList.stream().filter(dish -> dish.getColories() > 400).collect(Collectors.counting());
    System.out.println("卡路里大于400的菜單個(gè)數(shù):" + count);
    
    /* 第二種寫法 */
    count = dishList.stream().filter(dish -> dish.getColories() > 400).count();
    System.out.println("卡路里大于400的菜單個(gè)數(shù):" + count);
}

2.查找流中的元素某個(gè)屬性的最大值或者最小值

我們通常需要去拿到一個(gè)對(duì)象集合中對(duì)象某個(gè)屬性進(jìn)行查詢最大和最小值等孵,按照J(rèn)DK8以前的寫法是需要先去遍歷集合中所有的對(duì)象稚照,去讀取某個(gè)屬性的值,然后去記錄最大值或者最小值進(jìn)行記錄俯萌,全部遍歷完成以后把該值進(jìn)行返回果录。這種寫法,描述起來也麻煩咐熙,寫起來也麻煩弱恒。

JDK8的流中就可以比較方便的拿到上面的需求。只需要在流中定義需要什么東西棋恼,當(dāng)流完成以后就可以取到所需要的值了返弹。不過我們需要先定義一個(gè)比較器,來告訴JVM我們需要個(gè)什么值爪飘。

/**
 * cn.liweidan.collect.Demo01#demo03()
 * 取出最大值以及最小值
 */
@Test
public void demo03(){
    /* 定義一個(gè)卡路里比較器 */
    Comparator<Dish> comparator = Comparator.comparingInt(Dish::getColories);
    /* Collectors.maxBy(comparator)即取出流中的最大值 */
    Optional<Dish> collect = dishList.stream().collect(Collectors.maxBy(comparator));
    System.out.println(collect.get());
    /* Collectors.minBy(comparator)即取出流中的最小值 */
    Optional<Dish> collect1 = dishList.stream().collect(Collectors.minBy(comparator));
    System.out.println(collect1.get());
}

不過有時(shí)候我們需要最大值以及最小值在一個(gè)流中取出义起,這時(shí)候我們可以使用后面的分組進(jìn)行實(shí)現(xiàn)。

4. 匯總

匯總即對(duì)集合中元素的某個(gè)屬性進(jìn)行統(tǒng)計(jì)师崎,如菜單中的所有卡路里的匯總默终。

/**
 * cn.liweidan.collect.Demo01#demo04()
 * 匯總:對(duì)集合中所有菜單的卡路里進(jìn)行統(tǒng)計(jì)計(jì)算
 */
@Test
public void demo04(){
    int collect = dishList.stream().collect(Collectors.summingInt(Dish::getColories));
    System.out.println(collect);
}

示例中我們使用了summingInt方法,當(dāng)然Collectors還提供了Long和Double方法對(duì)Long和Double進(jìn)行統(tǒng)計(jì)犁罩。

匯總不僅僅包括sum穷蛹,還包括了平均數(shù)、最大值最小值等等昼汗。Collectors同時(shí)還定義了averagingInt以及IntSummaryStatistics來分別拿出元素屬性的均值和所有統(tǒng)計(jì)數(shù)據(jù)(包括最大值、最小值鬼雀、均值等)

/**
 * 查詢菜單集合中卡路里的平均值以及所有統(tǒng)計(jì)數(shù)據(jù)
 */
@Test
public void demo05(){
    /* 查詢所有菜單卡路里的平均值 */
    Double collect = dishList.stream().collect(Collectors.averagingInt(Dish::getColories));
    System.out.println("卡路里均值:" + collect);
    /* 查詢菜單中所有的匯總數(shù)據(jù) */
    IntSummaryStatistics collect1 = dishList.stream().collect(Collectors.summarizingInt(Dish::getColories));
    System.out.println(collect1);// IntSummaryStatistics{count=9, sum=4200, min=120, average=466.666667, max=800}
}

5. joining連接字符串

joining方法可以把自動(dòng)調(diào)用對(duì)象的toString方法顷窒,然后把字符串連接在一起,如果需要使用分隔符源哩,只要把分隔符傳遞給該方法就可以了鞋吉。

/**
 * joining連接字符串
 */
@Test
public void demo06(){
    String collect = dishList.stream().map(Dish::getName).collect(Collectors.joining(", "));
    System.out.println(collect);
    // pork, beef, chicken, french fries, rice, season fruit, pizza, prawns, salmon
}

6. 實(shí)現(xiàn)自定義歸約--reduce使用

像蚊帳之前講的均值、最值這些操作励烦,其實(shí)都是官方對(duì)reduce常用方法的封裝谓着,如果官方提供的這些方法不能夠滿足要求的話,那么就需要我們自己來自定義reduce的實(shí)現(xiàn)了坛掠。

reduce需要傳入三個(gè)參數(shù):

  • 第一個(gè)參數(shù)是規(guī)約操作的起始值赊锚,即如果要統(tǒng)計(jì)總值的時(shí)候治筒,那么起始值是0

  • 第二個(gè)參數(shù)就是要調(diào)用的對(duì)象的方法了,即菜單的卡路里值

  • 第三個(gè)參數(shù)就是一個(gè)BinaryOperator操作了舷蒲,在這里定義我們拿到的值的操作方式耸袜。即相加。

  • 也可以直接只傳需要的操作牲平,去除前兩個(gè)參數(shù)堤框。

/**
 * cn.liweidan.collect.Demo01#demo07()
 * Collectors.reducing的使用
 */
@Test
public void demo07(){
    /**
     * 取出卡路里最大的菜單
     */
    Optional<Dish> collect = dishList.stream().collect(Collectors.reducing((d1, d2) -> d1.getColories() > d2.getColories() ? d1 : d2));
    System.out.println(collect.get());

    /**
     * 計(jì)算菜單總卡路里值
     */
    Integer integer1 = dishList.stream().collect(Collectors.reducing(0,// 初始值
            Dish::getColories,// 轉(zhuǎn)換函數(shù)
            Integer::sum));// 累積函數(shù)
    System.out.println(integer1);

    Integer integer2 = dishList.stream().map(Dish::getColories).reduce(Integer::sum).get();
    System.out.println(integer2);

    int sum = dishList.stream().mapToInt(Dish::getColories).sum();// 推薦
    System.out.println(sum);

}

在計(jì)算總和的時(shí)候,推薦使用mapToInt纵柿,因?yàn)榭梢悦馊プ詣?dòng)裝箱拆箱的性能消耗蜈抓。

四、分組

1. 簡(jiǎn)單分組

我們經(jīng)常需要對(duì)數(shù)據(jù)進(jìn)行分組昂儒,特別是在數(shù)據(jù)庫(kù)操作的時(shí)候沟使。當(dāng)我們需要從一個(gè)集合中進(jìn)行分組,代碼會(huì)變得十分復(fù)雜荆忍,分組功能剛好能夠解決這個(gè)問題格带。我們可以對(duì)菜單中的類型進(jìn)行分組,也可以根據(jù)卡路里的大小對(duì)菜單進(jìn)行自定義的分組刹枉。

/**
 * 簡(jiǎn)單分組
 */
@Test
public void test01(){
    /** 按照屬性類型進(jìn)行分組 */
    Map<Dish.Type, List<Dish>> collect = dishList.stream().collect(Collectors.groupingBy(Dish::getType));
    System.out.println(collect);
    // {FISH=[Dish(name=prawns, vegetarain=false, colories=300, type=FISH),
    // Dish(name=salmon, vegetarain=false, colories=450, type=FISH)],
    // OTHER=[Dish(name=french fries, vegetarain=true, colories=530, type=OTHER),
    // Dish(name=rice, vegetarain=true, colories=350, type=OTHER),
    // Dish(name=season fruit, vegetarain=true, colories=120, type=OTHER),
    // Dish(name=pizza, vegetarain=true, colories=550, type=OTHER)],
    // MEAT=[Dish(name=pork, vegetarain=false, colories=800, type=MEAT),
    // Dish(name=beef, vegetarain=false, colories=700, type=MEAT), Dish(name=chicken, vegetarain=false, colories=400, type=MEAT)]}

    /** 自定義簡(jiǎn)單的分組方式 */
    Map<CaloricLevel, List<Dish>> map = dishList.stream().collect(Collectors.groupingBy(d -> {
        /** 此處寫if的時(shí)候注意要顧及到所有的情況 */
        if(d.getColories() <= 400){
            return CaloricLevel.DIET;
        }else if (d.getColories() <= 700){
            return CaloricLevel.NORMAL;
        } else {
            return CaloricLevel.FAT;
        }
    }));
    System.out.println(map);
    // {FAT=[Dish(name=pork, vegetarain=false, colories=800, type=MEAT)],
    // NORMAL=[Dish(name=beef, vegetarain=false, colories=700, type=MEAT), Dish(name=french fries, vegetarain=true, colories=530, type=OTHER), Dish(name=pizza, vegetarain=true, colories=550, type=OTHER), Dish(name=salmon, vegetarain=false, colories=450, type=FISH)],
    // DIET=[Dish(name=chicken, vegetarain=false, colories=400, type=MEAT), Dish(name=rice, vegetarain=true, colories=350, type=OTHER), Dish(name=season fruit, vegetarain=true, colories=120, type=OTHER), Dish(name=prawns, vegetarain=false, colories=300, type=FISH)]}
}

2. 多級(jí)分組

如果我們需要進(jìn)行多級(jí)分組叽唱,比如根據(jù)菜單的類型分組的情況下又要根據(jù)卡路里大小進(jìn)行分組。那么我們可以在groupingBy中再傳入第二個(gè)groupingBy微宝。

/**
 * 多級(jí)分組
 */
@Test
public void test02(){
    Map<Dish.Type, Map<CaloricLevel, List<Dish>>> collect = 
            dishList.stream().collect(Collectors.groupingBy(Dish::getType, 
                    Collectors.groupingBy(d -> {
        if (d.getColories() <= 400) {
            return CaloricLevel.DIET;
        } else if (d.getColories() <= 700) {
            return CaloricLevel.NORMAL;
        } else {
            return CaloricLevel.FAT;
        }
    })));
    System.out.println(collect);
}

4. 按子組收集數(shù)據(jù)

在上一節(jié)的第二個(gè)參數(shù)傳遞的是一個(gè)groupingBy棺亭,但是收集器的第二個(gè)參數(shù)可以傳入其他的收集器,以便可以達(dá)到手機(jī)子組數(shù)據(jù)的目的蟋软。比如我們可以計(jì)算每種菜單分類的個(gè)數(shù)镶摘,傳入一個(gè)counting

/**
 * 多級(jí)分組收集數(shù)據(jù)
 */
@Test
public void test03(){
    /** 計(jì)算每一種品類的菜單個(gè)數(shù) */
    Map<Dish.Type, Long> typeLongMap = dishList.stream().collect(Collectors.groupingBy(Dish::getType, Collectors.counting()));
    System.out.println(typeLongMap);
}

5. 按照謂詞分區(qū)

partitioningBy:通過傳遞一個(gè)條件只有true和false的結(jié)果的表達(dá)式,返回的結(jié)果中包括true(滿足條件)的集合以及false(不滿足條件)的集合岳守。
比如凄敢,篩選出來質(zhì)數(shù)以及非質(zhì)數(shù),那么我們可以傳遞一個(gè)表達(dá)式或者一個(gè)方法湿痢,返回的是true和false涝缝,true表示是質(zhì)數(shù),false表示非質(zhì)數(shù)的集合譬重。和按子組收集數(shù)據(jù)的區(qū)別就是拒逮,這里還可以收集到不滿足條件的所有元素集合。

/**
 * 將數(shù)字按質(zhì)數(shù)以及非質(zhì)數(shù)分區(qū)
 */
@Test
public void test08(){
    int demoInt = 100;
    Map<Boolean, List<Integer>> collect = IntStream.rangeClosed(2, demoInt).boxed()
            .collect(Collectors.partitioningBy(candidate -> isPrime(candidate)));
    System.out.println(collect);
}

public boolean isPrime(int candidate){
    /** 通過傳遞的數(shù)字進(jìn)行開方臀规,我們只需要對(duì)傳遞的數(shù)字與開方的數(shù)字進(jìn)行比對(duì)即可滩援,計(jì)算次數(shù)會(huì)減少 */
    int candidateRoot = (int) Math.sqrt((double) candidate);
    /** 產(chǎn)生一個(gè)從2開始到開方跟的數(shù)字的數(shù)據(jù)流,與該數(shù)據(jù)流的每一個(gè)元素進(jìn)行求余 */
    return IntStream.rangeClosed(2, candidateRoot)
            .noneMatch(i -> candidate % i == 0);// 表示沒有一個(gè)元素與開方根的數(shù)字求余等于0的
}

五塔嬉、Collect靜態(tài)工廠方法表

工廠方法 返回類型 用途 示例
toList List<T> 把流中所有的項(xiàng)目收集到List dishList.collect(Collectors.toList())
toSet Set<T> 把流中所有的項(xiàng)目收集到Set dishList.collect(Collectors.toSet())
toCollection Collection<T> 把流中所有項(xiàng)目收集到給定的供應(yīng)源創(chuàng)建的集合 dishList.collect(Collectors. toCollection(), ArrayList::new)
counting Long 計(jì)算出來流中元素的個(gè)數(shù) dishList.collect(Collectors.counting)
summingInt Integer 計(jì)算出來集合中元素的某個(gè)屬性的和 int collect = dishList.stream().collect(Collectors.summingInt(Dish::getColories));
averagingInt Double 計(jì)算出集合中元素某個(gè)屬性的均值 Double collect = dishList.stream().collect(Collectors.averagingInt(Dish::getColories));
summarizingInt IntSummaryStatistics 計(jì)算出集合中元素某個(gè)屬性的統(tǒng)計(jì)值玩徊,包括最值租悄、均值、總和等 IntSummaryStatistics collect1 = dishList.stream().collect(Collectors.summarizingInt(Dish::getColories));
joinging String 連接流中每個(gè)元素調(diào)用toString進(jìn)行拼接佣赖,使用傳遞的分隔符進(jìn)行分割 String collect = dishList.stream().map(Dish::getName).collect(Collectors.joining(", "));
maxBy Optional<T> 通過傳遞的比較器收集元素中屬性最大的值恰矩,如果流為空則返回Optional.empty() Optional<Dish> collect = dishList.stream().collect(Collectors.reducing((d1, d2) -> d1.getColories() > d2.getColories() ? d1 : d2));
minBy Optional<T> 通過傳遞的比較器收集元素中屬性最小的值,如果流為空則返回Optional.empty()
reducing 歸約操作產(chǎn)生的類型 從一個(gè)作為累加器的起始值開始憎蛤,利用BinaryOperator與流中的元素逐個(gè)結(jié)合外傅,從而將流規(guī)約為單個(gè)值 Integer integer1 = dishList.stream().collect(Collectors.reducing(0,Dish::getColories,Integer::sum));
collectingAndThen 轉(zhuǎn)換函數(shù)返回的類型 包裹另外一個(gè)收集器,對(duì)其結(jié)果進(jìn)行轉(zhuǎn)換
groupingBy Map<K, List<T>> 對(duì)流中元素的每個(gè)值進(jìn)行分組
partitioningBy Map<boolean, List<T>> 對(duì)流中元素的每個(gè)值進(jìn)行分區(qū)

六俩檬、開發(fā)自定義收集器

方式一

如果我們需要開發(fā)自己的自定義收集器的時(shí)候萎胰,需要讓我們自己的收集器去實(shí)現(xiàn)Collector接口。
Collector接口一共有五個(gè)方法去自己實(shí)現(xiàn)棚辽,現(xiàn)在我們用開發(fā)我們自己的ToList收集器為例技竟,寫一個(gè)我們自己的收集器。

package cn.liweidan.custom.collector;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

/**
 * <p>Desciption:自定義ToList收集器</p>
 * CreateTime : 2017/7/10 下午6:37
 * Author : Weidan
 * Version : V1.0
 */
public class MyListCollector<T> implements Collector<T, List<T>, List<T>> {

    /*
        第一個(gè)泛型指的是需要收集的流的泛型
        第二個(gè)泛型指的是累加器在收集時(shí)候的類型
        第三個(gè)泛型指的是返回的類型(可能不是集合屈藐,比如counting())
     */

    /**
     * 建立一個(gè)新的結(jié)果容器
     * @return
     */
    @Override
    public Supplier<List<T>> supplier() {
        return ArrayList::new;
    }

    /**
     * 將元素累加到容器中去
     * @return
     */
    @Override
    public BiConsumer<List<T>, T> accumulator() {
        return (list, item) -> list.add(item);
    }

    /**
     * 對(duì)結(jié)果容器進(jìn)行最終轉(zhuǎn)換(如需要轉(zhuǎn)換成Long返回榔组,則在這一步體現(xiàn))
     * @return
     */
    @Override
    public Function<List<T>, List<T>> finisher() {
        return Function.identity();// 此處無需進(jìn)行轉(zhuǎn)換,直接返回此函數(shù)即可
    }

    /**
     * 對(duì)每個(gè)子流中的數(shù)據(jù)進(jìn)行規(guī)約操作
     * 即在集合流中联逻,處理器會(huì)將集合流進(jìn)行不停地分割搓扯,分割到一定的很多的小子流的時(shí)候,再進(jìn)行操作
     * 在這一步就是將每一個(gè)小流中的元素合并到一起
     * @return
     */
    @Override
    public BinaryOperator<List<T>> combiner() {
        return (list1, list2) ->{
            list1.addAll(list2);
            return list1;
        };
    }

    /**
     * 這個(gè)方法是定義流返回的情況包归,一共有三種情況锨推,存放于Characteristics枚舉中
     * UNORDERED:規(guī)約結(jié)果不受項(xiàng)目的遍歷和累計(jì)順序的影響
     * CONCURRENT:accumulator函數(shù)可以從多個(gè)線程去調(diào)用。如果收集器沒有標(biāo)記UNORDERED那他僅用在無需數(shù)據(jù)源才可以規(guī)約
     * INDENTITY_FINISH:表明完成器方法返回的是一個(gè)恒等函數(shù)公壤,可以跳過换可。標(biāo)記這種情況則表示累加器A可以不加檢查的轉(zhuǎn)換為累加器B
     * @return
     */
    @Override
    public Set<Characteristics> characteristics() {
        return Collections.unmodifiableSet(EnumSet.of(Characteristics.CONCURRENT, Characteristics.IDENTITY_FINISH));
    }
}

現(xiàn)在對(duì)我們自己的收集器進(jìn)行測(cè)試,這里與自帶的收集器的區(qū)別就是我沒有定義工廠模式去拿到toList收集器的實(shí)例厦幅,而是需要自己手動(dòng)new出來沾鳄。

@Test
public void test(){
    List<Dish> collect = dishList.stream().collect(new MyListCollector<Dish>());
    System.out.println(collect);
}

方式二

方式二比較簡(jiǎn)單,但是功能也稍微差一點(diǎn)确憨。就是通過使用collect方法的重載方法進(jìn)行自定義收集器洞渔,并不需要去實(shí)現(xiàn)Collector接口。

/**
 * 使用方式二進(jìn)行自定義收集
 */
@Test
public void test02(){
    ArrayList<Object> collect = dishList.stream().collect(
            ArrayList::new, // 相當(dāng)于方式一的supplier()方法缚态,用于創(chuàng)建一個(gè)容器
            List::add,// 相當(dāng)于方式一的accumulator方法,用于迭代遍歷每個(gè)元素進(jìn)行加入容器
            List::addAll// 規(guī)約并行中所有的容器
    );
    System.out.println(collect);
}

另外值得注意的是堤瘤,這個(gè)方法并不能傳遞任何關(guān)于characteristics的信息玫芦,也就是說,默認(rèn)已經(jīng)給我們?cè)O(shè)定為INDENTITY_FINISH以及CONCURRENT了本辐。

七桥帆、開發(fā)自己的質(zhì)數(shù)收集器

在前面我們已經(jīng)試驗(yàn)過一個(gè)質(zhì)數(shù)收集器了医增,在這里使用自定義收集器再收集一次一定范圍內(nèi)的質(zhì)數(shù)。在之前老虫,我們是使用小于被測(cè)數(shù)的平方根的數(shù)字進(jìn)行對(duì)比叶骨,到了這里我們?cè)僮鲞M(jìn)一步的優(yōu)化,就是只拿小于被測(cè)數(shù)的平方根的質(zhì)數(shù)作為除數(shù)祈匙。

PrimeNumberCollector:

package cn.liweidan.custom.collector2;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;

/**
 * <p>Desciption:質(zhì)數(shù)收集器</p>
 * CreateTime : 2017/7/11 上午10:43
 * Author : Weidan
 * Version : V1.0
 */
public class PrimeNumberCollector implements Collector<Integer,
                                            Map<Boolean, List<Integer>>,
                                        Map<Boolean, List<Integer>>> {

    public static <A> List<A> takeWhile(List<A> list, Predicate<A> p){
        int i = 0;
        for (A a : list) {
            if(!p.test(a)){
                return list.subList(0, i);
            }
            i++;
        }
        return list;
    }

    /**
     * 拿到所有的質(zhì)數(shù)忽刽,以及被測(cè)數(shù)字。取出小于被測(cè)數(shù)的平方根與所有質(zhì)數(shù)比較夺欲,只拿被測(cè)數(shù)與小于平方根的質(zhì)數(shù)做計(jì)算
     * @param primes
     * @param candidate
     * @return
     */
    public static boolean isPrime(List<Integer> primes, int candidate) {
        int candidateRoot = (int) Math.sqrt((double) candidate);
        return takeWhile(primes, i -> i <= candidateRoot)
                .stream()
                .noneMatch(p -> candidate % p == 0);
    }

    @Override
    public Supplier<Map<Boolean, List<Integer>>> supplier() {
        return () -> new HashMap<Boolean, List<Integer>>(){{
            put(true, new ArrayList<>());
            put(false, new ArrayList<>());
        }};
    }

    @Override
    public BiConsumer<Map<Boolean, List<Integer>>, Integer> accumulator() {
        return (Map<Boolean, List<Integer>> acc, Integer candidate) -> {
            acc.get(isPrime(acc.get(true), candidate))
                    .add(candidate);
        };
    }

    @Override
    public BinaryOperator<Map<Boolean, List<Integer>>> combiner() {
        return null;
    }

    @Override
    public Function<Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> finisher() {
        return Function.identity();
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH));
    }
}

測(cè)試:

@Test
public void test01(){
    Map<Boolean, List<Integer>> collect = IntStream.rangeClosed(2, 100).boxed().collect(new PrimeNumberCollector());
    System.out.println(collect);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末跪帝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子些阅,更是在濱河造成了極大的恐慌伞剑,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件市埋,死亡現(xiàn)場(chǎng)離奇詭異黎泣,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)缤谎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門抒倚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人弓千,你說我怎么就攤上這事衡便。” “怎么了洋访?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵镣陕,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我姻政,道長(zhǎng)呆抑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任汁展,我火速辦了婚禮鹊碍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘食绿。我一直安慰自己侈咕,他們只是感情好器紧,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著铲汪,像睡著了一般罐柳。 火紅的嫁衣襯著肌膚如雪狰住。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天催植,我揣著相機(jī)與錄音,去河邊找鬼查邢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛扰藕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播邓深,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼未桥,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了芥备?” 一聲冷哼從身側(cè)響起冬耿,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎萌壳,沒想到半個(gè)月后亦镶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡袱瓮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年缤骨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尺借。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绊起,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出燎斩,到底是詐尸還是另有隱情虱歪,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布栅表,位于F島的核電站笋鄙,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏怪瓶。R本人自食惡果不足惜局装,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铐尚,春花似錦、人聲如沸哆姻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矛缨。三九已至爹脾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間箕昭,已是汗流浹背灵妨。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留落竹,地道東北人泌霍。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像述召,于是被迫代替她去往敵國(guó)和親朱转。 傳聞我的和親對(duì)象是個(gè)殘疾皇子藤为,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理缅疟,服務(wù)發(fā)現(xiàn)存淫,斷路器错览,智...
    卡卡羅2017閱讀 134,715評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,321評(píng)論 25 707
  • 昨天寫文章寫著寫著睡著了忌愚,看來却邓,真是老了,咳咳简十,誰來攙我一把,老身走不動(dòng)了……怎么還沒人來?yè)轿一帜眨懔艘饶疫€是自己走...
    飛雪_飄渺閱讀 324評(píng)論 4 3
  • 昨晚夢(mèng)到一個(gè)漂亮的不像話的男孩子牵署,好像,是我的兒子青责。 很高興半沽,又在夢(mèng)里有疑惑:是我的兒子嗎? 今早想起來浩村,依然高興...
    顧嶠閱讀 96評(píng)論 0 0
  • 天高云淡鄉(xiāng)間好心墅,蔬果俱鮮榨乎。 圍坐爐邊,約會(huì)尋愁硪Γ縷縷煙肛捍。 風(fēng)輕日暖深春意,眾鳥和弦依许。 細(xì)水流年缀蹄,人在閑中便是仙膘婶。
    悠游魚閱讀 298評(píng)論 0 1