Java8——Stream流式操作的一点小总结

Java8——Stream流式操作的一点小总结

我发现,自从我学了Stream流式操作之后,工作中使用到的频率还是挺高的,因为stream配合着lambda表达式或者双冒号(::)使用真的是优雅到了极致!今天就简单分(搬)享(运)一下我对stream流式操作的一点理解

一、什么是流式操作?或者准确的说什么是“流”

​ 所谓艺术来源于生活,所以不妨从一个生活中小例子展开说明一下。

​ 通过组词,流可以组成流动,流水,流经,流进流出… 这些描述的都是一种状态,是一种“运动”中的状态,更加通俗的讲,流水线。以往的流水线会有很多工人在,每一个工人负责一个环节,环环相联下来之后最终会形成成品。好了,现在分解一下

  1. 首先需要有一条流水线(好给你流水线)

在这里插入图片描述

  1. 流水线有了,那么总得需要有人在作业吧,那就放几个卡通人上去充当一下,他们将完成对原材料的筛选、清洗、组装、贴标签等操作,注意这是有顺序,这也很好理解,下一道工序必须是在上一道工序的基础上进行的,总不能跳过组装就直接装箱吧,虽然是可以,但是你发个空包给别人,真的好吗?

在这里插入图片描述

所以流水线+作业人员有了

  1. 经过一番操作之后,产出产品,之后就需要打包出厂,走进寻常百姓家了。最终完整的流程就是酱紫的

在这里插入图片描述

所以,对于“流式操作”可以想象成把一项需要完成的操作“打扁”成原材料,原材料会经过经过很多道工序,而经过多道工序时的状态就是“流”,最终会对流进行一个打包收集,形成业务产品。

二、对于stream,你不得不了解的几个概念

第一部分通过一个简单的例子,阐述了一下先决概念,接下来就就对stream本身进行了解。

中间操作符与终止操作符

一句话讲明,中间操作符可以有多个,每个中间操作符都是在前一个中间操作符的基础上进行操作的,这就像极了刚刚讲解的多道工序,二终止操作符有且仅有一个,也即处理完所有的中间操作之后,对最终产品进行收集或者消费的,流在这里之后就会得到一个实际的“产品”。

常见的中间操作符

操作符对应的概念
flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作比如把 int[]{2,3,4} 拍平 变成 2,3,4 也就是从原来的一个数据变成了3个数据,这里默认提供了拍平成int,long,double的操作符
limit 限流操作比如数据流中有10个 我只要出前3个就可以使用
distint 去重操作对重复元素去重,底层使用了equals方法
filter 过滤操作把不想要的数据过滤
peek 挑出操作如果想对数据进行某些操作,如:读取、编辑修改等
skip 跳过操作跳过某些元素
sorted(unordered) 排序操作对元素排序,前提是实现Comparable接口,当然也可以自定义比较器

常见的终止操作符

操作符对应的概念
collect 收集使用系统提供的收集器可以将最终的数据流收集到List,Set,Map等容器中
count 统计操作统计最终的数据个数
findFirst、findAny 查找操作查找第一个、查找任何一个 返回的类型为Optional
noneMatch、allMatch、anyMatch 匹配操作数据流中是否存在符合条件的元素 返回值为bool 值
min、max 最值操作,需要自定义比较器返回数据流中最大最小的值
reduce 规约操作将整个数据流的值规约为一个值,count、min、max底层就是使用reduce
forEach、forEachOrdered 遍历操作这里就是对最终的数据进行消费了
toArray 数组操作将数据流的元素转换成数组

⚠️所有的这些操作都是建立在流的基础上,所以首先需要把对象打成流,而stream主要用于对象类型的集合,当然基础类型的stream其实也是有提供的,这是打成流的方式不一致,待会会展示到底哪里不一致了。

