SpringBoot2.0不容错过的新特性 WebFlux响应式编程【第3章】Stream流编程

3-1 Stream流编程-概念

Stream是一个高级迭代器,不是数据结构,不是集合,不会存放数据,它关注的是怎么把数据高效的处理。

外部迭代和内部迭代

外部迭代:for 、while

int [] nums = {3,7,4};
        
int sum = 0;
//外部迭代
for (int num : nums) {
    sum += num;
}
System.out.println("sum = " +sum);

内部迭代

int intStream = IntStream.of(nums).sum();

System.out.println("sum = " + intStream);

中间操作/最终操作和惰性求值

//map是中间操作(返回Stream的操作)
//sum是终止操作
int mult =IntStream.of(nums).map(n -> n*2).sum();
System.out.println("multiplication = " +mult);

上面的代码也可以写为:

public static void main(String[] args) {
    int mult =IntStream.of(nums).map(StreamDemo3_1::multiplication).sum();
    System.out.println("multiplication = " +mult);
}
public static int multiplication(int n){
    return n*2;
}

惰性求值就是中间值没用调用的情况下,中间操作不会执行。

IntStream.of(nums).map(StreamDemo3_1::multiplication);

以上程序没有终止操作,中间操作map不会被调用。

3-2 流的创建

相关方法
集合Collection.stream/parallelStream
数组Arrays.stream
数字StreamIntStream/LongStream.range/rangeClosed
数字StreamRandom.ints/longs/soubles
自己创建Stream.generate/iterate
//从集合中创建流
List<String> list = new ArrayList<>();
list.add("hello");
list.add("my");
list.add("world");
list =list.stream().map( String::toUpperCase).collect(Collectors.toList());

for (String str: list) {
    System.out.println(str);
}

//从数组中创建
Arrays.stream(new int []{6,4,5}).sorted().forEach(System.out::println);

//数字Stream
IntStream.of(8,3,5).map(n -> 4*n).sorted().forEach(System.out::println);

//自己产生(无限)流(用limit来限制)
Stream.generate(()-> new Random().nextInt()).limit(10);

3-3 流的中间操作

中间操作分为:

  • 无状态操作:当前的操作和其它元素的前后没有关系。
  • 有状态操作:结果依赖其它元素。
相关方法
无状态操作map/mapToXXX
无状态操作flatMap/flatMapToXXX
无状态操作filter
无状态操作peek
无状态操作unordered
有状态操作distinct
有状态操作sorted
有状态操作limit/skip
  • mapA对象转换成B对象。
  • mapToXXX将对象转换为数字,得到对象上的信息(字符串的长度)。
  • flatMap:A对象包含B属性,B属性是个集合,那么可以使用flatMap得到最终结果是:得到所偶A对象里面的所有B属性的列表。
  • peek的入参是消费者和终止操作里面的forEach很像,但是它是中间操作。
  • unordered并行流才会用到。
String str = "I'm ugly useless person.";
//输出每个单词的长度
Stream.of(str.split(" "))
        .map( x -> x.length())
        .forEach(System.out::println);

//flatMap A -> B属性(是个集合),最终得到所有A元素里面的所有B属性集合
//IntStream LongStream并不是Stream的子类,所以需要进行装箱boxed
Stream.of(str.split(" "))
        .flatMap( n -> n.chars().boxed())
        .forEach( n -> System.out.println((char)n.intValue()));

//peek用于debug,是个中间操作,forEach是终止操作
Stream.of(str.split(" "))
        .peek(System.out::println)
        .forEach(System.out::println);

//limit限制无限流
new Random()
        .ints()
        .filter(n -> n > 200 && n < 300)
        .limit(10)
        .forEach(System.out::println);
总结

intchar
Integerint

3-4 流的终止操作

相关方法
非短路操作forEach/forEachOrdered
collect/toArray
reduce
min/max/count
短路操作findFirst/findAny
allMatch/anyMatch/noneMatch

reduce:减少,将流合并成一个数据。
XXXOrdered:带Ordered都是和并行有关。
findAny:找到任何一个。

String str = "Let life be beautiful like summer flowers and death like autumn leaves.";

//使用并行流
str.chars().parallel().forEach(s -> System.out.print((char) s));
System.out.println();
//使用forEachOrdered保证顺序
str.chars().parallel().forEachOrdered(s -> System.out.print((char) s));

输出结果

ded  lkersweilehe loaau nlime b ln ulifattbeautr fikfeeumLe st s.umae v
Let life be beautiful like summer flowers and death like autumn leaves.

在并行时使用forEach会导致乱序。

