天天看點

java8之Stream API

(一)Stream API簡述

Java8中有兩大最為重要的改變。第一個是 Lambda 表達式,另外一個則是 Stream API(java.util.stream.*)。 Stream 是 Java8 中處理集合的關鍵抽象概念,它可以指定你希望對 集合進行的操作,可以執行非常複雜的查找、過濾和映射資料等操作。 使Stream API 對集合資料進行操作,就類似于使用 SQL 執行的數 據庫查詢。也可以使用 Stream API 來并行執行操作。簡而言之, Stream API 提供了一種高效且易于使用的處理資料的方式。

1.流(Stream) 到底是什麼呢?

是資料管道,用于操作資料源(集合、數組等)所生成的元素序列。集合講的是資料,流講的是計算!

注意:

  • Stream 自己不會存儲元素。
  • Stream 不會改變源對象。相反,他們會傳回一個持有結果的新Stream。
  • Stream 操作是延遲執行的。這意味着他們會等到需要結果的時候才執行。

2.操作流的三個步驟:

  • 建立流:一個資料源(如:集合、數組),擷取一個流
  • 中間操作:一個中間操作鍊,對資料源的資料進行處理
  • 終止操作:一個終止操作,執行中間操作鍊,并産生結果

(二)Stream API的使用

1.建立Stream的6種方法

//方法一:集合建立流的方法
        List<Integer> list = Arrays.asList(1,2,3,4,5);
        Stream<Integer> stream = list.stream();
        Stream<Integer> parallelStream = list.parallelStream();

        //方法二:集合建立流
        int[] a = {1,2,3,4,5};
        IntStream intStream = Arrays.stream(a);

        //方法三:任意數值建立流
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);

        //方法四:由函數建立無限流
        Stream<Integer> limit = Stream.iterate(0, n -> n+2).limit(3);
        limit.forEach(s-> System.out.println("s = " + s));
        Stream<Double> generateA = Stream.generate(new Supplier<Double>() {
            @Override
            public Double get() {
                return java.lang.Math.random();
            }
        });

        Stream<Double> generateB = Stream.generate(()-> java.lang.Math.random());
        Stream<Double> generateC = Stream.generate(Math::random);
           

2.Stream中間操作

多個中間操作可以連接配接起來形成一個流水線,除非流水線上觸發終止操作,否則中間操作不會執行任何處理! 而在終止操作時一次性全部處理,稱為“惰性求值”。

2.1 映射

映射

方法 描述
map(Function<? super P_OUT, ? extends R> mapper)
           

接收一個函數作為參數,該函數會被應用到每個元

素上,并将其映射成一個新的元素。

mapToDouble(ToDoubleFunction<? super P_OUT> mapper)
           

接收一個函數作為參數,該函數會被應用到每個元

素上,産生一個新的 DoubleStream。

mapToInt(ToIntFunction<? super P_OUT> mapper)
           

接收一個函數作為參數,該函數會被應用到每個元

素上,産生一個新的 IntStream。

mapToLong(ToLongFunction<? super P_OUT> mapper)
           

接收一個函數作為參數,該函數會被應用到每個元

素上,産生一個新的 LongStream。

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

接收一個函數作為參數,将流中的每個值都換成另

一個流,然後把所有流連接配接成一個流。

方法使用

List<Employee> emps = Arrays.asList(
                new Employee(102, "李四", 59, 6666.66, Employee.Status.BUSY),
                new Employee(101, "張三", 18, 9999.99, Employee.Status.FREE),
                new Employee(103, "王五", 28, 3333.33, Employee.Status.VOCATION),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.BUSY),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.FREE),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.FREE),
                new Employee(105, "田七", 38, 5555.55, Employee.Status.BUSY)
        );
        //提取某個字段
        Stream<String> stringStream = emps.stream().map(employee -> employee.getName());
        DoubleStream doubleStream = emps.stream().mapToDouble(employee -> employee.getSalary());
        IntStream intStream = emps.stream().mapToInt(employee -> employee.getAge());

        //多個流合并成一個流,結果:list = [1, 2, 3, 4, 5, 6]
        List<Integer> list = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6))
                .flatMap(numbers -> numbers.stream()).collect(Collectors.toList());
        System.out.println("list = " + list);
           

2.2排序

排序

