我想使用Collectors.groupingBy按两列进行分组。

我写了以下内容:

public class TestGroupKey
{
    public static void main(String... args) {
        List<Item> list = Arrays.asList(
            new Item(1, 1, 1),
            new Item(1, 1, 2),
            new Item(1, 1, 3),
            new Item(1, 2, 1),
            new Item(1, 2, 2),
            new Item(2, 1, 1),
            new Item(2, 2, 1),
            new Item(2, 3, 1),
            new Item(2, 4, 1),
            new Item(2, 4, 2),
            new Item(2, 4, 3),
            new Item(2, 4, 4),
            new Item(3, 1, 1),
            new Item(3, 1, 2),
            new Item(3, 1, 3),
            new Item(3, 1, 4),
            new Item(3, 2, 1),
            new Item(3, 2, 2)
        );

        Map<CustomKey, List<Item>> tupleGrouping =
            list.stream().collect(Collectors.groupingBy(item -> item.customKey));
        tupleGrouping.entrySet().stream()
                .forEach(entry -> {
                    System.out.println(entry.getKey());
                });
    }

    public static class Item {
        public int topLevelId;
        public int secondLevelId;
        public int itemId;
        public CustomKey customKey;

        public Item(int topLevelId, int secondLevelId, int itemId) {
            this.topLevelId = topLevelId;
            this.secondLevelId = secondLevelId;
            this.itemId = itemId;
            this.customKey = new CustomKey(topLevelId, secondLevelId);
        }

        @Override
        public String toString() {
            return String.format("%d%d%d", this.topLevelId, this.secondLevelId, this.itemId);
        }
    }

    public static class CustomKey {
        public int topLevelId;
        public int secondLevelId;

        public CustomKey(int topLevelId, int secondLevelId) {
            this.topLevelId = topLevelId;
            this.secondLevelId = secondLevelId;
        }

        @Override
        public String toString() {
            return String.format("%d%d", this.topLevelId, this.secondLevelId);
        }
    }
}

预期结果是
11
12
21
22
23
24
31
32

但是实际结果是
24
31
23
22
12
21
24
31
31
24
12
32
32
11
11
11
31

我认为groupingBy无法正常工作。

我对CustomKey类的使用有什么问题?

此外,嵌套的地图关键字正在工作:
Map<Integer, Map<Integer, List<Item>>> entryGrouping =
    list.stream()
        .collect(Collectors.groupingBy(atta1 -> atta1.topLevelId,
                                       Collectors.groupingBy(atta2 -> atta2.secondLevelId)));

最佳答案

您的CustomKey类不会覆盖Objectequals方法,因此groupingBy仅将两个CustomKey视为相同的对象时才认为它们相等(在您的示例中从不成立,因为您为每个CustomKey创建了一个新的Item实例)。

public static class CustomKey {
    ...
    @Override
    public int hashCode ()
    {
        // if you override equals, you should also override hashCode
    }

    @Override
    public boolean equals (Object other)
    {
        if (other == this)
            return true;
        if (!(other instanceof CustomKey))
            return false;
        CustomKey okey = (CustomKey) other;
        return this.topLevelId == okey.topLevelId && this.secondLevelId == okey.secondLevelId;
    }
    ...
}

09-15 23:44