Stream01 定义、迭代、操作、惰性求值、创建流、并行流、收集器、stream运行机制

 

1 Stream

  Stream 是 Java 8 提供的一系列对可迭代元素处理的优化方案,使用 Stream 可以大大减少代码量,提高代码的可读性并且使代码更易并行。

 

2 迭代

  2.1 需求

    随机创建int类型的数组,计算数组中各个元素的总和

  2.2 思路

    2.2.1 外部迭代

      通过for循环迭代数组

    2.2.2 内部迭代

      先将数组转化成流 -> 在通过流的相关操作来实现

    2.2.3 外部迭代和内部迭代

      外部迭代式串行的,如果要实现并行需要自己编写代码实现;内部迭代实现并行操作只需要调用一个parallel()操作即可以啦

  2.3 代码实现

package demo01_iteration;

import org.junit.Before;
import org.junit.Test;

import java.util.Arrays;
import java.util.Random;
import java.util.stream.IntStream;

/**
 * @author 王杨帅
 * @create 2018-06-24 22:48
 * @desc 外部迭代和内部迭代
 **/
public class Case01 {

    private int [] nums;
    private int count = 4;
    private Random random;

    @Before
    public void init() {
        random = new Random();
        nums = new int[count];
        for (int i = 0; i < nums.length; i++) { // 随机产生数组元素
            nums[i] = random.nextInt(30);
        }
    }

    /**
     * 外部迭代:自己利用for训话实现
     */
    @Test
    public void test01() {
        int sum = 0;
        for (int i : nums) {
            sum += i;
        }
        System.out.println(Arrays.toString(nums) + " 各个元素的累加和为:" + sum);
    }

    /**
     * 内部迭代:利用流的相关方法实现
     */
    @Test
    public void test02() {
        int sum = 0;
        sum = IntStream.of(nums).parallel().sum();
        System.out.println(Arrays.toString(nums) + " 各个元素的累加和为:" + sum);
    }

}
View Code

 

3 操作

  3.1 分类

    3.1.1 中间操作

      返回一个Stream流的操作

package demo05_webflux.chapter03;

import java.util.Random;
import java.util.stream.Stream;

/**
 * @author 王杨帅
 * @create 2018-07-30 20:42
 * @desc 中间操作
 **/
public class Case02StreamDemo02 {

    public static void main(String [] args) {
        String str = "MY NAME IS FURY";

//        Stream.of(str.split(" ")).forEach(System.out::println);
//
//        Stream.of(str.split(" ")).map(s -> s.length()).forEach(System.out::println);

//        Stream.of(str.split(" ")) // 获取流
//                .map(s -> s.length()) // 获取流元素的长度并将其组成一个流
//                .filter(l -> l > 2) // 过滤流
//                .forEach(System.out::println); // 循环打印流元素

        /**
         *      flatMap: 一个流由A对象组成,A对象中由B属性,而且属性是一个集合;利用flatMap可以获取到流中所有元素
         * 的B属性的元素组合成的新流
         */
//        Stream.of(str.split(" "))
//                .flatMap(s -> s.chars().boxed())
//                .forEach(System.out::println);
//        String实例.chars() 返回的结果是 IntStream -> IntStream 不是 Stream 的子类,所以需要用 boxed 做一个装箱擦操作,使之变成 Stream<Integer>
//        String str02 = "warrior";
//        str02.chars().boxed().forEach(System.out::println);

        /**
         * peek :和forEach的功能是一样的,只不过peek是中间操作【常用于调试】,forEach是终止操作
         */
//        Stream.of(str.split(" "))
//                .peek(System.out::println)
//                .forEach(System.out::println);

        new Random()
                .ints() // 产生流
                .filter(i -> i > 10 && i < 100) // 过滤流
                .limit(10) // 限制流的长度
                .forEach(System.out::println);


    }



}
View Code
package demo_test02;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author 王杨帅
 * @create 2018-08-02 11:04
 * @desc
 **/
public class Demo03 {

    public static void main(String[] args) {

        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 4, 3, 2, 1, 5);

//        stream.distinct().forEach(System.out::println);

//        stream.sorted().forEach(System.out :: println);

//        stream.limit(5).forEach(System.out :: println);