//收集到List
List<String> stringList= Stream.of(str.split(" ")).collect(Collectors.toList());

Optional<String> stringOptional =Stream.of(str.split(" ")).reduce((s1, s2) -> s1 +"|" +s2);
//orElse:如果获取不到则取空
System.out.println(stringOptional.orElse(""));

//赋默认值
String string1 =Stream.of(str.split(" ")).reduce("",(s1, s2) -> s1 +"|" +s2);

System.out.println("串:" + string1);
//计算所有单词长度
int countLength =Stream.of(str.split(" ")).map(s -> s.length()).reduce(0,(n1,n2) -> n1 + n2);

System.out.println("计算所有单词长度" + countLength);

//max的使用
Optional<String> s = Stream.of(str.split(" ")).max((s1,s2) -> s1.length() - s2.length());

System.out.println(s.orElse(""));

3-5 并行流

parallel

IntStream.range(1,100).peek(StreamDemo3_5::debug).count();

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

输出结果

debug1
debug2
debug3
debug4

每隔三秒输出一个debugi

调用parallel产生并行流
IntStream.range(1,100).parallel().peek(StreamDemo3_5::debug).count();

输出结果

debug31
debug28
debug7
debug34
debug43
debug16
debug65
debug40

每隔三秒输出八个debugi

先并行后串行处理
IntStream.range(1,100)
         //调用parallel产生并行流
        .parallel()
        .peek(StreamDemo3_5::debug)
        //调用sequential产生串行流
        .sequential()
        .peek(StreamDemo3_5::debug)
        .count();

输出结果

debug1
debug1
debug2
debug2
debug3
debug3

每隔三秒输出一个debugi,以上一共用了18s
多次调用parallel/sequential,以最后一次调用为准

并行流使用的线程池:ForkJoinPool.commonPool


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

