Java8新特性之Stream 入门级

Java 8为我们带来了许多提高生产力的新玩意 这次来研究一下流 Stream的具体用法。
我们先看看比较官方的说法:

  • 流使用一种类似sql语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象
  • Stream API可以极大提高我们的生产力,让我们写出高效简洁的代码
  • Stream将要处理的集合看做一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果

当然 我一开始看到这些概念 也是比较懵的 但是别慌 我们一起来看看一些小demo 结合着理解一下
首先我们来看看一些基础的概念:

什么是流?

Stream(流)是一个来自数据源的元素队列并支持聚合操作的对象。
流跟我们以前对集合进行操作有两个比较特殊的特征:
一是Pipelining,顾名思义是管道化,中间操作都会返回流对象本身,这样的好处在于多个操作可以串联成一个管道,如同流式风格(fluent style),这样做可以对操作进行优化,比如延迟执行(laziness)和短路(short-circuiting)
二是内部迭代,以前对集合遍历都是通过在外部使用Iterator或者for-each的方式,在集合外部进行迭代,这叫做外部迭代,Stream提供了内部迭代的方式,通过访问者模式Visitor)实现。

生成流的两种方法

  • stream() 为集合创建串行流
  • parallelStream() 为集合创建并行流
两种流的效率比较

由这两种流的名称我们就可得知,parallelStream是并行流,在运行过程中,数据会被分为多个段,进行多线程的运行,最后将结果一起输出,而普通串行遍历时,只能一个item运行后再读下一个item,因此并行流肯定是比串行流要快的。
在这个demo中,我们先循环生成一个100000大小的ArrayList,然后再通过Stream API对每个值做覆盖处理,当然,前后需要分别使用stream和parallelStream并进行对比。
前者是使用stream,后者是使用parallelStream,可以看到还是有较大区别的。

List<Integer> list=new ArrayList<>();
long startTime=System.currentTimeMillis();
for(int i=0;i<100000000;i++){
    
    
    list.add(i);
}
list.stream().forEach(element->{
    
    
    int k=50;
    list.set(element,k);
});
long endTime=System.currentTimeMillis();
System.out.println("运行时间为:"+(endTime-startTime));

使用Stream
使用parallelStream()

使用并行流的注意事项

注意,ParallelStream并不是线程安全的,我们需要加锁、使用线程安全的集合或者采用collect()或者reduce()操作来保证线程安全。
另外,在使用并行流的过程中,还需要注意以下几点:

  1. 不要在多线程中使用parallelStream,原因同上类似,大家都抢着CPU是没有提升效果,反而还会加大线程切换开销
  2. parallelStream是创建一个并行的Stream,而且它的并行操作是不具备线程传播性的,所以是无法获取ThreadLocal创建的线程变量的值
  3. 在使用并行流的时候是无法保证元素的顺序的,也就是即使你用了同步集合也只能保证元素都正确但无法保证其中的顺序
    要注意并行和并发的区别,以及使用场景。

常用Stream方法

filter

filter一般用来过滤一些集合中特定的元素,通过具体设置的条件。

List<String> strings= Arrays.asList("sdiw","","dsdw","csd","cd");
        List<String> filterNull = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
        long count=strings.stream().filter(string -> string.isEmpty()).count();
        System.out.println("原本集合"+strings.toString());
        System.out.println("过滤空值"+filterNull.toString());
        System.out.println("空值数目"+count);

在这里插入图片描述

forEach

Stream 提供了新的方法 ‘forEach’ 来迭代流中的每个数据

Random random=new Random();
random.ints().limit(10).forEach(System.out::println);

在这里插入图片描述

map

map 方法用于映射每个元素到对应的结果,这里的i代表numbers中每一个元素,而distinct表示去除重复。

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
System.out.println(squaresList.toString());

limit

limit 方法用于获取指定数量的流,代码中的双冒号是java 8之后lambda的一种写法,可以看做是方法引用,提供的是不执行方法的方法,比如我们可以将person->person.getAge()替换为Person::getAge

Random random=new Random();
random.ints().limit(10).forEach(System.out::println);

在这里插入图片描述

sorted

这里可以看到排序只是在forEach之前调用一个sorted就可以达到排序的效果,这也照应了Stream的第一个特性,多个操作可以串联成一个管道,而在管道之中,你也可以加入不同的操作来达到想要的效果。

Random random=new Random();
random.ints().limit(10).sorted().forEach(System.out::println);

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/fucccck_ly/article/details/107692330