stream流

关于stream说了很多,这里简单做补充,中间操作、终止操作。没有调用终止操作的情况下,中间操作也不会执行,这也可以叫惰性求值。

关于流的常见创建有如下方法:

 方法
集合Collection.stream/parallelStream
数组Arrays.stream
纯数字流

IntStream/LongStream.range/rangeClosed

Random.ints/longs/doubles

自己创建Stream.generate/iterate

举个例子:

        List<String> list = new ArrayList<>();

        //从集合创建
        list.stream();
        list.parallelStream();

        //从数组创建
        Arrays.stream(new int[]{2,3,4});

        //创建数字流
        IntStream.of(1,2,3);
        //创建是1-10的流
        IntStream.rangeClosed(1 , 10);

        //random创建无限流,所以需要用limit做限制
        new Random().ints().limit(10);

        //自定义
        Random random = new Random();
        Stream.generate(() -> random.nextInt()).limit(20);

中间操作

 

相关方法

无状态操作

map / mapToXxx

flatMap / flatMapToXxx

filter

peek

unordered

有状态操作

distinct

sorted

limit / skip

无状态指当前操作跟其他元素的前后没有依赖关系。

有状态就是有关系。

关于flatMap,比如A元素下有B(是个集合)属性,最终得到所有A元素中的所有B属性

public class StreamDemo {
    public static void main(String[] args) {
        String str = "my name is haozirou";

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

        //flatMap
        Stream.of(str.split(" "))
                .flatMap(s -> s.chars().boxed())
                .forEach(c -> System.out.print((char)c.intValue() + " "));
    }
}

结果:


需要注意的是,如果不加boxed,会报错

这是因为intStream/longStream并不是Stream的子类,所以需要进行装箱boxed

源码:

终止操作

 方法
非短路操作

forEach / forEachOrdered

collect / toArray

reduce

min / max / count

短路操作

findFirst / findAny

allMatch / anyMatch / noneMatch

短路操作是指不需要等待这个流所有都操作完,只要满足条件就可以结束。

public class StreamDemo {
    public static void main(String[] args) {
        String str = "my name is haozirou";

        //并行流
        str.chars().parallel()
                .forEach(i -> System.out.print((char)i));
        System.out.println();
        str.chars().parallel()
                .forEachOrdered(i -> System.out.print((char)i));
    }
}

结果:

可以看出,并行的情况下,forEach并不能保证顺序。

reduce可以进行字符串拼接

public class StreamDemo {
    public static void main(String[] args) {
        String str = "my name is haozirou";
        Optional<String> reduce = Stream.of(str.split(" "))
                .reduce((s1, s2) -> s1 + "|" + s2);
        System.out.println(reduce.orElse(""));
    }
}

结果:

reduce还可以提供默认值,可以写成:

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

并行流和串行流

并行(parallel):

public class StreamDemo {
    public static void main(String[] args) {
        //调用parallel 产生一个并行流
        IntStream.range(1 , 100).parallel()
                .forEach(StreamDemo::debug);
    }
    public static void debug(int i){
        System.out.println(Thread.currentThread().getName() + ":debug" + i);
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

串行(sequential):

结果会一个一个打印

需要注意的是,如果多次调用并行和串行的情况下,会默认以最后一次调用为准。

从上面可以看到,并行流使用的线程池是:ForkJoinPool.commonPool,默认线程数和cup个数一样。如何修改默认线程数?

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

结果:

如何使用自己的线程池?

public class StreamDemo {
    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool(5);
        pool.submit(() -> IntStream.range(1 , 10).parallel()
                .forEach(StreamDemo::debug));
        pool.shutdown();
        synchronized (pool){
            try {
                pool.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void debug(int i){
        System.out.println(Thread.currentThread().getName() + ":debug" + i);
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

结果:

收集器

最常用的有

.collect(Collectors.toList());

如果想指定集合类型

.collect(Collectors.toCollection(TreeSet::new));

假如有一堆学生,需要得到学生的年龄汇总:

IntSummaryStatistics ages = students.stream()
        .collect(Collectors.summarizingInt(Student::getAge));
System.out.println("年龄汇总信息" + ages);

结果:

分块

Map<Boolean , List<Student>> genders = students.stream()
        .collect(Collectors.partitioningBy(s -> s.getGender() == Gender.MALE));
MapUtils.verbosePrint(System.out , "男女学生列表" , genders);

结果:

分组:

Map<Grade , List<Student> grades= students.stream()
        .collect(Collectors.groupingBy(Student::getGrade));
MapUtils.verbosePrint(System.out , "班级学生列表" , grades);

结果:

在分组基础上,获得所有班级学生的个数:

Map<Grade , Long> gradeCount= students.stream()
        .collect(Collectors.groupingBy(Student::getGrade , Collectors.counting()));
MapUtils.verbosePrint(System.out , "班级学生个数列表" , gradeCount);

结果:

运行机制

1.所有操作都是链式调用,一个元素只迭代一次。

2.每一个中间操作都会返回一个新的流。

3.无状态,有状态,无状态穿插的时候,先是前两个无状态和有状态交替执行,全部执行完以后,才会执行最后的无状态操作。也就是说有状态和之前全部执行完,才会继续往下进行。

4.并行环境下,有状态的中间操作不一定能并行。

5.并行和串行 也是中间操作(返回stream),但他们不创建流,只修改sourceStage中的parallel标志。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值