Java8:关于Collectors.groupingBy返回的Map元素的顺序

时间:2018-01-25 08:26:27

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

希望就以下一段代码中的代码寻求建议。

我想知道当输入List元素序列改变时,结果Map中的输出序列是否会改变。但是,似乎输出在所有情况下都是相同的(我在IDE上重复运行程序)。我是否可以就是否可以预期生成的Map元素的顺序寻求建议? 当使用enum或String时,序列(字母/非字母?)会有任何差异,或者元素序列是随机的吗?

public class TestCountry {

    public enum Continent {ASIA, EUROPE}

    String name;
    Continent region;

    public TestCountry (String na, Continent reg) {
        name = na;
        region = reg;
    }

    public String getName () {
        return name;
    }

    public Continent getRegion () {
        return region;
    }

    public static void main(String[] args) {
        List<TestCountry> couList1 = Arrays.asList (
                new TestCountry ("Japan", TestCountry.Continent.ASIA),
                new TestCountry ("Italy", TestCountry.Continent.EUROPE),
                new TestCountry ("Germany", TestCountry.Continent.EUROPE));

        List<TestCountry> couList2 = Arrays.asList (
                new TestCountry ("Italy", TestCountry.Continent.EUROPE),
                new TestCountry ("Japan", TestCountry.Continent.ASIA),
                new TestCountry ("Germany", TestCountry.Continent.EUROPE));

        Map<TestCountry.Continent, List<String>> mapWithRegionAsKey1 = couList1.stream ()
                    .collect(Collectors.groupingBy (TestCountry ::getRegion,
                        Collectors.mapping(TestCountry::getName, Collectors.toList())));

        Map<String, List<Continent>> mapWithNameAsKey1 = couList1.stream ()
                    .collect(Collectors.groupingBy (TestCountry::getName,
                        Collectors.mapping(TestCountry::getRegion, Collectors.toList())));

        Map<TestCountry.Continent, List<String>> mapWithRegionAsKey2 = couList2.stream ()
                    .collect(Collectors.groupingBy (TestCountry ::getRegion,
                        Collectors.mapping(TestCountry::getName, Collectors.toList())));

        Map<String, List<Continent>> mapWithNameAsKey2 = couList2.stream ()
                    .collect(Collectors.groupingBy (TestCountry::getName,
                        Collectors.mapping(TestCountry::getRegion, Collectors.toList())));

        System.out.println("Value of mapWithRegionAsKey1 in couList1: " + mapWithRegionAsKey1);
        System.out.println("Value of mapWithNameAsKey1 in couList1: " + mapWithNameAsKey1);

        System.out.println("Value of mapWithRegionAsKey2 in couList2: " + mapWithRegionAsKey2);
        System.out.println("Value of mapWithNameAsKey2 in couList2: " + mapWithNameAsKey2);
    }
}

/*
 * Output:
Value of mapWithRegionAsKey1 in couList1: {ASIA=[Japan], EUROPE=[Italy, 
Germany]}
Value of mapWithNameAsKey1 in couList1: {Japan=[ASIA], Italy=[EUROPE], 
Germany=[EUROPE]}
Value of mapWithRegionAsKey2 in couList2: {ASIA=[Japan], EUROPE=[Italy, 
Germany]}
Value of mapWithNameAsKey2 in couList2: {Japan=[ASIA], Italy=[EUROPE], 
Germany=[EUROPE]}
 */

2 个答案:

答案 0 :(得分:2)

Collectors.groupingBy()目前返回HashMap。这是一个可在将来版本中更改的实现细节。

HashMap的条目未排序,但迭代的顺序(打印HashMap时)是确定性的,并且不依赖于广告订单。

因此,无论输入List中元素的顺序如何,您都会看到相同的输出。但是,您不应该依赖该顺序,因为它是一个实现细节。

如果您关心输出Map中条目的顺序,则可以修改代码以生成LinkedHashMap(默认顺序为插入顺序)或TreeMap (键分类的地方)。

BTW,如果您将输入更改为

    List<TestCountry> couList1 = Arrays.asList (
            new TestCountry ("Japan", TestCountry.Continent.ASIA),
            new TestCountry ("Italy", TestCountry.Continent.EUROPE),
            new TestCountry ("Germany", TestCountry.Continent.EUROPE));

    List<TestCountry> couList2 = Arrays.asList (
            new TestCountry ("Germany", TestCountry.Continent.EUROPE),
            new TestCountry ("Italy", TestCountry.Continent.EUROPE),
            new TestCountry ("Japan", TestCountry.Continent.ASIA)
            );

您将在输出中获得不同的顺序:

  

couList1中mapWithRegionAsKey1的值:{ASIA = [Japan],EUROPE = [ Italy,Germany ]}
  couList1中mapWithNameAsKey1的值:{Japan = [ASIA],Italy = [EUROPE],Germany = [EUROPE]}
  mapVithRegionAsKey2在couList2中的值:{ASIA = [Japan],EUROPE = [德国,意大利]}
  couList2中mapWithNameAsKey2的值:{Japan = [ASIA],Italy = [EUROPE],Germany = [EUROPE]}

这是因为单个输出List s(当前实现中为ArrayList)的元素是根据插入顺序排序的,这取决于输入的顺序List

答案 1 :(得分:2)

在质疑之前,请阅读说明文件:

  

对于返回的Map或List对象的类型,可变性,可序列化或线程安全性没有任何保证。

因此,如果你不知道返回了什么类型的地图,你就无法确定会有什么样的顺序(如果有的话)。那么,As Eran points out它是HashMap,但不保证。

问题是你为什么要关心这个?如果它用于学术目的,那么它是有道理的,如果没有,收集到确保订单的东西。

Collectors.groupingBy采用一个参数,允许您指定可能需要的实际Map实现。