StreamApi学习

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 + "条商品型号重复");
                            }
                        });
                    }
                );
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值