在 java 8 中按多个字段名称分组

新手上路,请多包涵

我从 POJO 中找到了按某个字段名称对对象进行分组的代码。下面是代码:

 public class Temp {

    static class Person {

        private String name;
        private int age;
        private long salary;

        Person(String name, int age, long salary) {

            this.name = name;
            this.age = age;
            this.salary = salary;
        }

        @Override
        public String toString() {
            return String.format("Person{name='%s', age=%d, salary=%d}", name, age, salary);
        }
    }

    public static void main(String[] args) {
        Stream<Person> people = Stream.of(new Person("Paul", 24, 20000),
                new Person("Mark", 30, 30000),
                new Person("Will", 28, 28000),
                new Person("William", 28, 28000));
        Map<Integer, List<Person>> peopleByAge;
        peopleByAge = people
                .collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p, toList())));
        System.out.println(peopleByAge);
    }
}

输出是(正确的):

 {24=[Person{name='Paul', age=24, salary=20000}], 28=[Person{name='Will', age=28, salary=28000}, Person{name='William', age=28, salary=28000}], 30=[Person{name='Mark', age=30, salary=30000}]}

但是如果我想按多个字段分组怎么办?我显然可以在 groupingBy() 方法中传递一些 POJO 实现 equals() POJO 中的方法,但是是否有任何其他选项,比如我可以按给定 POJO 中的多个字段分组?

例如,在我的例子中,我想按姓名和年龄分组。

原文由 Mital Pritmani 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 322
1 个回答

您在这里有几个选择。最简单的是链接你的收集器:

 Map<String, Map<Integer, List<Person>>> map = people
    .collect(Collectors.groupingBy(Person::getName,
        Collectors.groupingBy(Person::getAge));

然后要获得名为 Fred 的 18 岁人员的列表,您可以使用:

 map.get("Fred").get(18);

第二种选择是定义一个代表分组的类。这可以在 Person 内部。此代码使用 record 但它可以很容易地成为一个类(在 J35 的版本中添加 equalshashCode 定义):

 class Person {
    record NameAge(String name, int age) { }

    public NameAge getNameAge() {
        return new NameAge(name, age);
    }
}

然后你可以使用:

 Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));

并搜索

map.get(new NameAge("Fred", 18));

最后,如果您不想实现自己的组记录,那么周围的许多 Java 框架都有一个 pair 专为此类事物设计的类。例如: apache commons pair 如果您使用这些库中的一个,那么您可以将地图的键设为一对姓名和年龄:

 Map<Pair<String, Integer>, List<Person>> map =
    people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));

并检索:

 map.get(Pair.of("Fred", 18));

就我个人而言,我并没有真正看到通用元组有多大价值,因为记录可以在语言中使用,因为记录可以更好地显示意图并且需要很少的代码。

原文由 sprinter 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