影落离风

The shadow falls away from the wind

0%

Stream-流式处理的常用操作你GET到了吗?

特性

  1. 对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。
  2. 借助于同样新出现的Lambda表达式,极大的提高编程效率和程序可读性。
  3. 提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用fork/join并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用Stream API无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。

使用技巧

  1. 获取集合中某属性值的集合

    1
    2
    3
    4
    5
    6
    7
    List<UserDto> userDtos = Arrays.asList(
    new UserDto(1, "用户1"),
    new UserDto(2, "用户2"),
    new UserDto(3, "用户3")
    );
    List<Integer> userId = userDtos.stream().map(UserDto::getUserId).collect(Collectors.toList());
    System.out.println(userId);
  2. 将集合转为map对象,以集合中某属性作为key,该属性值对应的对象做value;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //以userId作为key,key不能重复
    List<UserDto> userDtos = Arrays.asList(
    new UserDto(1, "用户1"),
    new UserDto(2, "用户2"),
    new UserDto(3, "用户3")
    );
    //方式1
    Map<Integer, UserDto> userDtoMap = userDtos.stream()
    .collect(Collectors.toMap(UserDto::getUserId, Function.identity()));
    System.out.println(userDtoMap);

    //方式2
    Map<Integer, UserDto> userDtoMap2 = userDtos.stream()
    .collect(Collectors.toMap(UserDto::getUserId, UserDto->UserDto));
    System.out.println(userDtoMap2);
  3. Collectors.toMap时保持原有顺序

    1
    2
    3
    LinkedHashMap<String, Integer> itemMap = entry.getValue().stream()
    .collect(Collectors.toMap(UserDto::getUserId,
    UserDto::getAge, (k1, k2) -> k1, LinkedHashMap::new));
  4. 以集合中某属性进行分组

    1
    2
    3
    4
    5
    6
    7
    8
    List<UserDto> userDtos = Arrays.asList(
    new UserDto(1, 20),
    new UserDto(2, 21),
    new UserDto(3, 20)
    );
    Map<Integer, List<UserDto>> userMap = userDtos.stream()
    .collect(Collectors.groupingBy(UserDto::getAge));
    System.out.println(userMap);
  5. 以集合中某属性进行分组,收集获取value对象集合中的属性集合

    1
    2
    3
    4
    5
    6
    7
    List<PersonDTO> list = Arrays.asList(
    PersonDTO.builder().city("深圳").name("李四").build(),
    PersonDTO.builder().city("深圳").name("王五").build(),
    PersonDTO.builder().city("西安").name("张三").build()
    );
    Map<String,List<String>> map = list.stream().collect(Collectors.groupingBy(PersonDTO::getCity,
    Collectors.mapping(PersonDTO::getName, Collectors.toList())));
  6. 以集合中某属性进行分组,并保持原有顺序

    1
    2
    dimensionMap = results.stream()
    .collect(Collectors.groupingBy(IstHistoryDataDimension::getDateFormat, LinkedHashMap::new, Collectors.toCollection(ArrayList::new)));
  7. 以集合中某属性进行排序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    List<UserDto> userDtos = Arrays.asList(
    new UserDto(3, 22),
    new UserDto(2, 21),
    new UserDto(4, 21),
    new UserDto(1, 20)
    );
    List<UserDto> userDtoList = userDtos.stream()
    //.reversed()倒序,没有是正序
    .sorted(Comparator.comparing(UserDto::getUserId).reversed())
    .collect(Collectors.toList());
    System.out.println(userDtoList);
  8. 适应属性值可能为null的排序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //将属性值可能为null的元素排在前面
    pList = pList.stream()
    .sorted(Comparator.comparing(Person::getAge, Comparator.nullsFirst(Integer::compareTo)))
    .collect(Collectors.toList());
    System.out.println("将属性值可能为null的元素排在前面 "+ pList);

    //将属性值可能为null的元素排在后面
    pList = pList.stream()
    .sorted(Comparator.comparing(Person::getAge, Comparator.nullsLast(Integer::compareTo)))
    .collect(Collectors.toList());
    System.out.println("将属性值可能为null的元素排在后面 "+ pList);
  9. 为集合添加序号

    1
    2
    Integer[] arr = {1};
    pList = pList.stream().peek(e -> e.setId(arr[0]++)).collect(Collectors.toList());
  10. Collectors.groupingBy保持原有顺序进行分组

    1
    2
    Map<String, List<UserDto>> detailVosMap = userDtos.stream()
    .collect(Collectors.groupingBy(UserDto::getUserId, LinkedHashMap::new, Collectors.toList()));
  11. 以集合中某属性进行排序后再以另一个属性进行分组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    List<UserDto> userDtos = Arrays.asList(
    new UserDto(3, 22),
    new UserDto(2, 21),
    new UserDto(4, 21),
    new UserDto(1, 20)
    );
    TreeMap<Integer, List<UserDto>> userDtoMap = userDtos.stream()
    //先以UserId进行排序
    .sorted(Comparator.comparing(UserDto::getUserId进行排序))
    //再以年龄进行分组
    .collect(Collectors.groupingBy(UserDto::getAge, TreeMap::new, Collectors.toList()));
    System.out.println("正序: " + userDtoMap);
    //以分组的key值倒序
    System.out.println("倒序" + userDtoMap.descendingMap());
  12. 对集合中某数值属性进行求和、平均值、计数等

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    List<UserDto> userDtos = Arrays.asList(
    new UserDto(1, 20),
    new UserDto(2, 23),
    new UserDto(3, 21)
    );
    Integer age = userDtos.stream().mapToInt(UserDto::getAge).sum();
    System.out.println("总和="+age);

    double age = userDtos.stream().mapToInt(UserDto::getAge).average().getAsDouble();
    System.out.println("平均值="+age);
    //sum、average、count等属性,自己可以再探索
  13. 对集合中某金额属性(BigDecimal)进行计算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    List<UserDto> userDtos = Arrays.asList(
    new UserDto(1, BigDecimal.ONE),
    new UserDto(2, BigDecimal.TEN),
    new UserDto(3, BigDecimal.ZERO)
    );
    BigDecimal money = userDtos.stream().map(UserDto::getMoney).reduce(BigDecimal::add).get();
    System.out.println("总金额="+money);

    BigDecimal money = userDtos.stream().map(UserDto::getMoney).reduce(BigDecimal::max).get();
    System.out.println("集合中最大金额="+money);
    //add、max、divide、multiply等属性,自己可以再探索
  14. 对集合去重

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //对元素列表去重
    list.stream().distinct().collect(Collectors.toList());

    //对集合对象去重
    list.stream().collect(
    Collectors.collectingAndThen(
    Collectors.toCollection(() -> new TreeSet<>
    //getTypeCode对象中的元素
    (Comparator.comparing(Bean::getTypeCode))), ArrayList::new));

    // 根据name,sex两个属性去重
    List<Person> unique = persons.stream().collect(
    Collectors. collectingAndThen(
    Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getName() + ";" + o.getSex()))), ArrayList::new)
    );
  15. 对两个集合取差集

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    List<Person> arels = new ArrayList<>();
    Person rel = new Person();
    rel.setName("1");
    arels.add(rel);
    Person rel1 = new Person();
    rel1.setName("2");
    arels.add(rel1);
    Person arel2 = new Person();
    arel2.setName("5");
    arels.add(arel2);

    List<Person> brels = new ArrayList<>();
    Person brel = new Person();
    brel.setName("2");
    brels.add(brel);
    Person brel1 = new Person();
    brel1.setName("5");
    brels.add(brel1);
    Person brel2 = new Person();
    brel2.setName("7");
    brels.add(brel2);

    // 求差集
    List<Person> list = brels.stream().filter(item -> !arels.stream().map(Person::getName)
    .collect(Collectors.toList()).contains(item.getName())).collect(Collectors.toList());
    System.out.println(JSONUtil.toJsonStr(list));
  16. stream对list集合对象进行分组求和

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    Seq.of(ksVoList.toArray()).ofType(ChuangLiangKsVo.class)
    .groupBy(
    //根据CampaignId属性分组
    x -> tuple(x.getCampaignId()),
    Tuple.collectors(
    // 对以下属性求和
    Collectors.summarizingDouble(ChuangLiangKsVo::getCharge),
    Collectors.summingLong(ChuangLiangKsVo::getAclick),
    Collectors.summingLong(ChuangLiangKsVo::getBclick),
    Collectors.summingLong(ChuangLiangKsVo::getDownloadStarted),
    Collectors.summingLong(ChuangLiangKsVo::getDownloadCompleted),
    Collectors.summingLong(ChuangLiangKsVo::getActivation),
    Collectors.summingLong(ChuangLiangKsVo::getEventRegister)

    )
    )
    .entrySet()
    .stream()
    //将求和后的字段塞入ChuangLiangKsVo对象中
    .map(e -> new ChuangLiangKsVo对象中(e.getKey().v1, e.getValue().v1.getSum(), e.getValue().v2, e.getValue().v3,
    e.getValue().v4, e.getValue().v5, e.getValue().v6, e.getValue().v7))
    .collect(Collectors.toList());

    需要用到的包

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.jooq</groupId>
    <artifactId>jool</artifactId>
    <version>0.9.12</version>
    </dependency>
  17. stream的骚操作扩展

    代码示例路径,包含对stream的leftjoin,rightjoin,concat,partitioningby,zip

目前就用到这么多,等用到新的再补充!

资料