三、stream的简单小操作展示

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
class Person{
	private Integer id;
	private String name;
	private Integer age;
	private String sex;
}
/**
* @author Amg
* @Description 首先展现一下对于对象的集合跟基本类型是怎么打成流的
* @param
* @date 2020/9/13
* @return void
*/
public void tt(){

    //基于对象的集合
    List<Person> list = new ArrayList<>();
    Stream<Person> collection = list.stream();

    //基于基本类型的
    int[] array = new int[]{1,2,3,4,5,6,7,8,9};
    IntStream primitive = Arrays.stream(array);

    //挖一下源码就会发现,其实Stream<T>跟IntStream都是继承自BaseStream的,有Int自然也会有Double、Long等等
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xTxmhZll-1599981812509)(E:\杂七杂八\公众号\2020-7-15\结构图.png)]

/**
* @author Amg
* @Description 第二个讲一下遍历过滤输出一个给定的范围的偶数
* @param
* @date 2020/9/13
* @return void
*/
public void testStream01() {
    IntStream.range(0, 20).filter(i -> (i % 2 == 0)).forEach(result -> System.out.print(result + " "));
}

//output 0 2 4 6 8 10 12 14 16 18 这里得注意了,对于lambda表达式跟方法引用的使用大家是要会的
/**
* @author Amg
* @Description 模拟场景就是一个带重复数据的数组集合,把它转换成一个去重后的List集合并且打印List中所有元素
* @param 
* @date 2020/9/13
* @return void
*/
public void testStream02(){

    Object[] array = new Object[]{1,1,1,1,1,1,2,2,2,
                                  2,2,2,3,3,3,3,3,
                                  'a','a','a','a',
                                  "e","e","e","e",
                                  3.579f,3.579f,594d,594d,
                                  97586L,97586L
                                 };
    Arrays.stream(array).distinct().collect(Collectors.toList()).forEach(res-> System.out.print(res + " "));

    //output 1 2 3 a e 3.579 594.0 97586 distinct就是去重的操作
}
/**
* @author Amg
* @Description 这次模拟的场景是对对象进行操作,把list转换成map,map的键是对象的id主键,值是整个对象
* @param
* @date 2020/9/13
* @return void
*/
public void testStream03(){

    //prepareData()准备一些数据
    List<Person> list = prepareData();
    System.out.println(list);
    //Function.identify() 等价于 t -> t 返回自身
    //toMap的第三个参数可以解决冲突问题,当键值都是一致的情况,如果不添加第三个参数就会抛异常,下面的写法代表,如果有冲突则保留其中一个
    Map<Integer, Person> result = list.stream().collect(Collectors.toMap(Person -> Person.getId() ,Function.identity(),(entity1,entity2)-> entity1));
    result.forEach((key,value)->{
        System.out.println(key + ":[" + value + "]");
    });
}

//output
/**  
[Person(id=1, name=z3, age=3, sex=男), Person(id=2, name=l4, age=4, sex=男), Person(id=3, name=w5, age=2, sex=男), Person(id=4, name=z6, age=13, sex=女), Person(id=5, name=t7, age=35, sex=女), Person(id=5, name=t7, age=35, sex=女)]
1:[Person(id=1, name=z3, age=3, sex=男)]
2:[Person(id=2, name=l4, age=4, sex=男)]
3:[Person(id=3, name=w5, age=2, sex=男)]
4:[Person(id=4, name=z6, age=13, sex=女)]
5:[Person(id=5, name=t7, age=35, sex=女)]

*/
/**
* @author Amg
* @Description 再考虑一个业务,从数据库中获取到对应表中指定的数据集,然后我们需要的是该表的主键id值,
* 然后通过这个主键id值去查,另外一张表的数据,得到的数据才是我们真实需要的
* @param 
* @date 2020/9/13
* @return void
*/
public void testStream04(){

    //模拟环境,数据直接从方法里面模拟
    List<Person> list = getAllPersonById();

    //原操作是如此的
    List<Integer> personId = new ArrayList<>();
    for (Person person : list) {
        personId.add(person.getId());
    }

    //list里面存放的是所有的Person对象,我们将通过Stream流操作抽取出我们需要id,一行代码可以完成
    List<Integer> result = list.stream().map(Person::getId).collect(Collectors.toList());
    System.out.println(result);
    
    //output [1, 2, 3, 4, 5, 5]
}

好了,这就是今天分享的小内容,感谢你的观看,祝你生活愉快!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值