上转 《Stream流 - 获取Stream和转换操作》
将最终处理的结果进行聚合输出。
min/max
:最值操作,需要比较器count
:统计操作,统计数据个数collect
:收集操作,使用官方的Collectors提供的收集器findFirst/findAny
:查找操作,返回的类型为OptionalnoneMatch、AllMatch和anyMatch
:匹配操作,检查数据流中是否存在符合条件的数据,返回一个boolean值reduce
:规约操作,将数据流的值规约为一个值,例如count/min/max底层实际上就是使用reduceforEach
:遍历操作,可以对最终的数据进行消费toArray
:数组操作,用于将数据流的元素转换为数组min和max
用于获取最小值和最大值,实现 Comparator接口。
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(39);
list.add(10);
list.add(78);
list.add(39);
Integer maxInteger = list.stream().max(Integer::compareTo).get();
System.out.println(maxInteger);
输出:
78
count
统计数据个数。
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(39);
list.add(10);
list.add(78);
list.add(39);
long len = list.stream().count();
System.out.println(len);
输出:
5
Collectors类实现了很多的聚合操作,例如将流转换为集合或者聚合元素,Collector可以返回集合、字符串、Map集合。
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(","));
System.out.println(list2);
System.out.println(result);
输出:
[abc, bcd, efg, abcd, jklm]
abc,bcd,efg,abcd,jklm
使用 Collectors.toMap
方法将集合中的元素收集到Map中,但是要求有2个参数,分别用来生成Map中的key值和value值。
List<Product> list = new ArrayList<>();
list.add(new Product("product1","11.2"));
list.add(new Product("product2","22.3"));
list.add(new Product("product3","33.4"));
// 以对象的id值作为key,存储的value为name属性值
Map<String, String> map1 = list.stream().collect(Collectors.toMap(Product::getName, Product::getPrice));
System.out.println(map1);
// Function.identity()用于获取实际的对象
Map<String, Product> map2 = list.stream().collect(Collectors.toMap(Product::getName, Function.identity()));
System.out.println(map2);
输出:
{product2=22.3, product1=11.2, product3=33.4}
{product2=Product{name='product2', price='22.3'}, product1=Product{name='product1', price='11.2'}, product3=Product{name='product3', price='33.4'}}
Function.identity()
用于获取实际的对象。
Collectors.groupingBy()
指定分组字段
List<Product> list = new ArrayList<>();
list.add(new Product("product1","11.2"));
list.add(new Product("product2","22.3"));
list.add(new Product("product3","33.4"));
list.add(new Product("product4","11.2"));
Map<String, List<Product>> map = list.stream().collect(Collectors.groupingBy(Product::getPrice));
System.out.println(map);
输出:
{33.4=[Product{name='product3', price='33.4'}], 22.3=[Product{name='product2', price='22.3'}], 11.2=[Product{name='product1', price='11.2'}, Product{name='product4', price='11.2'}]}
Collectors.groupingBy()
指定分组条件,当分组条件是一个返回boolean值的函数时,流元素可以分为2组列表,一个是返回true的元素集合,一个是返回false的元素集合。
List<Product> list = new ArrayList<>();
list.add(new Product("product1","11.2"));
list.add(new Product("product2","22.3"));
list.add(new Product("product3","33.4"));
list.add(new Product("product4","11.2"));
//将大于20岁的人分为一组,将不大于20岁的人分为一组
Map<Boolean, List<Product>> map = list.stream().collect(Collectors.groupingBy(v -> Double.valueOf(v.getPrice()) > 20));
System.out.println(map);
System.out.println(map.get(true));
Map<Boolean, List<Product>> map2 = list.stream().collect(Collectors.partitioningBy(v -> Double.valueOf(v.getPrice()) > 20));
System.out.println(map2);
输出:
{false=[Product{name='product1', price='11.2'}, Product{name='product4', price='11.2'}], true=[Product{name='product2', price='22.3'}, Product{name='product3', price='33.4'}]}
[Product{name='product2', price='22.3'}, Product{name='product3', price='33.4'}]
{false=[Product{name='product1', price='11.2'}, Product{name='product4', price='11.2'}], true=[Product{name='product2', price='22.3'}, Product{name='product3', price='33.4'}]}
Collectors.partitioningBy()
也可以分组。
Stream分组并排序:介绍Stream指定字段分组排序
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 maxInteger = list.stream().collect(Collectors.maxBy(Integer::compare)).get();
System.out.println(maxInteger);
Integer min = list.stream().collect(Collectors.minBy(Integer::compareTo)).get();
System.out.println(min);
输出:
176
35.2
78
10
也可以使用 mapToInt
list.stream().mapToInt((x) -> x).summaryStatistics().getSum();
findFirst
返回非空集合中的第一个元素值,一般会与filter
方法结合使用。
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(39);
list.add(10);
list.add(78);
Optional<Integer> op = list.stream().filter(i -> i > 20).findFirst();
if (op.isPresent())
System.out.println(op.get());
else
System.out.println("没有数据");
输出:
39
anyMatch
判定是否还有匹配的元素,返回一个boolean值。
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(39);
list.add(78);
boolean res1 = list.parallelStream().anyMatch(i -> i > 39);
boolean res2 = list.parallelStream().anyMatch(i -> i > 100);
System.out.println(res1);
System.out.println(res2);
输出:
true
false
判断所有的元素都满足条件或者没有元素满足条件返回true。这些方法用来检查整个流,所以可以通过使用并行流提高速度。
reduce
方法用于将流中的元素进行进一步的归并计算。
首先熟悉三个概念
Identity
: 定义一个元素代表是归并操作的初始值,如果Stream 是空的,也是Stream 的默认结果。Accumulator
: 定义一个带两个参数的方法,第一个参数是上个归并方法的返回值,第二个是Strem 中下一个元素。Combiner
: 调用一个方法来组合归并操作的结果,当归并是并行执行或者当累加器的方法和累加器的实现类型不匹配时才会调用此方法。List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int result = numbers
.stream()
.reduce(0, (subtotal, element) -> subtotal + element);
System.out.println(result);
输出:
21
reduce 方法的第一个参数 0 是 identity
初始值 ,此参数用来保存归并参数的初始值,当Stream 为空时也是默认的返回值。
(subtotal, element) -> subtotal + element 是accumulator
,第一个参数是上次累计的和,第二个参数是数据流的下一个元素。
为了使代码更简洁,我们可以用方法引用来代替 lambda 表达式。
int result = numbers.stream().reduce(0, Integer::sum);
还可以操作一个 String 类型的数组,把数组的字符串进行拼接。
List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
String result = letters
.stream()
.reduce("", (partialString, element) -> partialString + element);
简写:
String result = letters.stream().reduce("", String::concat)
如果流中包含的是User 对象,但是累加方法的参数分别是数字和user 对象,而累加器的实现是求和:
int result = users.stream()
.reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
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);
输出:
35
35
45
8
实际项目中,一般金额都是用String类型进行存储,使用stream.sum()
进行累加获取的值缺失精度,需要使用BigDecimal.add
进行累加。
List<String> nums = Arrays.asList("13.1", "2.1", "2.1", "3.1", "7.1");
BigDecimal reduce = nums.stream().map(x -> new BigDecimal(x)).reduce(BigDecimal.ZERO, BigDecimal::add);
System.out.println(reduce);
输出:
27.5
forEach
可以迭代流中的每个数据,forEach方法可以接收一个lambda表达式,并且在每个元素上执行该表达式。
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(39);
list.add(78);
list.stream().forEach(v -> {
if (v > 30) {
System.out.println(v);
}
});
输出:
39
78
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(arr2));
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 res = Stream.of("1", "2", "2", "5", "2", "7").collect(Collectors.joining());
System.out.println(res);
读取一个文本文件,查找最长一行内容的字符个数
BufferedReader br = new BufferedReader(new FileReader("input/abc.logs"));
int maxLength=br.lines().mapToInt(String::length).max().getAsInt();
br.close();
System.out.println(maxLength);
读取一个英文的文本文件,查找所有的英文单词,转换为全小写,并排序
BufferedReader br = new BufferedReader(new FileReader("input/bbb.logs"));
List<String> words = br.lines().flatMap( line -> Stream.of(line.split(" "))).filter(word -> word.length() > 1) .map(String::toLowerCase).distinct().sorted().collect(Collectors.toList());
br.close();
System.out.println(words);
计算列表对象某个字段值总和
List<Product> list = new ArrayList<>();
list.add(new Product("product1","11.2"));
list.add(new Product("product2","22.3"));
list.add(new Product("product3","33.4"));
list.add(new Product("product4","11.2"));
System.out.println("sum=" + list.stream().mapToDouble(v -> Double.valueOf(v.getPrice())).sum());
System.out.println("sum=" + list.stream().map(v -> Double.valueOf(v.getPrice())).reduce(0.0, (x,y) -> x+y));
System.out.println("sum=" + list.stream().map(v -> Double.valueOf(v.getPrice())).reduce(0.0, Double::sum));
输出:
sum=78.1
sum=78.10000000000001
sum=78.10000000000001
计算列表总和
//如果不需要转换,就不需要使用map
List<Integer> nums = Arrays.asList(13, 2, 2, 3, 7, 3, 5);
System.out.println("sum=" + nums.stream().mapToInt(v->v).sum());
System.out.println("sum=" + nums.stream().reduce(0, (x,y)->x+y));
System.out.println("sum=" + nums.stream().reduce(0, Integer::sum));
输出:
sum=35
sum=35
sum=35