方法 描述
sorted()      
産生一個新流,其中按自然順序排序
sorted(Comparator<? super T> comparator)      
産生一個新流,其中按比較器順序排序

方法使用

List<Employee> emps = Arrays.asList(
                new Employee(102, "李四", 59, 6666.66, Employee.Status.BUSY),
                new Employee(101, "張三", 18, 9999.99, Employee.Status.FREE),
                new Employee(103, "王五", 28, 3333.33, Employee.Status.VOCATION),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.BUSY),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.FREE),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.FREE),
                new Employee(105, "田七", 38, 5555.55, Employee.Status.BUSY)
        );
        //從小到大排序
        emps.stream().map(Employee::getAge).sorted().forEach(System.out::println);
        //年齡相等按姓名排序,否則按年排序(升序)
        emps.stream()
                .sorted((x, y) -> {
                    if (x.getAge() == y.getAge()) {
                        return x.getName().compareTo(y.getName());
                    } else {
                        return Integer.compare(x.getAge(), y.getAge());
                    }
                }).forEach(System.out::println);
           

2.3歸納求和

規約

方法 說明
reduce(BinaryOperator<T> b)      
可以将流中元素反複結合起來,得到一個值。傳回 Optional<T>
reduce(T identity, BinaryOperator<T> b)      
可以将流中元素反複結合起來,得到一個值。傳回 T

方法使用

List<Employee> emps = Arrays.asList(
                new Employee(102, "李四", 59, 6666.66, Employee.Status.BUSY),
                new Employee(101, "張三", 18, 9999.99, Employee.Status.FREE),
                new Employee(103, "王五", 28, 3333.33, Employee.Status.VOCATION),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.BUSY),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.FREE),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.FREE),
                new Employee(105, "田七", 38, 5555.55, Employee.Status.BUSY)
        );
        //累加求和總薪水=48888.84000000001
        Optional<Double> sumSalary = emps.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        System.out.println("總薪水=" + sumSalary);

        //累加求和總年齡=167
        Optional<Integer> sumAge = emps.stream()
                .map(Employee::getAge)
                .reduce(Integer::sum);
        System.out.println("總年齡=" + sumAge);

        //累加employee.getAge()+1,累加求和總年齡=174
        double sum = emps.stream().mapToDouble(employee->employee.getAge()+1).sum();
        System.out.println("sum = " + sum);

        //歸納求和=15
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Integer sums = list.stream().reduce(0, (x, y) -> x + y);
        System.out.println("歸納求和=" + sums);

        //optional = 167
        Optional<Integer> optional = emps.stream().map(Employee::getAge).collect(Collectors.reducing(Integer::sum));
        System.out.println("optional = " + optional.get());
           

2.4篩選與切片

篩選與切片

方法 說明
filter(Predicate<? super T> predicate)      
接收 Lambda , 從流中排除某些元素。
distinct()      

篩選,通過流所生成元素的 hashCode() 和 equals() 去

除重複元素

limit(long maxSize)      
截斷流,使其元素不超過給定數量
skip(long n)      

跳過元素,傳回一個扔掉了前 n 個元素的流。若流中元素

不足 n 個,則傳回一個空流。與 limit(n) 互補

方法使用

//distinct--去除集合重複元素
        List<String> list = Arrays.asList("AA", "BB", "CC", "BB", "CC", "AA", "AA");
        long  counts = list.stream().distinct().count();

        //filter--接收 Lambda ,從流中排除AA些元素。
        Stream<String> stream = list.stream().filter(str -> !str.equals("AA"));
        stream.forEach(str-> System.out.println("str = " + str));

        //擷取前2個元素,AA,BB
        Stream<String> limit = list.stream().limit(2);
        limit.forEach(s -> System.out.println("s = " + s));

        //skip
        Stream<String> skip = list.stream().skip(2);
        skip.forEach(skips-> System.out.println("skips = " + skips));
           

2.5查找與比對

查找與比對

方法 說明
allMatch(Predicate<? super T> predicate)      
檢查是否比對所有元素
anyMatch(Predicate<? super T> predicate)      
檢查是否至少比對一個元素
noneMatch(Predicate<? super T> predicate)      
檢查是否沒有比對所有元素
findFirst()      
傳回第一個元素
findAny()      
傳回目前流中的任意元素
count()      
傳回流中元素總數
max(Comparator<? super T> comparator)      
傳回流中最大值
min(Comparator<? super T> comparator)      
傳回流中最小值
forEach(Consumer<? super T> action)      
内部疊代(使用 Collection 接口需要使用者去做疊
代,稱為外部疊代。相反,Stream API 使用内部疊代——它幫你把疊代做了)      