        stream.skip(3).forEach(System.out::println);


    }

}
View Code

    

package demo02_operation;

import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream;

/**
 * @author 王杨帅
 * @create 2018-06-25 7:46
 * @desc 中间操作
 **/
public class Case02 {

    private String str;

    @Before
    public void init() {
        str = "My name is warrior and I come from yuzu .";
    }

    /**
     * 中间操作:map -> 对每个流元素进行相同操作
     */
    @Test
    public void test01() {

        Stream.of(str.split(" ")) // 创建单词流
                .map(s -> s.length()) // 中间操作:获取每个单词的长度
//                .forEach(System.out::println); // 遍历打印每个单词的长度
                .forEach(i -> System.out.println(i));

    }

    /**
     * 中间操作:filter -> 主要是过滤作用
     */
    @Test
    public void test02() {
        Stream.of(str.split(" ")) // 创建字符串流
                .filter(s -> s.length() >= 4) // 过滤操作:只要单词长度大于等于4的单词
                .forEach(System.out::println); // 打印输出:打印单词长度大于等于4的单词
    }

    /**
     * 中间操作:flatMap -> A元素中有B元素,而且B元素是一个集合;利用flatMap可以得到B元素集合
     *      技巧01:intStream/longStream不是Stream的子类,所以需要进行装箱操作
     *      技巧02:Integer类型也不能直接强转成char类型,必须进行拆箱操作
     */
    @Test
    public void test03() {
//        Stream.of(str.split(" "))
//                .flatMap(s -> s.chars().boxed())
//                    .forEach(System.out::println);

//        优化之后

        Stream.of(str.split(" "))
                .flatMap(s -> s.chars().boxed())
                .forEach(i -> System.out.println((char)i.intValue()));
    }

    /**
     * 中间操作:peek -> 和forEach一行,只不过前者是中间操作用于debug用,后者是终止操作
     */
    @Test
    public void test04() {
        Stream.of(str.split(" "))
                .peek(System.out::println)
                .forEach(System.out::println);
    }

    /**
     * 中间操作:limit -> 主要用于限制无限流
     */
    @Test
    public void test05() {
        new Random().ints()
                .filter(i -> i >= 100 && i <= 1000)
                .limit(10)
                .forEach(System.out::println);
    }

}
View Code

 

    3.1.2 终止操作

      返回一个结果的操作

      短路操作:发现符合条件的就结束流操作

package demo05_webflux.chapter03;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author 王杨帅
 * @create 2018-07-30 21:20
 * @desc 终止操作
 **/
public class Case03StreamDemo03 {

    public static void main(String[] args) {

        String str = "my name is fury";

        str.chars()
                .parallel()
                .forEach(i -> System.out.print((char)i));

        System.out.println("\n===分割线===");

        /**
         * forEachOrdered 可以保证顺序
         */
        str.chars()
                .parallel()
                .forEachOrdered(i -> System.out.print((char)i));
        System.out.println("\n===分割线===");

        // 转化成集合
        List<String> list = Stream.of(str.split(" "))
                .collect(Collectors.toList());
        System.out.println(list);
        System.out.println("===分割线===");

        // 转化成数组【只能转化成Objec类型的数组】
        Object[] arr = Stream.of(str.split(" "))
                .toArray();
        System.out.println(Arrays.toString(arr));
        System.out.println("===分割线===");

        /**
         * 利用reduce进行拼接【reduce有三个重载方法】
         */
        Optional<String> result = Stream.of(str.split(" "))
                .reduce((s1, s2) -> s1 + "|" + s2);
        System.out.println(result.orElse("数据为空"));
        System.out.println("===分割线===");

        Integer result02 = Stream.of(str.split(" "))
                .map(i -> i.length())
                .reduce(0, (s1, s2) -> s1 + s2);
        System.out.println(result02);
        System.out.println("===分割线===");

        Optional<Integer> resul03 = Stream.of(str.split(" "))
                .map(s -> s.length())
                .max((s1, s2) -> s1 - s2);
        System.out.println(resul03.orElse(-1));




    }

}
View Code

      

package demo02_operation;

import org.junit.Before;
import org.junit.Test;

