StreamAPI
Stream处理的主要流程:
- 创建
–>由Collection直接创建
–>通过Arrays静态方法创建
–>通过Stream静态方法创建 - 中间处理
–>过滤、截断、舍弃、去重、排序
–>映射、扁平化映射 - 结束处理
–>迭代、匹配、查找、统计、归约、收集
基本方法
- 筛选
filter(d -> "1".equals(d.get("type")))
- 截断
limit(5)
- 舍弃
skip(5)
- 去重
distinct()
- 排序
sorted((v1, v2) -> v1 - v2)
- 映射
map(d -> (String) d.get("key"))
- 扁平化映射
flatMap(e -> e.getValue().stream())
- 迭代
forEach(d -> System.out.println(d))
- 匹配
allMatch(d -> d > 10)
noneMatch(d -> StringUtils.isEmpty(d))
anyMatch(d -> "1".equals(d.get("type")))
- 查找
findFirst(d -> d > 10).orElse(0)
findAny(d -> (Boolean) d.get("is_valid")).get()
- 统计
count()
min(Comparator.comparing(v -> v))
max((v1, v2) -> v1.compareTo(v2))
- 规约
reduce(BigDecimal.ZERO, BigDecimal::add).get()
- 收集
collect(Collectors.toList())
collect(Collectors.toMap(d -> d.get("user_id"), v -> v)
- 计数
collect(Collectors.counting())
- 平均
collect(Collectors.averagingInt(d -> d.get("quantity")))
- 最小值
collect(Collectors.minBy(Integer::compare))
- 最大值
collect(Collectors.maxBy(Integer::compare))
- 合计
collect(Collectors.summingInt(v -> v))
- 分组
collect(Collectors.groupingBy(d -> d.get("key")))
- 分组合计
collect(Collectors.groupingBy(d -> d.get("key"), Collectors.summingDouble(d -> d.get("quantity")))
- 分区
collect(Collectors.partitioningBy(g -> g.getPrice() > 15))
- 分区合计
collect(Collectors.partitioningBy(g -> g.getPrice() > 15, Collectors.summingDouble(d -> d.get("quantity")))
1、创建
1-1.由Collection直接创建
Collection接口及其被继承的List、Set、Queue、Stack等类/接口的实体可以直接创建Stream。
例如:
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
Map<String, String> map = new HashMap<>();
Stream<Entry<String, String>> stream = map.entrySet().stream();
1-2.数组可以通过Arrays.stream静态方法来创建
例如:
String[] array = new String[5];
Stream<String> stream = Arrays.stream(array);
1-3.通过Stream.of静态方法创建
例如:
Stream<String> stream = Stream.of("a", "b", "c");
1-4.通过Stream.iterate方法生成无限流
例如:
Stream<Integer> stream = Stream.iterate(0, x -> x + 2); // 生成所有的非负偶数流
1-5.通过Stream.generate方法生成无限流
例如:
Stream<Double> stream = Stream.generate(() -> Math.random()); // 生成无限多项的随机数流
2、中间处理
所有的中间处理都是惰性(lazy)的,它仅仅标记的中间处理的过程,并不会即时执行。
2-1. 过滤(filter)
接收一个lambda表达式,过滤掉某些元素,仅留下符合要求的元素。
例如:
Stream<Integer> stream = Stream.of(1, 2, -1, 0, 3, -2);
stream.filter(value -> value > 0).forEach(System.out::print);
输出的结果将为123
2-2. 截断(limit)
仅保留流中的前n个元素。由于中间处理是惰性的,所以limit在某些情况下可以很大的提升处理速度。
例如:
Stream<Integer> stream = Stream.iterate(0, x -> x + 2);
stream.limit(5).forEach(System.out::print);
输出的结果将为02468
2-3. 舍弃(skip)
舍弃流中的前n个元素,仅保留第n+1个及其之后的元素。
例如:
Stream<Integer> stream = Stream.iterate(1, 2, 3, 4, 5, 6, 7);
stream.skip(3).forEach(System.out::print);
输出的结果将为4567
2-4. 去重(distinct)
去掉Stream中重复的元素,它使用hashCode和equals方法来判断元素是否相等。
例如:
Stream<String> stream = Stream.of("a", "b", "c", "b", "c");
stream.distinct().forEach(System.out::print);
输出的结果将为abc
2-5. 排序(sorted)
对Stream中的元素进行排序。
例如:
Stream<Integer> stream = Stream.of(2, 4, 1, 5, 3);
stream.sorted().forEach(System.out::print);
输出的结果将为12345
例如:
Stream<Integer> stream = Stream.of(2, 4, 1, 5, 3);
stream.sorted(Comparator.reverseOrder()).forEach(System.out::print);
输出的结果将为54321
例如:
Stream<Map<String, Object>> stream = Stream.of(map1, map2, map3);
stream.sorted((map1, map2) -> map1.get("index").compareTo(map2.get("index"))).forEach(System.out::print);
输出的结果将按照index的升序排序
2-6. 映射(map)
通过Lambda表达式,将每一个元素一一映射为一个新的元素。
例如:
Stream<Integer> stream = Stream.of(2, 4, 1, 5, 3);
stream.map(value -> String.format("第%d名", value)).forEach(System.out::print);
输出的结果将为“第2名第4名第1名第5名第3名”
2-7.扁平化映射(flatMap)
通过Lambda表达式,将每一个元素一一映射为一个新的Stream后,将新的Stream全部连起来。
例如:
Stream<String> stream = Stream.of("abc", "def", "ghi");
stream.flatMap(str -> str.chars().boxed()).forEach(System.out::print);
输出的结果将为“979899100101102103104105”
3、结束处理
触发结束处理后,Stream将关闭而不能再次使用。
3-1. 迭代(forEach)
对Stream内的每一个元素进行循环处理。
例如:
Stream<String> stream = Stream.of("a", "b", "c");
stream.forEach(System.out::print);
输出的结果将为abc
3-2. 匹配(allMatch、anyMatch、noneMatch)
判断Stream中的元素是否匹配某条件,返回boolean结果。
allMatch:Stream中是否所有元素都匹配
anyMatch:Stream中是否有任一元素匹配
noneMatch:Stream中是否所有元素都不匹配
例如:
Stream<String> stream = Stream.of(1, 2, 4, 0, -3, -5);
stream.allMatch(value -> value > 0); // 返回false
stream.anyMatch(value -> value > 0); // 返回true
stream.noneMatch(value -> value > 0); // 返回false
3-3. 查找(findFirst、findAny)
查找Stream中的一个元素,返回Optional类型。一般与filter等一起使用。
findFirst:查找第一个元素
findAny:查找任一个元素。在并行流(parallelStream)中性能提升比较明显。
例如:
Stream<String> stream = Stream.of(1, 2, 4, 0, -3, -5);
System.out.print(stream.findFirst().orElse(0));
System.out.print(stream.findAny().orElse(0));
输出的结果将为1和任一个元素
3-4. 统计(count、min、max)
count:统计Stream中元素的个数。
min:获取Stream中的最小元素。
max:获取Stream中的最大元素。
例如:
System.out.println(Stream.of(1, 2, 4, 0, -3, -5).count());
System.out.println(Stream.of(1, 2, 4, 0, -3, -5).min(Comparator.comparing(v -> v)).orElse(0));
System.out.println(Stream.of(1, 2, 4, 0, -3, -5).max((v1, v2) -> v1.compareTo(v2)).orElse(0));
输出的结果将分别为6、-5、4
3-5. 归约(reduce)
将Stream中的每一个元素进行指定的叠加处理,最终生成一个值。
例如:
Stream<String> stream = Stream.of("abc", "def", "ghi");
System.out.println(stream.reduce("", String::concat).get()); // 连接多个字符串
这段代码等同于以下代码
String result = "";
for (Object value : stream.toArray()) {
}
return result;
输出的结果将为 abcdefghi
3-6. 收集(collect)
将Stream收集成各种形式。主要利用Collectors中的静态方法来实现。
例如:
收集成List、Set等Collection类型
List<String>list = Stream.of("abc", "def", "ghi").collect(Collectors.toList());
Set<String>set = Stream.of("abc", "def", "ghi").collect(Collectors.toSet());
LinkedList<String>list = Stream.of("abc", "def", "ghi").collect(Collectors.toCollection(LinkedList::new));
收集成Map类型
Map<String, String> map = Stream.of("abc", "def", "ghi").collect(Collectors.toMap(v -> v, v -> v.toUpperCase()));
统计总数、平均值、最值、合计等
long count = Stream.of(1, 2, 4, 0, -3, -5).collect(Collectors.counting());
double average = Stream.of(1, 2, 4, 0, -3, -5).collect(Collectors.averagingInt(v -> v));
Optional<Integer> min = Stream.of(1, 2, 4, 0, -3, -5).collect(Collectors.minBy(Integer::compare));
Optional<Integer> max = Stream.of(1, 2, 4, 0, -3, -5).collect(Collectors.maxBy(Integer::compare));
int sum = Stream.of(1, 2, 4, 0, -3, -5).collect(Collectors.summingInt(v -> v));
分组、分区
Map<String, List<Goods>> groupedGoods = Stream.of(new Goods("A", 18), new Goods("A", 15), new Goods("B", 5), new Goods("B", 20)).collect(Collectors.groupingBy(Goods::getGoodsName)); // 分组
Map<String, Map<String, List<Goods>>> groupedGoods = Stream.of(new Goods("A", 18), new Goods("A", 15), new Goods("B", 5), new Goods("B", 20)).collect(Collectors.groupingBy(Goods::getGoodsType, Collectors.groupingBy(Goods::getGoodsName))); // 多层分组
Map<String, Double> groupedGoods = Stream.of(new Goods("A", 18), new Goods("A", 15), new Goods("B", 5), new Goods("B", 20)).collect(Collectors.groupingBy(Goods::getGoodsType, Collectors.summingDouble(Goods::getPrice))); // 分组求和
Map<Boolean, List<Goods>> groupedGoods = Stream.of(new Goods("A", 18), new Goods("A", 15), new Goods("B", 5), new Goods("B", 20)).collect(Collectors.partitioningBy(g -> g.getPrice() > 15)); // 分区
Map<Boolean, Double> groupedGoods = Stream.of(new Goods("A", 18), new Goods("A", 15), new Goods("B", 5), new Goods("B", 20)).collect(Collectors.partitioningBy(g -> g.getPrice() > 15, , Collectors.summingDouble(Goods::getPrice))); // 分区求和
StreamAPI常见用法
1.将Map转换为List
Map<String, Object> mapData = …;
List<Map<String, Object>> listData = mapData.stream().map(e -> {// 获取Map的EntrySet的Stream进行变换
Map<String, Object> item = new HashMap<>();
// 将每一个Entry的key和value分别放入新的Map中
item.put("key", e.getKey());
item.put("value", e.getValue());
return item;
}).collect(Collectors.toList());
2.对List中的数据分组并合计数值
List<Map<String, Object>> dataList = …;
List<Map<String, Object>> groupedDataList = dataList.stream().collect(Collectors.groupingBy(d -> (String) d.get("goods_model"))// 按商品型号将数据分组
.entrySet().stream().map(e -> {// 将分组后的数据进行转换
Map<String, Object> item = new HashMap<>();
item.put("goods_model", e.getKey());// 商品型号由分组键值获取
item.put("total_quantity",e.getValue()
.stream().map(d -> new BigDecimal(d.get("quantity").toString()))
.reduce(BigDecimal.ZERO, BigDecimal::add).get());// 将同一组数据的数量进行汇总并设定到结果中
item.put("data_count", e.getValue().size());
return item;
}).collect(Collectors.toList());
3.对List中的数据去重
List<Map<String, Object>> dataList = …;
dataList = dataList.stream().collect(Collectors.groupingBy(d -> d.get("goods_model") + "||" + d.get("organization"))// 按商品型号和组织将数据分组
.entrySet().stream().map(e -> e.getValue(0))// 将分组后的数据进行转换,只保留每组第1条数据
.collect(Collectors.toList());
4.从一个List中去除另一个List中已有的数据
List<Map<String, Object>> checkList = …;
List<Map<String, Object>> targetList = …;
方法1:
targetList.removeIf(target -> checkList.stream().anyMatch(check -> check.get("document_no").equals(target.get("document_no"))));// 将已在checkList里的document_no的数据从targetList里去除
方法2:
targetList = targetList.stream().filter(target -> checkList.stream().noneMatch(check -> check.get("document_no").equals(target.get("document_no")))).collect(Collectors.toList());// 仅保留不在checkList里的document_no的数据
5.将List中的数据排序
List<Map<String, Object>> dataList = …;
dataList = dataList.stream().sorted(// 对List进行排序处理
(d1, d2) -> {
int res = ((String) d1.get("organization")).compareTo((String) d2.get("organization"));// 首先使用组织代码的升序排序
if (res != 0) {
return res;
}
return new BigDecimal(d2.get("quantity").toString()).doubleValue() - new BigDecimal(d1.get("quantity").toString()).doubleValue();// 若组织代码相同,则按数量的降序排序
}).collect(Collectors.toList());
6.将List中的数据按数量的正负符号分组,然后分别进行处理
List<Map<String, Object>> dataList = …;
Map<Boolean, List<Map<String, Object>> partitionDataList = dataList.stream().filter(d -> new BigDecimal(d.get("quantity").toString()).doubleValue() != 0)// 首先去除数量为0的数据
.collect(Collectors.partitionBy(d -> new BigDecimal(d.get("quantity").toString()).doubleValue() > 0);// 按照数量是否大于0对数据进行分区
partitionDataList.get(true).forEach(…);// 处理数量为正值的数据
partitionDataList.get(false).forEach(…);// 处理数量为负值的数据
7.将多个批量处理的错误信息汇总
BatchResultCollector collector = new BatchResultCollector();
collector.markBatchTime();
for (…) {
BatchResult batchResult = ...;
String key = …;
collector.createFailRecord(key);
batchResult.getFailRecords().stream().flatMap(r -> r.getCheckItems().stream()).distinct().forEach(// 将批量处理的所有错误信息取出,去重后,合并到主处理的批量处理结果中
item -> collector.createCheckItems(key, item.getTitle(), item.getContent())
);
collector.increaseFailCount();
}
补充:2018-0416 两个数字字符的比较
failRecords = failRecords.stream().sorted((map1,map2) ->(new BigDecimal(map1.getKey().toString())).compareTo(new BigDecimal(map2.getKey().toString()))).collect(Collectors.toList());
2018-04-24找出两个重复
//2.1.1查询每个组别不可存在重复商品数据
perListData.stream().forEach(a -> {
perListData.stream().forEach(b->{
if(a.get("goodsModel").equals(b.get("goodsModel"))){
int aIndex = Integer.valueOf(a.get("rowIndex").toString());
aIndex +=1;
int bIndex = Integer.valueOf(b.get("rowIndex").toString());
bIndex +=1;
collector.addFailRecord(b.get("groupId").toString(), "商品重复",
"第" +aIndex + "条 与 "+"第" +bIndex + "条商品型号重复");
}
});
}
);