方法使用

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        //allMatch--檢查是否比對所有元素
        boolean allMatch = list.stream().allMatch(value -> value.equals(3));
        //anyMatch--檢查是否至少比對一個元素
        boolean anyMatch = list.stream().anyMatch(vaule -> vaule.equals(3));
        //noneMatch--檢查是否沒有比對的元素
        boolean noneMatch = list.stream().noneMatch(vaule -> vaule.equals(3));
        //findFirst--傳回第一個元素
        Integer firstnumber = list.stream().findFirst().get();
        //findAny--傳回目前流中的任意元素
        Integer anyNumber = list.stream().findAny().get();
        //count——傳回流中元素的總個數
        long count = list.stream().count();
        //max——傳回流中最大值
        Integer max = list.stream().max(Integer::compare).get();
        //min——傳回流中最小值
        Integer min = list.stream().min(Integer::compare).get();
           

3.Stream的終止操作

流中元素收集

方法 說明
collect(Collector<? super T, A, R> collector)      

将流轉換為其他形式。接收一個 Collector接口的

實作,用于給Stream中元素做彙總的方法

toList()      
把流中元素收集到List
toSet()      
把流中元素收集到Set
toCollection()      
把流中元素收集到建立的集合
counting()      
計算流中元素的個數
summingInt(ToIntFunction<? super T> mapper)      
對流中元素的整數屬性求和
averagingInt(ToIntFunction<? super T> mapper)      
計算流中元素Integer屬性的平均 值
summarizingInt(ToIntFunction<? super T> mapper)       
收集流中Integer屬性的統計值。如:平均值
joining()      
連接配接流中每個字元串
maxBy(Comparator<? super T> comparator)      
根據比較器選擇最大值      
reducing(BinaryOperator<T> op)      

從一個作為累加器的初始值

開始,利用BinaryOperator與

流中元素逐個結合,進而歸

約成單個值

collectingAndThen(Collector<T,A,R> downstream,
                                                            Function<R,RR> finisher)      

包裹另一個收集器,對其結

果轉換函數

inthow= list.stream().collect(Collectors.collectingAndThen(Collectors.toList()

groupingBy(Function<? super T, ? extends K> classifier)      

根據某屬性值對流分組,屬

性為K,結果為V

partitioningBy(Predicate<? super T> predicate)      
根據true或false進行分區

3.1Java8操作集合,實作List,Set,Map周遊

List<Employee> emps = Arrays.asList(
                new Employee(102, "李四", 59, 6666.66, Employee.Status.BUSY),
                new Employee(101, "張三", 18, 9999.99, Employee.Status.FREE),
                new Employee(103, "王五", 28, 3333.33, Employee.Status.VOCATION),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.BUSY),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.FREE),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.FREE),
                new Employee(105, "田七", 38, 5555.55, Employee.Status.BUSY)
        );
        //抽取一個元素封裝到另一個List容器
        List<String> list = emps.stream().map(Employee::getName).collect(Collectors.toList());
        //周遊list
        list.forEach(s->{
            System.out.println("s = " + s);
        });

        //抽取一個元素封裝到Set容器
        Set<Double> set = emps.stream().map(Employee::getSalary).collect(Collectors.toSet());
        //周遊set
        set.forEach(d -> {
            System.out.println("d = " + d);
        });
        System.out.println("set = " + set);

        /**
         * List -> Map
         * 需要注意的是:
         * toMap 如果集合對象有重複的key,會報錯Duplicate key ....
         *  Employee1,Employee2的id都為1。
         *  可以用 (k1,k2)->k1 來設定,如果有重複的key,則保留key1,舍棄key2
         */
        Map<Integer, Employee> map = emps.stream().collect(Collectors.toMap(Employee::getId, Employee -> Employee, (k1, k2) -> k1));
        System.out.println("map = " + map);
        //周遊map
        map.forEach((s,v)->{
            System.out.println("s = " + s);
        });
           

3.2一級分組、二級分組

