集合流简介
一、集合的流式编程简介
- Stream 是 JDK1.8之后出现的新特性,也是JDK1.8新特性中最值得学习的两种新特性之一。
- Stream 是对集合操作的增强但不影响数据源,流不是集合的元素,不是数据结构,不负责数据的存储。流更像是一个迭代器,可以单向遍历集合中的每一个元素,并且不可循环。
- 其实在 1.8 以前我们也使用过一些流式处理API 比如 StringBuffer、StringBuilder 中的append 方法。每次都是返回StringBuffer、StringBuilder流本身。
二、为什么使用集合的流式编程
有时候对集合中的元素进行操作的时候,需要用到其他操作的结果,在这个过程中流式编程能大幅度简化代码的数量,提高可阅读性,将数据源读取到流中可以对这个流进行(删除、过滤、映射、统计…)等等操作。每次操作的结果也是返回流本身可以继续操作。
三、流式编程的步骤
1、获取数据源,将数据源读取到流中。
2、对流中数据进行各种各样的处理。
3、对流中数据整合处理。
四、数据源的获取
数据源 - 顾名思义,就是流中数据的来源可以是DB中、第三方系统、缓存等等返回的集合数据。
/**
*模拟集合数据源
*/
public static Stream<Integer> listDataSource(){
// 初始化集合
List<Integer> list = new ArrayList<>();
// 填充元素
Collections.addAll(list,0,1,2,3,4,5,6,7,8,9);
// 获取集合中的元素到 同步流中
Stream<Integer> synchronizeStream = list.stream();
// 获取集合中的元素到 异步流中
//Stream<Integer> asyncStream = list.parallelStream();
return synchronizeStream;
}
// 模拟数组数据源
public static Stream<Integer> arrayDataSource(){
// 初始化数组
Integer[] arr = new Integer[]{0,1,2,3,4,5};
// Arrays 工具类获取 arr 流对象
Stream<Integer> stream = Arrays.stream(arr);
return stream;
}
五、最终操作(这里我们先从最终操作开始了解了解流中的一些方法)
将流中的数据整合到一起,可以存入到集合,也可以直接对流中的数据做统计、遍历、比较大小、求和、平均值等操作。
注意:最终操作 - 每次操作完都会释放流,容易抛出异常。
1、collect - 将流对象 转为不同的数据结构 List Set Map等等。
/**
* 测试入口
* @param args
*/
public static void main(String[] args) {
// 获取数据源 流对象
Stream<Integer> integerStream = listDataSource();
/**
* Collectors 里面有很多 to List Map Set的方法
*/
List<Integer> list = integerStream.collect(Collectors.toList());
Set<Integer> set = integerStream.collect(Collectors.toSet());
// toMap 参数含义是:
// m -> m.toString() 用 string类型的 当前值 做key
// m -> m 用值本身 就key 的值
Map<String, Integer> map = integerStream.collect(Collectors.toMap(m -> m.toString(), m -> m));
// 这里需要注意 只会输出第一句下面的会抛异常因为最终操作每次操作完则关闭释放流
System.out.println("stream to list : " + collect);
System.out.println("stream to set : " + set);
System.out.println("stream to map : " + map);
}
2、reduce - 将流的元素逐一带入到这个函数中进行运算。
public static void main(String[] args) {
// 获取数据源 流对象
Stream<Integer> integerStream = listDataSource();
/**
* (e1, e2) 每遍历一次 将当前值 与 下一个值 做运算
* (e1 + e2) 运算符 可以 加减乘除
* .get() 才能获取到实际 integer 值 否则返回 Optional
*/
//Optional<Integer> reduce = integerStream.reduce((e1, e2) -> (e1 + e2));
Integer integer = integerStream.reduce((e1, e2) -> (e1 + e2)).get();
// 输出结果为 --> 45 0+123456789
System.out.println(integer);
}
3、count - 用于统计集合中的数量 等同于 list.size。
public static void main(String[] args) {
// 获取数据源 流对象
Stream<Integer> integerStream = listDataSource();
/**
* count 用于统计元素的数量
*/
long count = integerStream.count();
System.out.println(count);
}
4、foreach - 循环遍历集合中的数据。
public static void main(String[] args) {
// 获取数据源 流对象
Stream<Integer> integerStream = listDataSource();
// forEach 循环遍历集合中的值
integerStream.forEach(System.out::println);
// 实际场景中 也可以根据业务进行更多操作
integerStream.forEach(stream ->{
System.out.println(stream );
});
}
5、Max & Min - 获取集合中最大 最小值。
public static void main(String[] args) {
// 获取数据源 流对象
Stream<Integer> integerStream = listDataSource();
// 获取集合中元素最大值
Integer max = integerStream.max(Integer::compareTo).get();
// 获取集合中元素最小值
Integer min = integerStream.min(Integer::compareTo).get();
System.out.println("最大值:" + max);
System.out.println("最小值:" + min);
}
6、matching - 匹配元素。
- allMtach - 只有当流中所有的元素都匹配指定的规则才为 true。
- anyMtach - 只要流中有任意数据满足指定规则都为true。
- noneMtach - 只有当流中所有的元素都不满足指定规则才为 true。
public static void main(String[] args) {
// 获取数据源 流对象
Stream<Integer> integerStream = listDataSource();
// 条件 当前值 > 0
boolean allMatch = integerStream.allMatch( m -> (m > 0));
boolean anyMatch = integerStream.anyMatch( m -> (m > 0));
boolean noneMatch = integerStream.noneMatch( m -> (m > 0));
System.out.println(allMatch);
System.out.println(anyMatch);
System.out.println(noneMatch);
}
7、find - 看名字也知道是查找了。
- findFirst - 从流中获取一个元素,普遍都是获取开头的元素。
- findAny - 从流中获取一个元素,一般情况下也是开头的元素。
- 绝大情况下两个方法的结果都是相同的,但是多线程情况下可能不一致。
public static void main(String[] args) {
// 获取数据源 流对象
Stream<Integer> integerStream = listDataSource();
Integer integer = integerStream.findFirst().get();
Integer integer1 = integerStream.findAny().get();
System.out.println(integer);
System.out.println(integer1);
}
8、其他流对象 IntStream、DoubleStream、LongStream等等。
注意:因为我们知道 最终操作每次操作完都会关闭流对象而我们需要的是一次性要返回 更多信息比如统计数量、平均数、总数量等等。使用普通的流对象则需要频繁打开关闭流消耗资源。所以这里要着重注意流对象的分析类【IntSummaryStatistics】所有的分析数据都可以通过这个类获取。
public static void main(String[] args) {
// 获取数据源 流对象
int[] arr = new int[]{0,1,2,3,4,5};
// intStream
IntStream intStream = Arrays.stream(arr);
System.out.println(intStream.count());
System.out.println(intStream.max());
System.out.println(intStream.min());
// .... 等等更多操作都有
IntSummaryStatistics intSummaryStatistics = intStream.summaryStatistics();
intSummaryStatistics.getMin();
intSummaryStatistics.getMax();
intSummaryStatistics.getSum();
intSummaryStatistics.getCount();
// 获取平均值
intSummaryStatistics.getAverage();
}
- 最终操作就到这里了,因为我本人也是刚开始学习流式编程说的不好请各位大佬指教。
下一章说一说:集合流式编程中间操作。
个人Gitee