import javax.swing.text.html.Option;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author 王杨帅
 * @create 2018-06-25 8:17
 * @desc 终止操作
 **/
public class Case03 {

    private String str;

    @Before
    public void init() {
        str = "My Name is warrior and I am from yuzu .";
    }

    /**
     * 在进行并行操作时 forEachOrdered 的妙用
     */
    @Test
    public void test01() {
        System.out.println("原始数据:" + str);
        str.chars() // 将字符串转化成intStream
                .parallel() // 并行操作
                .forEach(i -> System.out.print((char)i)); // 并行操作时不可以保证顺序
        System.out.println();
        System.out.println("===分割线===");
        str.chars()
                .parallel()
                .forEachOrdered(i -> System.out.print((char)i)); // 并行操作时可以保证顺序
    }

    /**
     * 终止操作:collect -> 将流转化成一个集合
     */
    @Test
    public void test02() {
        List<String> stringList = Stream.of(str.split(" ")) // 创建单词流
                .collect(Collectors.toList()); // 将单词流转化成集合

        System.out.println(stringList);
    }

    /**
     * 终止操作: toArray -> 将流转化成一个数组
     */
    @Test
    public void test03() {
        Object[] objects = Stream.of(str.split(" "))
                .toArray();

        System.out.println(Arrays.toString(objects));
    }

    /**
     * 终止操作:reduce -> 拼接流元素
     */
    @Test
    public void test04() {

        Optional<String> optional = Stream.of(str.split(" "))
                 .reduce((s1, s2) -> s1 + "|" + s2);

//        System.out.println(optional.get()); // 如果为空会抛出异常
        System.out.println(optional.orElse("数据为空")); // 如果为空就返回提示信息【推荐使用】

    }

    /**
     * 终止操作:reduce 之 带初始化的reduce终止操作
     */
    @Test
    public void test05() {
        String result = Stream.of(str.split(" "))
                .reduce("", (s1, s2) -> s1 + "|" + s2);

        System.out.println(result);
    }

    /**
     * 终止操作:reduce 之 带初始化的reduce终止操作小demo
     */
    @Test
    public void test06() {
        Integer integer = Stream.of(str.split(" "))
                .map(s -> s.length())
                .reduce(0, (s1, s2) -> s1 + s2);

        System.out.println("所有流单词的长度为:" + integer);
    }