public static void debug(int i){
    System.out.println("current thread name = ["+ Thread.currentThread().getName()+"]debug" + i);
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

输出结果

current thread name = [ForkJoinPool.commonPool-worker-7]debug87
current thread name = [ForkJoinPool.commonPool-worker-3]debug81
current thread name = [main]debug65
current thread name = [ForkJoinPool.commonPool-worker-1]debug90
current thread name = [ForkJoinPool.commonPool-worker-6]debug78
current thread name = [ForkJoinPool.commonPool-worker-5]debug96
current thread name = [ForkJoinPool.commonPool-worker-4]debug16
current thread name = [ForkJoinPool.commonPool-worker-2]debug31

默认的线程数是当前CPU个数

修改默认的线程数

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism","20");

所有的并行流都使用同一个默认的线程池,就会有阻塞问题,所以要使用自己的线程池

//使用自己的线程池,不使用默认线程池,防止任务被阻塞
ForkJoinPool pool = new ForkJoinPool(10);
pool.submit(() -> IntStream.range(1,100).parallel()
        .peek(StreamDemo3_5::debug).count());
pool.shutdown();

输出结果


主函数已经退出,由于当前线程是守护线程,所以也自动退出了

//使用自己的线程池,不使用默认线程池,防止任务被阻塞
ForkJoinPool pool = new ForkJoinPool(10);
pool.submit(() -> IntStream.range(1,100).parallel()
        .peek(StreamDemo3_5::debug).count());
pool.shutdown();
//不要让主线程退出,让主线程等待
synchronized (pool){
    try {
        pool.wait(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

输出结果

current thread name = [ForkJoinPool-1-worker-4]debug16
current thread name = [ForkJoinPool-1-worker-15]debug56
current thread name = [ForkJoinPool-1-worker-8]debug7
current thread name = [ForkJoinPool-1-worker-13]debug43
current thread name = [ForkJoinPool-1-worker-1]debug28
current thread name = [ForkJoinPool-1-worker-9]debug65
current thread name = [ForkJoinPool-1-worker-6]debug81
current thread name = [ForkJoinPool-1-worker-2]debug31
current thread name = [ForkJoinPool-1-worker-10]debug40
current thread name = [ForkJoinPool-1-worker-11]debug90

3-6 收集器

Employee.java

public class Employee {

    private String name;

    private int age;

    private String gender;

    private String department;

    //工作时间(年)
    private int dueTime;

    public Employee() {
    }

    public Employee(String name, int age, String gender, String department, int dueTime) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.department = department;
        this.dueTime = dueTime;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public String getGender() {
        return gender;
    }

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

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public int getDueTime() {
        return dueTime;
    }

    public void setDueTime(int dueTime) {
        this.dueTime = dueTime;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", department='" + department + '\'' +
                ", dueTime=" + dueTime +
                '}';
    }
}

收集器功能演示

List<Employee> employeeList = new ArrayList<>();

employeeList.add(new Employee("王晓红", 28, "女","前端",10));
employeeList.add(new Employee("韩晨旭", 64, "女","前端",40));
employeeList.add(new Employee("蔡觅风", 33, "女","前端",13));
employeeList.add(new Employee("杨和顺", 33, "男","前端",11));

employeeList.add(new Employee("鱼思博", 26, "男","JAVA开发",5));
employeeList.add(new Employee("孙艺珍", 18, "女","JAVA开发",1));
employeeList.add(new Employee("刘诗诗", 19, "女","JAVA开发",2));
employeeList.add(new Employee("倪妮", 21, "女","JAVA开发",4));
employeeList.add(new Employee("杨幂", 23, "女","JAVA开发",6));

employeeList.add(new Employee("罗玉凤", 45, "女","PHP开发",25));
employeeList.add(new Employee("史恒侠", 52, "女","PHP开发",30));
employeeList.add(new Employee("王诗锦", 36, "女","PHP开发",10));
employeeList.add(new Employee("鲁塞", 36, "男","PHP开发",8));

//获取所有人的工作年限
employeeList.stream()
        .map(Employee::getDueTime)
        .collect(Collectors.toList())
        .forEach(System.out::println);

//分块(男女分块)
Map<Boolean, List<Employee>> collect = employeeList.stream()
        .collect(Collectors.partitioningBy(s -> "男".equals(s.getGender())));
System.out.println(collect);

//统计信息(年龄)
IntSummaryStatistics collect1 = employeeList.stream()
        .collect(Collectors.summarizingInt(Employee::getAge));
System.out.println(collect1);

//按部门分组
Map<String, List<Employee>> collect2 = employeeList.stream()
        .collect(Collectors.groupingBy(Employee::getDepartment));
System.out.println(collect2);

//每个部门的人员数
Map<String,Long> departInfo = employeeList.stream()
        .collect(Collectors.groupingBy(Employee::getDepartment,Collectors.counting()));

System.out.println(departInfo);

System.out.println("==========每个部门工作年限大于5年的人员==============");
//每个部门工作年限大于5年的人员
Map<String,Long> departInfo2 = employeeList.stream()
        .filter(x -> x.getDueTime() >= 5)
        .collect(Collectors.groupingBy(Employee::getDepartment,Collectors.counting()));

System.out.println(departInfo2);

3-7 Stream运行机制

public static void main(String[] args) {

    Random random = new Random();

    Stream.generate(() ->random.nextInt())
            //随机产生1000个,无限流需要短路操作
            .limit(10)
            //第一个无状态操作
            .peek( s-> print("peek "+ s))
            //第二个无状态操作
            .filter(x-> {
                print("filter "+ x);
                return x > 1000;
            })
            //终止操作
            .count();
}

private static void print(String s) {
    System.out.println("Current thread name is [" + Thread.currentThread().getName() +"]" +s);
}

输出结果

Current thread name is [main]peek -1481969448
Current thread name is [main]filter -1481969448
Current thread name is [main]peek 1751174304
Current thread name is [main]filter 1751174304
Current thread name is [main]peek -407154946
Current thread name is [main]filter -407154946
Current thread name is [main]peek -1668783575
Current thread name is [main]filter -1668783575
Current thread name is [main]peek -377677467
Current thread name is [main]filter -377677467
Current thread name is [main]peek 171132531
Current thread name is [main]filter 171132531
Current thread name is [main]peek 440439267
Current thread name is [main]filter 440439267
Current thread name is [main]peek -1525975399
Current thread name is [main]filter -1525975399
Current thread name is [main]peek -598675908
Current thread name is [main]filter -598675908
Current thread name is [main]peek 1409027428
Current thread name is [main]filter 1409027428
所有操作是链式调用,一个元素值迭代一次

在这里插入图片描述

每一个中间操作返回一个新的流,流里面有一个属性sourceStage指向同一个地方,就是链表的头Head

在这里插入图片描述

Head -> nextStage -> nextStage ···->null
Random random = new Random();

Stream stream = Stream.generate(() ->random.nextInt())
        //随机产生1000个,无限流需要短路操作
        .limit(10)
        //第一个无状态操作
        .peek( s-> print("peek "+ s))
        //第二个无状态操作
        .filter(x-> {
            print("filter "+ x);
            return x > 1000;
        })
        //有状态操作
        .sorted((x,x2) ->{
            print("sorted "+ x + " \t" +x2);
            return x.compareTo(x2);

        }).peek(s-> print("peek2 "+ s));
        //终止操作
        stream.count();

输出结果

Current thread name is [main]peek -1219493409
Current thread name is [main]filter -1219493409
Current thread name is [main]peek 129329340
Current thread name is [main]filter 129329340
Current thread name is [main]peek 291924908
Current thread name is [main]filter 291924908
Current thread name is [main]peek -1311720116
Current thread name is [main]filter -1311720116
Current thread name is [main]peek 467565180
Current thread name is [main]filter 467565180
Current thread name is [main]peek -260908389
Current thread name is [main]filter -260908389
Current thread name is [main]peek -866398431
Current thread name is [main]filter -866398431
Current thread name is [main]peek 1719204022
Current thread name is [main]filter 1719204022
Current thread name is [main]peek -964722788
Current thread name is [main]filter -964722788
Current thread name is [main]peek -889925863
Current thread name is [main]filter -889925863
Current thread name is [main]sorted 291924908 	129329340
Current thread name is [main]sorted 467565180 	291924908
Current thread name is [main]sorted 1719204022 	467565180
Current thread name is [main]peek2 129329340
Current thread name is [main]peek2 291924908
Current thread name is [main]peek2 467565180
Current thread name is [main]peek2 1719204022
有状态操作会把无状态操作截断,单独处理。
Random random = new Random();

Stream stream = Stream.generate(() ->random.nextInt())
        //随机产生1000个,无限流需要短路操作
        .limit(10)
        //第一个无状态操作
        .peek( s-> print("peek "+ s))
        //第二个无状态操作
        .filter(x-> {
            print("filter "+ x);
            return x > 1000;
        })
        //有状态操作
        .sorted((x,x2) ->{
            print("sorted "+ x + " \t" +x2);
            return x.compareTo(x2);

        }).peek(s-> print("peek2 "+ s))
        .parallel();
        //终止操作
        stream.count();

输出结果

Current thread name is [ForkJoinPool.commonPool-worker-4]peek 974711749
Current thread name is [ForkJoinPool.commonPool-worker-4]filter 974711749
Current thread name is [ForkJoinPool.commonPool-worker-4]peek -481309025
Current thread name is [ForkJoinPool.commonPool-worker-4]filter -481309025
Current thread name is [ForkJoinPool.commonPool-worker-4]peek -1304435164
Current thread name is [ForkJoinPool.commonPool-worker-4]filter -1304435164
Current thread name is [ForkJoinPool.commonPool-worker-4]peek 428794899
Current thread name is [ForkJoinPool.commonPool-worker-4]filter 428794899
Current thread name is [ForkJoinPool.commonPool-worker-4]peek 710600140
Current thread name is [ForkJoinPool.commonPool-worker-4]filter 710600140
Current thread name is [ForkJoinPool.commonPool-worker-4]peek 502505696
Current thread name is [ForkJoinPool.commonPool-worker-4]filter 502505696
Current thread name is [ForkJoinPool.commonPool-worker-4]peek 2059903126
Current thread name is [ForkJoinPool.commonPool-worker-4]filter 2059903126
Current thread name is [ForkJoinPool.commonPool-worker-4]peek -751936808
Current thread name is [ForkJoinPool.commonPool-worker-4]filter -751936808
Current thread name is [ForkJoinPool.commonPool-worker-4]peek -142914388
Current thread name is [ForkJoinPool.commonPool-worker-4]filter -142914388
Current thread name is [ForkJoinPool.commonPool-worker-4]peek -1798349696
Current thread name is [ForkJoinPool.commonPool-worker-4]filter -1798349696
Current thread name is [main]sorted 428794899 	974711749
Current thread name is [main]sorted 710600140 	428794899
Current thread name is [main]sorted 710600140 	974711749
Current thread name is [main]sorted 710600140 	428794899
Current thread name is [main]sorted 502505696 	710600140
Current thread name is [main]sorted 502505696 	428794899
Current thread name is [main]sorted 2059903126 	710600140
Current thread name is [main]sorted 2059903126 	974711749
Current thread name is [main]peek2 710600140
Current thread name is [ForkJoinPool.commonPool-worker-7]peek2 974711749
Current thread name is [ForkJoinPool.commonPool-worker-3]peek2 2059903126
Current thread name is [ForkJoinPool.commonPool-worker-6]peek2 428794899
Current thread name is [ForkJoinPool.commonPool-worker-2]peek2 502505696
并行环境下,有状态的中间值不一定能并行操作

在这里插入图片描述

parallel/sequentail是中间操作(返回Stream),但是他们不创建流,值修head的并行标志
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值