一、stream介绍
Stream(流)
是一个来自数据源的元素队列并支持聚合操作
元素
是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
数据源
流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
聚合操作
类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:
Pipelining:
中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
内部迭代:
以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
二、生成流的方法
stream() – 为集合创建串行流
parallelStream() – 为集合创建并行流
三、Stream流处理方法
1、forEach:用于迭代流中的每一个数据
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().foreach(System.out::println);
2、map: 用于映射每个元素到对应的结果
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map(i -> i*i).collect(Collectors.toList());
System.out.println(squaresList.toString());
3、filter:用于通过设置的条件过滤出元素
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
//获取数组中不为空的字符串
strings = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println(strings.toString());
4、limit:用于获取指定数量的流
//获取前两个
List<String> strings = Arrays.asList("abc", "cde", "bc", "efg", "abcd","", "jkl");
strings.stream().limit(2).forEach(System.out::println);
5、sorted:用于对流进行排序
List<Integer> numbers = Arrays.asList(1, 10, 13, 16, 5, 6, 7);
numbers = numbers.stream().sorted().collect(Collectors.toList());
System.out.println(numbers.toString());
四、Collectors:
实现了很多归约操作,例如将流转换成集合和聚合元素或者对集合分组排序处理
(1)Collectors.toCollection() 将流转换成集合
Stream.of(1,2,3,4,5,6,8,9,0).collect(Collectors.toCollection(ArrayList::new));
Stream.of(1,2,3,4,5,6,8,9,0).collect(Collectors.toCollection(HashSet::new));
(2) Collectors.toList() 将流转换成集合 和Collectors.toCollection() 类似
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
(3) Collectors.toSet() 将流转换成集合 和Collectors.toCollection() 类似
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toSet());
(4)Collectors.toMap() 、Collectors.toConcurrentMap() 将流转成Map、 concurrentMap
class Student{
//唯一
private String id;
private String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
//get set方法省略。。。。。
}
Student studentA = new Student("20190001","张三");
Student studentB = new Student("20190002","王五");
Student studentC = new Student("20190003","李四");
//Function.identity() 获取这个对象本身,那么结果就是Map<String,Student> 即 id->student
//串行收集
Stream.of(studentA,studentB,studentC)
.collect(Collectors.toMap(Student::getId, Function.identity()));
//并发收集
Stream.of(studentA,studentB,studentC)
.parallel()
.collect(Collectors.toConcurrentMap(Student::getId,Function.identity()));
//Map<String,String> 即 id->name
//串行收集
Stream.of(studentA,studentB,studentC)
.collect(Collectors.toMap(Student::getId,Student::getName));
//并发收集
Stream.of(studentA,studentB,studentC)
.parallel()
.collect(Collectors.toConcurrentMap(Student::getId,Student::getName));
//key重复的该怎么处理?这里我们假设有两个id相同Student,如果他们id相同,在转成Map的时候,取name大一个,小的将会被丢弃。
Stream.of(studentA, studentB, studentC)
.collect(Collectors
.toMap(Student::getId,
Function.identity(),
BinaryOperator
.maxBy(Comparator.comparing(Student::getName))));
(5)Collectors.joining(", ") 将流转换成字符串
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
(6)Collectors.counting() 统计元素个数,这个和Stream.count() 作用都是一样的
返回的类型一个是包装Long,另一个是基本long
// Long 8
Stream.of(1,0,-10,9,8,100,200,-80)
.collect(Collectors.counting());
//如果仅仅只是为了统计,那就没必要使用Collectors了,那样更消耗资源
// long 8
Stream.of(1,0,-10,9,8,100,200,-80)
.count();
(7)Collectors.minBy()、Collectors.maxBy() 获取最大最小值,这个和Stream.min()、Stream.max()作用一样,适用于高级场景
// maxBy 200
Stream.of(1, 0, -10, 9, 8, 100, 200, -80)
.collect(Collectors.maxBy(Integer::compareTo)).ifPresent(System.out::println);
// max 200
Stream.of(1, 0, -10, 9, 8, 100, 200, -80)
.max(Integer::compareTo).ifPresent(System.out::println);
// minBy -80
Stream.of(1, 0, -10, 9, 8, 100, 200, -80)
.collect(Collectors.minBy(Integer::compareTo)).ifPresent(System.out::println);
// min -80
Stream.of(1, 0, -10, 9, 8, 100, 200, -80)
.min(Integer::compareTo).ifPresent(System.out::println);
(8)Collectors.groupingBy()、Collectors.groupingByConcurrent()单线程和多线程归类
//这里将一组数整型数分为正数、负数、零
//Map<String,List<Integer>>
Stream.of(-6, -7, -8, -9, 1, 2, 3, 4, 5, 6)
.collect(Collectors.groupingBy(integer -> {
if (integer < 0) {
return "小于";
} else if (integer == 0) {
return "等于";
} else {
return "大于";
}
}));
//Map<String,Set<Integer>>
//自定义下游收集器
Stream.of(-6, -7, -8, -9, 1, 2, 3, 4, 5, 6)
.collect(Collectors.groupingBy(integer -> {
if (integer < 0) {
return "小于";
} else if (integer == 0) {
return "等于";
} else {
return "大于";
}
},Collectors.toSet()));
//Map<String,Set<Integer>>
//自定义map容器 和 下游收集器
Stream.of(-6, -7, -8, -9, 1, 2, 3, 4, 5, 6)
.collect(Collectors.groupingBy(integer -> {
if (integer < 0) {
return "小于";
} else if (integer == 0) {
return "等于";
} else {
return "大于";
}
}, LinkedHashMap::new,Collectors.toSet()));