聚合操作
将流中的数据进行汇聚为一个值,一般都是终止操作min和max用于获取最小值和最大值,注意Comparator接口,count用于统计元素个数
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(39);
list.add(10);
list.add(78);
list.add(39);
Integer maxValue = list.stream().max(Integer::compareTo).get();
System.out.println(maxValue);
long len=list.stream().count();
System.out.println(len);
利用收集器Collectors实现的聚合操作
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(39);
list.add(10);
list.add(78);
list.add(39);
//总和、平均值、最大值、最小值
// 针对int类型的数据进行累加操作,会使用参数lambda表达式将元素转换为int类型
long sum = list.stream().collect(Collectors.summarizingInt(Integer::intValue)).getSum();
System.out.println(sum);
// 求平均值
Double avg = list.stream().collect(Collectors.averagingInt(Integer::intValue));
System.out.println(avg);
//求最大值 最小值
Integer maxValue=list.stream().collect(Collectors.maxBy(Integer::compare)).get();
Integer min=list.stream().collect(Collectors.minBy(Integer::compareTo)).get();
System.out.println("max:"+maxValue+",min:"+min);
Collectors类实现了很多的聚合操作,例如将流转换为集合或者聚合元素,Collector可以返回列表List或者字符串
List<String> list1=Arrays.asList("abc","","bcd","","efg","abcd","jklm");
List<String> list2=list1.stream().filter(str->!str.isEmpty())//剔除空字符串
.collect(Collectors.toList());
String result = list1.stream().filter(str -> !str.isEmpty())
.collect(Collectors.joining(","));
查找元素
findFirst返回非空集合中的第一个元素值,一般会与filter方法结合使用
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(39);
list.add(10);
list.add(78);
list.add(39);
Optional<Integer> op = list.stream().filter(i -> i > 20).findFirst();
if(op.isPresent())
System.out.println(op.get());
else
System.out.println("没有数据");
findAny可以在stream中找到任意一个所匹配的元素就直接返回,在流的平行处理十分有效
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(39);
list.add(10);
list.add(78);
list.add(39);
Integer any=list.parallelStream().filter(i->i>20).findAny().get();
anyMathch判定是否还有匹配的元素,返回一个boolean值
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(39);
list.add(10);
list.add(78);
list.add(39);
boolean res=list.parallelStream().anyMatch(i->i>100);
类似的方法allMatch和noneMatch分别是判断所有元素都满足条件或者没有元素满足条件返回true,否则false。这些方法都是用来检查整个流,所以可以通过使用并行流提高速度。
reduce归并
reduce方法用于将流种的元素进行进一步的对并计算
List<Integer> nums = Arrays.asList(13, 2, 2, 3, 7, 3, 5);
// 求和
Integer sum = nums.stream().reduce((x, y) -> x + y).get();
System.out.println(sum);
// 简化写法
Integer sum1 = nums.stream().reduce(Integer::sum).get();
System.out.println(sum1);
// 可以指定初始值的求和计算,参数1就是累加器的初始值
Integer sum2 = nums.stream().reduce(10, Integer::sum);
System.out.println(sum2);
// 对元素的长度进行求和
int sum3 = nums.stream().map(Object::toString).mapToInt(String::length).sum();
System.out.println(sum3);
// 复杂的写法
int sum4 = nums.stream().reduce(0, (total, y) -> total + y.toString().length(), (t1, t2) -> t1 + t2);
System.out.println(sum4);
收集结果
当数据经过souce--transform--sink处理后进行处理结果的收集。一般使用Collectors提供的常见的收集器
集合
//将处理结果存储到一个List中
Random r = new Random();
List<Integer> intList = r.ints().limit(10).mapToObj(Integer::valueOf).collect(Collectors.toList());
System.out.println(intList);
//将处理结果存储到一个Set中
Set<Integer> intSet = r.ints().limit(10).mapToObj(Integer::valueOf).collect(Collectors.toSet());
System.out.println(intSet);
字符串
将stream中的字符串连接并收集起来,可以在元素之间添加指定符号
Random r = new Random();
//将字符串类型的stream使用特定符号进行拼接,拼接为一个字符串
String res=r.ints().limit(10).mapToObj((x)- >""+x).collect(Collectors.joining(","));
Map集合
可以使用Collectors.toMap方法将集合中的元素收集到Map中,但是要求有2个参数,分别用来生成 Map中的key值和value值。
List<Person> list = new ArrayList<>();
Random r = new Random();
for (int i = 0; i < 10; i++) {
Person p = new Person();
p.setId(i + 1L);
p.setName("name-" + i);
p.setAge(r.nextInt(8) + 14);
list.add(p);
}
//以对象的id值作为key,存储的value为name属性值
Map<Long, String> map1 = list.stream().collect(Collectors.toMap(Person::getId, Person::getName));
System.out.println(map1);
// Function.identity()用于获取实际的对象
Map<Long, Person> map2 = list.stream().collect(Collectors.toMap(Person::getId, Function.identity()));
System.out.println(map2);
分组操作
按照年龄分组操作
List<Person> list = new ArrayList<>();
Random r = new Random();
for (int i = 0; i < 10; i++) {
Person p = new Person();
p.setId(i + 1L);
p.setName("name-" + i);
p.setAge(r.nextInt(8) + 14);
list.add(p);
}
Map<Integer, List<Person>> map1 = list.stream().collect(Collectors.groupingBy(Person::getAge));
System.out.println(map1);
当分组条件是一个返回boolean值的函数时,流元素可以分为2组列表,一个是返回true的元素集合,一个是返回false的元素集合
List<Person> list = new ArrayList<>();
Random r = new Random();
for (int i = 0; i < 10; i++) {
Person p = new Person();
p.setId(i + 1L);
p.setName("name-" + i);
p.setAge(r.nextInt(8) + 14);
list.add(p);
}
//将大于20岁的人分为一组,将不大于20岁的人分为一组
Map<Boolean, List<Person>> map1 = list.stream().collect(Collectors.partitioningBy(p -> p.getAge() > 20));
System.out.println(map1);
并行流中的问题
stream使并行计算比较容易,在数据量较大的集合中可以体现出并行流的优势,利用多核CPU资源提升执行效率。但是使用需要注意一些问题。
首先必须是并行流。parallel方法可以将任意的串行流转换为并行流
Stream.of(1, 2, 3, 5, 6, 7).forEach(System.out::println);
System.out.println();
//将一个串行流转换为并行流
Stream.of(1, 2, 3, 5, 6, 7).parallel().forEach(System.out::println);
其次要确保传递给并行流的操作函数是线程安全的
int[] bb = new int[10];
Stream.of(1, 2, 2, 5, 2, 7).parallel().forEach(s -> {
if (s < 5)
bb[s]++;
});
System.out.println(Arrays.toString(bb));
转换结构
转换为数组
Object[] arr = Stream.of(1, 2, 2, 5, 2, 7).toArray();
System.out.println(Arrays.toString(arr));
Integer[] arr2 = Stream.of(1, 2, 2, 5, 2, 7).toArray(Integer[]::new);
System.out.println(Arrays.toString(arr));
转换为集合
List<Integer> list = Stream.of(1, 2, 2, 5, 2, 7).collect(Collectors.toList());
System.out.println(list);
ArrayList<Integer> list2 = Stream.of(1, 2, 3, 4, 5).collect(Collectors.toCollection(ArrayList::new));
System.out.println(list2);
Set<Integer> set1 = Stream.of(1, 2, 2, 4, 2, 5).collect(Collectors.toSet());
System.out.println(set1);
Stack<Integer> stack = Stream.of(1, 2, 2, 4, 2, 5).collect(Collectors.toCollection(Stack::new));
System.out.println(stack);
转化为string
String res = Stream.of("1", "2", "2", "5", "2", "7")
.collect(Collectors.joining());
System.out.println(res);
总结:
stream不是数据结构,没有内存内部存储,只是用操作管道从source中抓取数据,不修改数据的 底层结构;
一般stream的操作都是使用lambda表达式为参数;
不支持索引访问;
stream具有惰性化特征,很多的stream都是向后延迟,直到搞清楚有多少数据后进行计算;
并行化操作。