    /**
     * 终止操作:max -> 获取最大值
     */
    @Test
    public void test07() {
        System.out.println("原始数据:" + str);

        Optional<String> optional = Stream.of(str.split(" "))
                .max((s1, s2) -> s1.length() - s2.length());

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

    /**
     * 终止操作: min -> 获取最小值
     */
    @Test
    public void test08() {
        System.out.println("原始数据:" + str);

        Optional<String> optional = Stream.of(str.split(" "))
                .min((s1, s2) -> s1.length() - s2.length());

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

    /**
     * 终止操作:count -> 获取流中的元素数量
     */
    @Test
    public void test09() {
        System.out.println("原始数据为:" + str);
        Long num = Stream.of(str.split(" "))
                .count();
        System.out.println("流中元素的数量为:" + num);
    }

    /**
     * 终止操作:findFirst -> 寻找流中的第一个元素
     */
    @Test
    public void test11() {
        OptionalInt first = new Random().ints().findFirst();
        System.out.println("流中的第一个元素为:" + first);
    }


    /**
     * 中间操作:sorted -> 排序操作
     */
    @Test
    public void test10() {
        List<String> result = Stream.of(str.split(" ")) // 获取单词流
                .sorted(Comparator.comparing(i -> i.length())) // 根据长度排序
                .collect(Collectors.toList());

        System.out.println(result);
    }

}
View Code

 

  3.2 代码体验

package demo02_operation;

import org.junit.Before;
import org.junit.Test;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Random;
import java.util.stream.IntStream;

/**
 * @author 王杨帅
 * @create 2018-06-24 23:04
 * @desc 中间操作、终止操作、惰性求值
 **/
public class Case01 {

    private int [] nums;
    private int count = 5;
    private Random random;

    @Before
    public void init() {
        random = new Random();
        nums = new int[count];
        for (int i = 0; i < nums.length; i++) {
            nums[i] = random.nextInt(30);
        }
    }

    /**
     * 终止操作: 返回一个结果的操作
     */
    @Test
    public void test01() {
        int sum = IntStream.of(nums).sum();
        System.out.println(Arrays.toString(nums) + " 各个元素之和为: " + sum);
    }

    /**
     * 中间操作:返回一个流的操作【例如:Map操作】
     */
    @Test
    public void test02() {
        System.out.println("老的数组为:" + Arrays.toString(nums));
        int [] newNums = IntStream.of(nums).map(s -> s + 2).toArray();
        System.out.println("新的数组为:" + Arrays.toString(newNums));
    }


}
View Code

 

4 惰性求值

  如果流的操作中没有执行终止操作也不会执行中间操作

  4.1 代码体验

package demo02_operation;

import org.junit.Before;
import org.junit.Test;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Random;
import java.util.stream.IntStream;

/**
 * @author 王杨帅
 * @create 2018-06-24 23:04
 * @desc 中间操作、终止操作、惰性求值
 **/
public class Case01 {

    private int [] nums;
    private int count = 5;
    private Random random;

    @Before
    public void init() {
        random = new Random();
        nums = new int[count];
        for (int i = 0; i < nums.length; i++) {
            nums[i] = random.nextInt(30);
        }
    }

    /**
     * 惰性求值
     */
    @Test
    public void test01() {
        System.out.println("老的数组为:" + Arrays.toString(nums));
//        IntStream.of(nums).map(Case01::addFive); // 没有终止操作,map操作不会执行
        IntStream.of(nums).map(Case01::addFive).sum(); // 有中间操作,map操作会执行
    }

    public static Integer addFive(Integer num) {
        System.out.println("中间操作执行了");
        return num + 5;
    }

}
View Code

 

5 创建流

  5.1 创建流的方式

    

  5.2 代码体验

package demo03_create_stream;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author 王杨帅
 * @create 2018-06-25 6:57
 * @desc 创建流的方法
 **/
public class Case01 {

    /**
     * 根据集合创建流
     */
    @Test
    public void test01() {
        List<Integer> integerList = new ArrayList<>();
        integerList.add(1);
        integerList.add(2);
        integerList.add(3);

        /**
         * 根据集合创建流的两种方式
         */
        integerList.stream();
        integerList.parallelStream();
    }

    /**
     * 根据数组创建流
     */
    @Test
    public void test02() {
        int [] nums = {1,2,3,4};

        Arrays.stream(nums);
    }

    /**
     * 创建数字流
     */
    @Test
    public void test03() {
        IntStream.of(1, 2, 3);

        int [] nums = {4, 5, 6};
        IntStream.of(nums);

        IntStream.range(1, 10);

        IntStream.rangeClosed(1, 10);
    }

    /**
     * 利用Random实例创建无限流
     *      limit的作用是限制个数,避免创建无限流
     */
    @Test
    public void test04() {
        new Random().ints().limit(10);
    }

    /**
     * 自己产生流
     */
    @Test
    public void test05() {
        Random random = new Random();
        Stream.generate(() -> random.nextInt()).limit(20);
    }

}
View Code

 

6 并行流

  就是并行的操作流

package demo05_webflux.chapter03;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @author 王杨帅
 * @create 2018-07-31 9:48
 * @desc 并行操作
 **/
public class Case04StreamDemo04 {

    public static void main(String[] args) {

        // 01 串行操作
//        IntStream.range(1, 100)
//                .peek(Case04StreamDemo04 :: debug)
//                .count();

        // 02 并行操作
//        IntStream.range(1, 100)
//                .parallel()
//                .peek(Case04StreamDemo04 :: debug)
//                .count();

        // 03 先并行再串行
        /**
         * 结论:多次调用串行和并行后,以最后一次为准
         */
//        IntStream.range(1, 100)
//                .parallel()
//                .peek(Case04StreamDemo04 :: debug)
//                .sequential()
//                .peek(Case04StreamDemo04 :: debug02)
//                .count();

//        IntStream.range(1, 100)
//                .sequential()
//                .peek(Case04StreamDemo04 :: debug)
//                .parallel()
//                .peek(Case04StreamDemo04 :: debug02)
//                .count();

        // 04 并行操作时打印线程信息
        /**
         * 结论:
         *      并行流使用的线程池是 ForkJoinPool.commonPool【JDK自带的】;
         *      默认的线程数时物理机器中cpu个的数量
         *      可以通过java.util.concurrent.ForkJoinPool.common.parallelism属性
         *   来修改默认的线程数
         *
         *
         */
//        System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");
//        IntStream.range(1, 100)
//                .parallel()
//                .peek(Case04StreamDemo04::debug03)
//                .count();

        // 05 使用自己的线程池进行并行操作
        /**
         * note:
         *      1 不使用默认的线程池,是为了防止阻塞
         *      2 线程池名字是:ForkJoinPool-1
         */
        ForkJoinPool pool = new ForkJoinPool(20);
        pool.submit(() -> IntStream.range(1, 100)
                                    .parallel()
                                    .peek(Case04StreamDemo04 :: debug03)
                                    .count()
                    );
        pool.shutdown(); // 关闭线程池

        synchronized (pool) {
            try {
                pool.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public static void debug(Integer i) {

        System.out.println("Debug" + i);

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public static void debug02(Integer i) {

        System.err.println("Debug" + i);

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public static void debug03(Integer i) {
        System.out.println(Thread.currentThread().getName() + "-Debug-" + i);
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
View Code

 

package demo04_parallel_stream;

import demo02_operation.Case02;
import org.junit.Test;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @author 王杨帅
 * @create 2018-06-25 21:59
 * @desc
 **/
public class Case01 {

    /**
     * 串行操作流
     */
    @Test
    public void test01() {
        IntStream.range(1, 100).peek(Case01::debug).count();
    }

    /**
     * 并行操作流
     *    技巧01:并行的数量默认是物理即CPU的数量
     */
    @Test
    public void test02() {
        IntStream.range(1, 100).parallel().peek(Case01::debug).count();
    }

    /**
     * 多次调用parallel和sequential,以最后一次为准
     */
    @Test
    public void test03() {
        IntStream.range(1, 100)
                .parallel().peek(Case01::debug)
                .sequential().peek(Case01::debug2)
                .count();
    }

    /**
     * 并行流默认的线程池:ForkJoinPool.commonPool
     *      技巧01:线程池默认的线程数量是物理机器的cpu个数
     */
    @Test
    public void test04() {
        IntStream.range(1, 100)
                .parallel().peek(Case01::debug3)
                .count();
    }

    /**
     * 修改默认的线程数量
     */
    @Test
    public void test05() {
        // 修改并行操作时系统默认的线程数量
        System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");

        IntStream.range(1, 100)
                .parallel().peek(Case01::debug)
                .count();
    }

    /**
     * 使用自己的线程池进行并行操作,不使用默认的线程池;目的是为了防止任务被阻塞
     *      技巧01:自己创建的线程池使用的是 ForkJoinPool
     */
    @Test
    public void test06() {
        // 创建一个拥有10个线程的线程池
        ForkJoinPool forkJoinPool = new ForkJoinPool(10);

        // 将并行操作放到线程池中
        forkJoinPool.submit(() -> IntStream.range(1, 100)
                                    .parallel().peek(Case01::debug3)
                                    .count());
        // 并行操作完成后关闭线程池
        forkJoinPool.shutdown();

        // 让主线程等待一下
        synchronized (forkJoinPool) {
            try {
                forkJoinPool.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }



    public static void debug(int i) {
        System.out.println("debug " + i);
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void debug2(int i) {
        System.err.println("debug2 " + i);
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void debug3(int i) {
        System.out.println(Thread.currentThread().getName() + " debug3 " + i);
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
View Code

 

7 收集器

  7.1 准备

  

package demo05_webflux.chapter03;

/**
 * @author 王杨帅
 * @create 2018-08-01 9:42
 * @desc 学生实体类
 **/
public class Student {
    private String name;
    private Integer age;
    private Gender gender;
    private Grade grade;

    public Student(String name, Integer age, Gender gender, Grade grade) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.grade = grade;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }

    public Grade getGrade() {
        return grade;
    }

    public void setGrade(Grade grade) {
        this.grade = grade;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                ", grade=" + grade +
                '}';
    }
}
Student.java
package demo05_webflux.chapter03;

/**
 * @author 王杨帅
 * @create 2018-08-01 9:44
 * @desc 性别枚举
 **/
public enum Gender {
    MALE,
    FEMALE;
}
Gender.java
package demo05_webflux.chapter03;

/**
 * @author 王杨帅
 * @create 2018-08-01 9:45
 * @desc 班级枚举
 **/
public enum Grade {
    ONE,
    TWO,
    THREE,
    FOUR,
    FIVE;
}
Grade.java
package demo05_webflux.chapter03;

import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 王杨帅
 * @create 2018-08-01 9:41
 * @desc 搜集器
 **/
public class Case05StreamDemo05 {

    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
                new Student("fury", 1, Gender.MALE, Grade.ONE),
                new Student("fury01", 2, Gender.MALE, Grade.THREE),
                new Student("fury02", 3, Gender.FEMALE, Grade.ONE),
                new Student("fury03", 4, Gender.MALE, Grade.FOUR),
                new Student("fury04", 5, Gender.FEMALE, Grade.ONE),
                new Student("fury05", 6, Gender.MALE, Grade.ONE),
                new Student("fury06", 7, Gender.FEMALE, Grade.TWO),
                new Student("fury07", 8, Gender.MALE, Grade.ONE),
                new Student("fury08", 9, Gender.FEMALE, Grade.THREE),
                new Student("fury09", 10, Gender.MALE, Grade.ONE)
        );

        /**
         * Notes:
         *      1 多使用方法引用来代替lambda表达式,这样可以少生成一个lambda$0这样的函数
         */
        List<Integer> ageList = students.stream()
                                    .map(Student :: getAge)
                                    .collect(Collectors.toList());
        System.out.println("所有学生的年龄为:" + ageList);

        // 02 信息汇总、
        IntSummaryStatistics agesSummaryStatistics =
                students.stream().collect(Collectors.summarizingInt(Student :: getAge));
        System.out.println(agesSummaryStatistics);

        // 03 分块【就是一个只有两个组的特殊分组】
        Map<Boolean, List<Student>> genderCollect = students.stream().collect(Collectors.partitioningBy(s -> s.getGender() == Gender.MALE));
        System.out.println("男女学生分别为:" + genderCollect);

        // 04 分组
        Map<Grade, List<Student>> gradeGroup = students.stream()
                .collect(Collectors.groupingBy(Student::getGrade));
        System.out.println("班级分组为:" + gradeGroup);

        Map<Grade, Long> collect = students.stream()
                .collect(Collectors.groupingBy(Student::getGrade, Collectors.counting()));
        System.out.println("各个班级的学生个数为:" + collect);

    }

}
View Code

 

package demo05_collector;

import com.sun.org.apache.xpath.internal.operations.Bool;
import org.apache.commons.collections4.MapUtils;
import org.junit.Before;
import org.junit.Test;

import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 王杨帅
 * @create 2018-06-25 22:51
 * @desc
 **/
public class Case01 {

    private List<Student> students;

    @Before
    public void init() {
        students = Arrays.asList(
                new Student("fury", 1, Gender.MALE, Grage.ONE),
                new Student("fury01", 2, Gender.MALE, Grage.THREE),
                new Student("fury02", 3, Gender.FEMALE, Grage.ONE),
                new Student("fury03", 4, Gender.MALE, Grage.FOUR),
                new Student("fury04", 5, Gender.FEMALE, Grage.ONE),
                new Student("fury05", 6, Gender.MALE, Grage.ONE),
                new Student("fury06", 7, Gender.FEMALE, Grage.TWO),
                new Student("fury07", 8, Gender.MALE, Grage.ONE),
                new Student("fury08", 9, Gender.FEMALE, Grage.THREE),
                new Student("fury09", 10, Gender.MALE, Grage.ONE)
        );
    }

    /**
     * 所有学生的年龄列表
     *      技巧:lambda表达式能用引用就尽量用引用,少用箭头函数;这样就不会多生成一个类似lambda$0这样的函数【参见lambda底层】
     */
    @Test
    public void test01() {
//        System.out.println(students);
        List<Integer> ageList = students.stream()
                .map(Student::getAge)
//                .collect(Collectors.toList());
                .collect(Collectors.toCollection(ArrayList::new));

        System.out.println("所有学生的年龄集合为:" + ageList);
    }

    /**
     * 统计
     */
    @Test
    public void test02() {
        IntSummaryStatistics summaryStatistics =  students.stream().collect(Collectors.summarizingInt(Student::getAge));

        System.out.println("年龄汇总信息:" + summaryStatistics);
    }

    /**
     * 分块
     */
    @Test
    public void test03() {
        Map<Boolean, List<Student>> map = students.stream().collect(Collectors.partitioningBy(s -> s.getGender() == Gender.MALE));

        MapUtils.verbosePrint(System.out, "男女学生列表为:", map);
    }

    /**
     * 分组
     */
    @Test
    public void test04() {
        Map<Grage, List<Student>> map = students.stream().collect(Collectors.groupingBy(Student::getGrage));

        MapUtils.verbosePrint(System.out, "学生班级列表为:", map);
    }

    /**
     * 分组下级操作
     */
    @Test
    public void test05() {
        Map<Grage, Long> map = students.stream().collect(Collectors.groupingBy(Student::getGrage, Collectors.counting()));

        MapUtils.verbosePrint(System.out, "班级学生数量列表为:", map);
    }

}
View Code

 

8 stream运行机制

 

  

package demo06_stream_run;

import org.junit.Test;

import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

/**
 * @author 王杨帅
 * @create 2018-06-26 6:38
 * @desc
 **/
public class Case01 {

    /**
     * Notes:
     *  1 所有操作都是链式操作,一个元素只迭代一次
     *  2 每一个中间操作都返回一个新的流
     *      流里面有一个属性叫sourceStage,它都指向同一个地方就是这个流的Head
     *      Head -> nextStage -> nextStage -> ... -> null
     */
    @Test
    public void test01() {
        Random random = new Random();
        Stream<Integer> stream = Stream.generate(() -> random.nextInt()) // 产生流
                // 短路操作
                .limit(500)
                // 中间操作(无状态)
                .peek(s -> System.out.println("peek: " + s))
                // 中间操作(无状态)
                .filter(s -> {
                    System.out.println("filter: " + s);
                    return s > 1000000;
                });

        // 终止操作
        stream.count();
    }

    /**
     * Notes:
     *  3 有状态操作会将无状态操作截断,单独处理
     */
    @Test
    public void test02() {
        Random random = new Random();
        Stream<Integer> stream = Stream.generate(() -> random.nextInt()) // 产生流
                // 短路操作
                .limit(500)
                // 中间操作(无状态)
                .peek(s -> System.out.println("peek: " + s))
                // 中间操作(无状态)
                .filter(s -> {
                    System.out.println("filter: " + s);
                    return s > 1000000;
                })
                // 中间操作(有状态)
                .sorted((i1, i2) -> {
                    System.out.println("排序:" + i1 + "," + i2);
                    return i1.compareTo(i2);
                })
                // 中间操作(无状态)
                .peek(s -> System.out.println("peek2: " + s));

        // 终止操作
        stream.count();
    }

    /**
     * Notes:
     *  4 并行环境下,有状态的并行操作不一定能并行操作
     *  5 parallel和sequetial者两个操作也是中间操作(也是返回流)
     *        注意:他们不创建流,他们只修改Head的并行标志
     */
    @Test
    public void test03() {
        Random random = new Random();
        Stream<Integer> stream = Stream.generate(() -> random.nextInt()) // 产生流
                // 短路操作
                .limit(500)
                // 中间操作(无状态)
                .peek(s -> print("peek: " + s))
                // 中间操作(无状态)
                .filter(s -> {
                    print("filter: " + s);
                    return s > 1000000;
                })
                // 中间操作(有状态) 【并行环境下时不能进行并行操作】
                .sorted((i1, i2) -> {
                    print("排序:" + i1 + "," + i2);
                    return i1.compareTo(i2);
                })
                // 中间操作(无状态)
                .peek(s -> print("peek2: " + s))
                .parallel();

        // 终止操作
        stream.count();
    }

    public void print(String s) {
        System.out.println(Thread.currentThread().getName() + " -> " + s);
//        try {
//            TimeUnit.SECONDS.sleep(1);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
    }

}
View Code

   8.1 链式调用

    所有的操作都是链式调用,每个操作只会对每个元素操作一次;

    每个中间操作都会返回一个新的流,每个流里面都会有一个SourceStage属性,所有流的SourceStage属性都指向同一个地方【就是原始流的头部】;

    如果一个中间操作之后还有中间操作,那么这个中间操作对应的流中nextStage属性就会执行下一个中间操作对应的流,否则就是null

    技巧01:返回一个流的操作都叫作中间操作【原始流也看作是一个中间操作??】

package demo05_webflux.chapter03;

import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author 王杨帅
 * @create 2018-08-01 10:58
 * @desc Stream的运行机制
 **/
public class Case06StreamDemo06 {

    public static void main(String[] args) {

        Stream<Integer> integerStream = Stream.generate(() -> new Random().nextInt())
                .limit(500)
                .peek(s -> System.out.println("peek:" + s))
                .filter(s1 -> {
                    System.out.println("filter:" + s1);
                    return s1 > 100;
                });

        integerStream.count();
    }

}
View Code

  8.2 有状态操作对无状态操作的影响

    技巧01:如果所有操作都是无状态操作,那么都是链式调用的;但是如果在无状态操作之间添加了有状态操作,那么有状态操作会将链式操作截成两部分,那两部分分别进行链式操作

    例如:无状态操作A -> 无状态操作B ->  无状态操作C -> 无状态操作D

      这种情况下所有的操作都是链式的

    例如:无状态操作A -> 无状态操作B ->  无状态操作Y -> ->  无状态操作C -> 无状态操作D

      Y会将之前的链式操作截成两个链式操作,Y之前的A、B操作是基于原始流进行链式操作,Y之后的C、D操作是基于Y产生的流进行的链式操作

package demo05_webflux.chapter03;

import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author 王杨帅
 * @create 2018-08-01 10:58
 * @desc Stream的运行机制
 **/
public class Case06StreamDemo06 {

    public static void main(String[] args) {

        Stream<Integer> integerStream = Stream.generate(() -> new Random().nextInt())
                .limit(10)
                .peek(s -> System.out.println("peek:" + s))
                .filter(s1 -> {
                    System.out.println("filter:" + s1);
                    return s1 == s1;
                })
                .sorted((s1, s2) -> {
                    System.out.println("排序:" + s1 + "," + s2);
                    return s1.compareTo(s2);
                })
                .peek(s -> System.out.println("peek02-:" + s))
                ;

        integerStream.count();
    }

}
View Code

   8.3 并行操作对有状态的中间操作的影响

    有状态的中间操作并不一定可以进行并行操作

package demo05_webflux.chapter03;

import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author 王杨帅
 * @create 2018-08-01 10:58
 * @desc Stream的运行机制
 **/
public class Case06StreamDemo06 {

    public static void main(String[] args) {

        Stream<Integer> integerStream = Stream.generate(() -> new Random().nextInt())
                .limit(500)
                .peek(s -> print("peek:" + s))
                .filter(s1 -> {
                    print("filter:" + s1);
                    return s1 == s1;
                })
                .sorted((s1, s2) -> {
                    print("排序:" + s1 + "," + s2);
                    return s1.compareTo(s2);
                })
                .peek(s -> print("peek02-:" + s))
                .parallel()
                ;

        integerStream.count();
    }

    public static void print(String s) {
        System.out.println(Thread.currentThread().getName() + "-" + s);
    }

}
View Code

  8.4 特殊的中间操作

    parallel和sequetial这两个操作也是中间操作(返回的也是stream);

    但是他们不创建流,只是改变流中 sourceStage 中的 parallel 属性而已(并行时为true,串行时为false【默认为false】)

9 stream小结

  

 

    

 

posted @ 2018-06-24 23:20  寻渝记  阅读(910)  评论(0编辑  收藏  举报