【问题标题】:Java 8 grouping using custom collector?使用自定义收集器的 Java 8 分组?
【发布时间】:2016-01-25 12:46:54
【问题描述】:

我有以下课程。

class Person {

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;

    public int getAge() {
        return birthday.until(IsoChronology.INSTANCE.dateNow()).getYears();
    }

    public String getName() {
        return name;
    }
}

我希望能够按年龄分组,然后收集人员姓名列表而不是 Person 对象本身;全部在一个漂亮的lamba表达式中。

为了简化所有这些,我将链接我当前的解决方案,该解决方案存储按年龄分组的结果,然后对其进行迭代以收集名称。

ArrayList<OtherPerson> members = new ArrayList<>();

members.add(new OtherPerson("Fred", IsoChronology.INSTANCE.date(1980, 6, 20), OtherPerson.Sex.MALE, "fred@example.com"));
members.add(new OtherPerson("Jane", IsoChronology.INSTANCE.date(1990, 7, 15), OtherPerson.Sex.FEMALE, "jane@example.com"));
members.add(new OtherPerson("Mark", IsoChronology.INSTANCE.date(1990, 7, 15), OtherPerson.Sex.MALE, "mark@example.com"));
members.add(new OtherPerson("George", IsoChronology.INSTANCE.date(1991, 8, 13), OtherPerson.Sex.MALE, "george@example.com"));
members.add(new OtherPerson("Bob", IsoChronology.INSTANCE.date(2000, 9, 12), OtherPerson.Sex.MALE, "bob@example.com"));

Map<Integer, List<Person>> collect = members.stream().collect(groupingBy(Person::getAge));

Map<Integer, List<String>> result = new HashMap<>();

collect.keySet().forEach(key -> {
            result.put(key, collect.get(key).stream().map(Person::getName).collect(toList()));
});

Current solution

不理想,为了学习,我希望有一个更优雅和执行的解决方案。

【问题讨论】:

    标签: java lambda java-8 java-stream collectors


    【解决方案1】:

    当使用Collectors.groupingBy 对流进行分组时,您可以使用自定义Collector 指定对值的归约操作。在这里,我们需要使用Collectors.mapping,它接受一个函数(映射是什么)和一个收集器(如何收集映射的值)。在这种情况下,映射为Person::getName,即返回人员名称的方法引用,我们将其收集到List

    Map<Integer, List<String>> collect = 
        members.stream()
               .collect(Collectors.groupingBy(
                   Person::getAge,
                   Collectors.mapping(Person::getName, Collectors.toList()))
               );
    

    【讨论】:

    • 操作,这很容易啊!干杯!
    • 在这种情况下,只有 String 存在。如果成员有 List 名称该怎么办。而且,一切都保持不变。在 Collectors.mapping 方法中需要进行哪些修改。此外,如果有任何方法在将对象作为值部分返回之前对其进行修改。例如,我需要修改名称以进行一些自定义字符串操作。
    【解决方案2】:

    您可以使用mapping CollectorPerson 列表映射到人名列表:

    Map<Integer, List<String>> collect = 
        members.stream()
               .collect(Collectors.groupingBy(Person::getAge,
                                              Collectors.mapping(Person::getName, Collectors.toList())));
    

    【讨论】:

    • 在这种情况下,只有 String 存在。如果成员有 List 名称该怎么办。而且,一切都保持不变。在 Collectors.mapping 方法中需要进行哪些修改。此外,如果有任何方法在将对象作为值部分返回之前对其进行修改。例如,我需要修改名称以进行一些自定义字符串操作。
    【解决方案3】:

    您还可以使用 Collectors.toMap 并为键、值和合并函数(如果有)提供映射。

    Map<Integer, String> ageNameMap = 
        members.stream()
                .collect(Collectors.toMap(
                  person -> person.getAge(), 
                  person -> person.getName(), (pName1, pName2) -> pName1+"|"+pName2)
        );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-04
      • 1970-01-01
      • 2016-12-21
      • 2014-06-11
      相关资源
      最近更新 更多