List<Employee> emps = Arrays.asList(
                new Employee(102, "李四", 59, 6666.66, Employee.Status.BUSY),
                new Employee(101, "張三", 18, 9999.99, Employee.Status.FREE),
                new Employee(103, "王五", 28, 3333.33, Employee.Status.VOCATION),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.BUSY),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.FREE),
                new Employee(104, "趙六", 8, 7777.77, Employee.Status.FREE),
                new Employee(105, "田七", 38, 5555.55, Employee.Status.BUSY)
        );
        Map<Employee.Status, List<Employee>> map = emps.stream().collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println("map = " + map);

        Map<Employee.Status, Map<String, List<Employee>>> mapMap = emps.stream().collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy(
                (employee) -> {
                    if (employee.getAge() >= 60)
                        return "老年";
                    else if (employee.getAge() >= 35)
                        return "中年";
                    else
                        return "成年";
                }
        )));
        System.out.println("mapMap = " + mapMap);
           

3.3方法的使用

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        //toList--元素收集到List容器
        List<Integer> tolist = list.stream().collect(Collectors.toList());
        //toSet--元素收集到Set容器
        Set<Integer> set = list.stream().collect(Collectors.toSet());
        //toCollection--把流中元素收集到建立的集合
        ArrayList<Integer> arrayList = list.stream().collect(Collectors.toCollection(ArrayList::new));
        //counting--計算集合中元素的個數
        Long aLong = list.stream().collect(Collectors.counting());
        //summingInt--求集合中元素和
        Integer sum = list.stream().collect(Collectors.summingInt(i -> i));
        //averagingInt--求平均值
        Double average = list.stream().collect(Collectors.averagingInt(i -> i));
        System.out.println("average = " + average);
        // 結果: intSummary = IntSummaryStatistics{count=5, sum=15, min=1, average=3.000000, max=5}
        IntSummaryStatistics intSummary = list.stream().collect(Collectors.summarizingInt(i -> i));
        //maxBy--根據比較器選擇最大值
        Optional<Integer> optional = list.stream().collect(Collectors.maxBy(comparingInt(i -> i)));
        System.out.println("optional = " + optional.get());
           

3.4案例示範

