java 8新特性 stream流式编程

stream概要与使用场景

stream的概要

stream与InputStream和outputStream不同,是用于对集合迭代器的增强,使之能够完成更高效率的聚合操作(过滤,排序,统计分组),或者大批量的数据操作. 此外与stream与lambada表达式节后后编码效率大大提高,并且可读性更强

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

再学习stream之前,需要对Lambda表达式有一定的了解。

下面这个例子可以解释Stream可以做什么:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uDjczjF4-1599051678458)(/Users/faro_z/Library/Application Support/typora-user-images/image-20200902144322581.png)]

上面的例子中,获取一些带颜色塑料球作为数据源,首先过滤掉红色的、把它们融化成随机的三角形。再过滤器并删除小的三角形。最后计算出剩余图形的周长。

如上图,对于流的处理,主要有三种关键性操作:分别是流的创建、中间操作(intermediate operation)以及最终操作(terminal operation)。

用更简洁的话来说,就是将集合中的元素放在流水线上,并在每一步添加条件,筛选部分元素最后留下的就是你想要的元素。

stream的操作流程

对于流的处理,主要有三种关键性操作:分别是流的创建、中间操作(intermediate operation)以及最终操作(terminal operation)。

  • 流创建:就是stream()方法
  • 中间操作:筛选、排序这类操作
  • 最终操作:取出、打印这些操作

下面会对这三类操作做具体的介绍

管道源/流创建

将Collection切换为管道源很简单,调用stream

扫描二维码关注公众号,回复: 12960734 查看本文章
heros.stream();

但是数组没有stream方法,需要使用

Arrays.stream(hs);

或者

Stream.of(hs);

这里不要和I/O操作中的InputStream、OutputStream搞混了,两个不是同一个概念。

中间操作

每个中间操作,又会返回一个Stream,比如.filter()又返回一个Stream, 中间操作是“懒”操作,并不会真正进行遍历。
中间操作比较多,主要分两类
对元素进行筛选 和 转换为其他形式的流

对元素进行筛选:

filter 匹配
distinct 去除重复(根据equals判断) //注意:Object里的equals判断的是不是同一个对象,下面是Object中equals()的源码:

public boolean equals(Object obj)
{
     
     
	return this == obj;
}

但是String中的equals判断的是字符串内容是否一样(当然如果是同一个字符串对象的话,返回的也是true)

sorted 自然排序
sorted(Comparator) 指定排序
limit 保留
skip 忽略

转换为其他形式的流:

mapToDouble 转换为double的流
类似的还有mapToInt(),mapToLong()

map 转换为任意类型的流

package lambda;
  
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
 
import charactor.Hero;
  
public class TestAggregate {
    
    
  
    public static void main(String[] args) {
    
    
        Random r = new Random();
        List<Hero> heros = new ArrayList<Hero>();
        for (int i = 0; i < 5; i++) {
    
    
            heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));
        }
        //制造一个重复数据
        heros.add(heros.get(0));
        System.out.println("初始化集合后的数据 (最后一个数据重复):");
        System.out.println(heros);
        System.out.println("满足条件hp>100&&damage<50的数据");
          
        heros
            .stream()
            .filter(h->h.hp>100&&h.damage<50)
            .forEach(h->System.out.print(h));
          
        System.out.println("去除重复的数据,去除标准是看equals");
        heros
            .stream()
            .distinct()
            .forEach(h->System.out.print(h));
        System.out.println("按照血量排序");
        heros
            .stream()
            .sorted((h1,h2)->h1.hp>=h2.hp?1:-1)
            .forEach(h->System.out.print(h));
          
        System.out.println("保留3个");
        heros
            .stream()
            .limit(3)
            .forEach(h->System.out.print(h));
          
        System.out.println("忽略前3个");
        heros
            .stream()
            .skip(3)
            .forEach(h->System.out.print(h));
          
        System.out.println("转换为double的Stream");
        heros
            .stream()
          //这里虽然获取的是血量
          //但是操作的还是对象
            .mapToDouble(Hero::getHp)
            .forEach(h->System.out.println(h));
          
        System.out.println("转换任意类型的Stream");
        heros
            .stream()
            .map((h)-> h.name + " - " + h.hp + " - " + h.damage)
            .forEach(h->System.out.println(h));
          
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-acom9UEy-1599051678462)(/Users/faro_z/Library/Application Support/typora-user-images/image-20200902191427499.png)]

再看一个实例

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis", "Hello", "HelloWorld", "Hollis");
Stream s = strings.stream()
  .filter(string -> string.length()<= 6)
  .map(String::length)
  .sorted()
  .limit(3)
  .distinct();

下图是Stream对象的变化过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JPggVXPb-1599051678467)(/Users/faro_z/Library/Application Support/typora-user-images/image-20200902193853184.png)]

最终操作

Stream的中间操作得到的结果还是一个Stream,那么如何把一个Stream转换成我们需要的类型呢?比如计算出流中元素的个数、将流装换成集合等。这就需要最终操作(terminal operation)

最终操作会消耗流,产生一个最终结果。也就是说,在最终操作之后,不能再次使用流,也不能在使用任何中间操作,否则将抛出异常。
常见的结束操作如下:

forEach() 遍历每个元素
collect()
toArray() 转换为数组
min(Comparator) 取最小的元素
max(Comparator) 取最大的元素
count() 用来统计流中的元素个数
findFirst() 第一个元素

下面是一个使用collect的例子

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis","Hollis666", "Hello", "HelloWorld", "Hollis");
strings  = strings
  .stream()
  .filter(string -> string.startsWith("Hollis"))
  .collect(Collectors.toList());
//找出以“Hollis”开头的元素
System.out.println(strings);
//Hollis, HollisChuang, Hollis666, Hollis

总结

Java中的Stream就像数据库的查询功能,能够帮助我们写出更加高效的代码

猜你喜欢

转载自blog.csdn.net/weixin_44062380/article/details/108370326