/**
 * 一、 Stream 的操作步驟
 * <p>
 * 1. 建立 Stream
 * <p>
 * 2. 中間操作
 * <p>
 * 3. 終止操作
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class StreamApiTest {
    List<Employee> emps = Arrays.asList(
            new Employee(102, "李四", 59, 6666.66, Employee.Status.BUSY),
            new Employee(101, "張三", 18, 9999.99, Employee.Status.FREE),
            new Employee(103, "王五", 28, 3333.33, Employee.Status.VOCATION),
            new Employee(104, "趙六", 8, 7777.77, Employee.Status.BUSY),
            new Employee(104, "趙六", 8, 7777.77, Employee.Status.FREE),
            new Employee(104, "趙六", 8, 7777.77, Employee.Status.FREE),
            new Employee(105, "田七", 38, 5555.55, Employee.Status.BUSY)
    );
    @Test
    public void  test(){
        //提取某個字段
        Stream<String> stringStream = emps.stream().map(employee -> employee.getName());
        DoubleStream doubleStream = emps.stream().mapToDouble(employee -> employee.getSalary());
        IntStream intStream = emps.stream().mapToInt(employee -> employee.getAge());

        //多個流合并成一個流,結果:list = [1, 2, 3, 4, 5, 6]
        List<Integer> list = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6))
                .flatMap(numbers -> numbers.stream()).collect(Collectors.toList());
        System.out.println("list = " + list);

    }
    /**
     * 基本使用,從集合中提取對象的一個字段
     */
    @Test
    public void test001() {
        //方式一: 使用lambda
        Stream<String> stringStream = emps.stream().map((employee -> employee.getName()));
        stringStream.forEach(System.out::println);

        //方式二
        emps.stream().map(Employee::getName).forEach(System.out::println);
    }
    /**
     * Java8操作集合,實作List,Set,Map周遊
     */
    @Test
    public void test002() {
        //抽取一個元素封裝到另一個List容器
        List<String> list = emps.stream().map(Employee::getName).collect(Collectors.toList());
        //周遊list
        list.forEach(s->{
            System.out.println("s = " + s);
        });

        //抽取一個元素封裝到Set容器
        Set<Double> set = emps.stream().map(Employee::getSalary).collect(Collectors.toSet());
        //周遊set
        set.forEach(d -> {
            System.out.println("d = " + d);
        });
        System.out.println("set = " + set);

        /**
         * List -> Map
         * 需要注意的是:
         * toMap 如果集合對象有重複的key,會報錯Duplicate key ....
         *  Employee1,Employee2的id都為1。
         *  可以用 (k1,k2)->k1 來設定,如果有重複的key,則保留key1,舍棄key2
         */
        Map<Integer, Employee> map = emps.stream().collect(Collectors.toMap(Employee::getId, Employee -> Employee, (k1, k2) -> k1));
        System.out.println("map = " + map);
        //周遊map
        map.forEach((s,v)->{
            System.out.println("s = " + s);
        });
    }

    /**
     * 對集合進行過濾操作
     */
    @Test
    public void test003() {
        //這個過濾隻擷取大于5000&&Employee.Status.BUSY,而不是過濾掉
        List<Employee> list = emps.stream()
                .filter(employee -> employee.getSalary() > 5000
                        && employee.getStatus().equals(Employee.Status.BUSY))
                .collect(Collectors.toList());
        for(Employee employee : list){
            System.out.println("employee = " + employee);
        }
    }
    /**
     * 分組:
     * 一級分組
     * 多級分組
     */
    @Test
    public void test004() {
        Map<Employee.Status, List<Employee>> map = emps.stream().collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println("map = " + map);

        Map<Employee.Status, Map<String, List<Employee>>> mapMap = emps.stream().collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy(
                (employee) -> {
                    if (employee.getAge() >= 60)
                        return "老年";
                    else if (employee.getAge() >= 35)
                        return "中年";
                    else
                        return "成年";
                }
        )));
        System.out.println("mapMap = " + mapMap);

    }
    /**
     * 歸納求和
     */
    @Test
    public void test005() {
        //累加求和總薪水=48888.84000000001
        Optional<Double> sumSalary = emps.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        System.out.println("總薪水=" + sumSalary);

        //累加求和總年齡=167
        Optional<Integer> sumAge = emps.stream()
                .map(Employee::getAge)
                .reduce(Integer::sum);
        System.out.println("總年齡=" + sumAge);

        //累加employee.getAge()+1,累加求和總年齡=174
        double sum = emps.stream().mapToDouble(employee->employee.getAge()+1).sum();
        System.out.println("sum = " + sum);

        //歸納求和=15
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Integer sums = list.stream().reduce(0, (x, y) -> x + y);
        System.out.println("歸納求和=" + sums);

        //optional = 167
        Optional<Integer> optional = emps.stream().map(Employee::getAge).collect(Collectors.reducing(Integer::sum));
        System.out.println("optional = " + optional.get());
    }


    /*
    allMatch——檢查是否比對所有元素
    anyMatch——檢查是否至少比對一個元素
    noneMatch——檢查是否沒有比對的元素
    findFirst——傳回第一個元素
    findAny——傳回目前流中的任意元素
    count——傳回流中元素的總個數
    max——傳回流中最大值
    min——傳回流中最小值
    */
    @Test
    public void test006() {

        //allMatch——檢查是否比對所有元素
        boolean b1 = emps.stream().allMatch((employee -> employee.getStatus().equals(Employee.Status.BUSY)));
        System.out.println("傳回狀态:" + b1);

        //anyMatch——檢查是否至少比對一個元素
        boolean b2 = emps.stream().anyMatch((employee -> employee.getStatus().equals(Employee.Status.BUSY)));
        System.out.println("傳回狀态:" + b2);

        //檢查是否沒有比對的元素
        boolean b3 = emps.stream().noneMatch((employee -> employee.getStatus().equals(Employee.Status.BUSY)));
        System.out.println("傳回狀态:" + b3);

        //傳回第一個元素
        Optional<Employee> optional = emps.stream()
                .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
                .findFirst();
        System.out.println("擷取第一個元素" + optional.get());

        //傳回目前流中的任意元素
        Optional<Employee> any = emps.parallelStream().filter((employee -> employee.getStatus().equals(Employee.Status.FREE)))
                .findAny();
        System.out.println("傳回目前流中的任意元素" + any.get());

        //傳回流中元素的總個數
        long count = emps.stream().count();
        System.out.println("傳回流中元素的總個數==" + count);

        //傳回流中最大值
        Optional<Double> max = emps.stream().map(Employee::getSalary).max(Double::compare);
        System.out.println("傳回流中最大值==" + max);

        //傳回流中最小值
        Optional<Double> min = emps.stream().map(Employee::getSalary).min(Double::compare);
        System.out.println("傳回流中最小值==" + min);

    }
    @Test
    public void test007() {
        //取最大薪水
        Optional<Double> maxSalary = emps.stream().map(Employee::getSalary).collect(Collectors.maxBy(Double::compare));
        System.out.println("maxSalary = " + maxSalary.get());

        //取出集合中最大薪水的員工
        Optional<Employee> maxSalaryEmployee = emps.stream().collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println("maxSalaryEmployee = " + maxSalaryEmployee);

        //取最小薪水
        Optional<Double> minSalary = emps.stream().map(Employee::getSalary).collect(Collectors.minBy(Double::compare));
        System.out.println("minSalary = " + minSalary.get());

        //取出集合中最小薪水的員工
        Optional<Employee> minSalaryEmployee = emps.stream().collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println("minSalaryEmployee = " + minSalaryEmployee.get());

        //計算薪水總和
        Double sumSalary = emps.stream().collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println("sumSalary = " + sumSalary);

        //計算薪水準均值
        Double aveSalary = emps.stream().collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println("aveSalary = " + aveSalary);

        //計算集合中元素個數
        Long count = emps.stream().collect(Collectors.counting());
        System.out.println("count = " + count);

        //計算薪水最大,最小,平均,總和等等
        DoubleSummaryStatistics summaryStatistics = emps.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println("summaryStatistics = " + summaryStatistics.getMax());
    }
    @Test
    public void test008() {
        List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
        strList.stream().map(String::toUpperCase).forEach(System.out::println);
        System.out.println("--------------自定義方法過濾-----------------");
        strList.stream().map(StreamApiTest::filterCharacter).forEach(System.out::println);

    }

    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();
        for (Character ch : str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }
    //需求:搜尋名字中 “六” 出現的次數
    @Test
    public void test009() {
        Optional<Integer> sum = emps.stream()
                .map(Employee::getName)
                .flatMap(StreamApiTest::filterCharacter)
                .map((ch) -> {
                    if (ch.equals('六'))
                        return 1;
                    else
                        return 0;
                }).reduce(Integer::sum);

        System.out.println(sum.get());
    }

    /**
     * 集合中的元素排序
     */
    @Test
    public void test010() {
        //從小到大排序
        emps.stream().map(Employee::getAge).sorted().forEach(System.out::println);
        //年齡相等按姓名排序,否則按年排序(升序)
        emps.stream()
                .sorted((x, y) -> {
                    if (x.getAge() == y.getAge()) {
                        return x.getName().compareTo(y.getName());
                    } else {
                        return Integer.compare(x.getAge(), y.getAge());
                    }
                }).forEach(System.out::println);
    }

    /**
     * 字元串拼接
     */
    @Test
    public void test011() {
        String s = emps.stream().map(Employee::getName).collect(Collectors.joining("", "First", "End"));
        System.out.println("s = " + s);
    }
    /**
     * 分區操作
     */
    @Test
    public void test12() {
        Map<Boolean, List<Employee>> map = emps.stream().collect(Collectors.partitioningBy(e -> e.getSalary() >= 5000));
        System.out.println("map = " + map);
    }
    @Test
    public void test0013(){
        //rate = 0.666667
        BigDecimal rate = new BigDecimal(2).divide(new BigDecimal(3), 6, BigDecimal.ROUND_HALF_UP);
        System.out.println("rate = " + rate);
    }

}
//employeeList.parallelStream()
//        .map((String orderId) -> userHandler.queryInvestDetailByOrderId(orderId))
//        .filter((PrizeInvestDetailBO prizeInvestDetailBO) -> prizeInvestDetailBO != null && prizeInvestDetailBO.getPrizeType() != null && prizeInvestDetailBO.getPrizeType() == PrizeTypeEnum.COUPON.getCode())
//        .filter((PrizeInvestDetailBO prizeInvestDetailBO) -> userCouponInvestFlowDao.queryByPayOrderId(prizeInvestDetailBO.getPayOrderId()) == null)
//        .forEach((PrizeInvestDetailBO prizeInvestDetailBO) -> userInvestHandler.insertInvestDetail(prizeInvestDetailBO));