Java8:关于Collectors.groupingBy返回的Map元素的顺序
Java8: About order of Map elements returned by Collectors.groupingBy
想请教一下遇到的例子修改的下面这段代码
我想知道当输入的List元素序列发生变化时,结果Map中的输出序列是否会发生变化。但是,似乎所有情况下的输出都是相同的(我在 IDE 上重复 运行 程序)。我可以就生成的 Map 元素的顺序是否可以预期寻求建议?
使用 enum 或 String 时,序列是否会有任何差异(alphabetical/non-alphbetical?),或者元素序列只是随机的?
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]}
*/
Collectors.groupingBy()
目前 returns 一个 HashMap
。这是在未来版本中可能会更改的实现细节。
HashMap
的条目未排序,但它们的迭代顺序(打印 HashMap
时)是确定的,不依赖于插入顺序。
因此,无论输入中元素的顺序如何,您都会看到相同的输出 List
。不过,您不应该依赖该顺序,因为它是一个实现细节。
如果您关心输出中条目的顺序 Map
,您可以修改代码以生成 LinkedHashMap
(默认顺序为插入顺序)或 TreeMap
(键排序的地方)。
顺便说一句,如果您将输入更改为
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)
);
您将在输出中得到不同的顺序:
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=[Germany, Italy]}
Value of mapWithNameAsKey2 in couList2: {Japan=[ASIA], Italy=[EUROPE], Germany=[EUROPE]}
这是因为单个输出 List
s(在当前实现中是 ArrayList
s)的元素是根据插入顺序排序的,插入顺序取决于你的输入 List
.
在质疑这个之前,请阅读文档,内容如下:
There are no guarantees on the type, mutability, serializability, or thread-safety of the Map or List objects returned.
因此,如果您无法判断返回的 Map 的类型,您就无法真正判断将以何种顺序(如果有)。那么目前, 是 HashMap
,但这并不能保证。
问题是你为什么要关心这个?如果是出于学术目的,那是有道理的,如果不是,收集到一些确实保证顺序的东西。
Collectors.groupingBy
接受一个参数,允许您指定您可能需要的实际 Map
实现。
想请教一下遇到的例子修改的下面这段代码
我想知道当输入的List元素序列发生变化时,结果Map中的输出序列是否会发生变化。但是,似乎所有情况下的输出都是相同的(我在 IDE 上重复 运行 程序)。我可以就生成的 Map 元素的顺序是否可以预期寻求建议? 使用 enum 或 String 时,序列是否会有任何差异(alphabetical/non-alphbetical?),或者元素序列只是随机的?
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]}
*/
Collectors.groupingBy()
目前 returns 一个 HashMap
。这是在未来版本中可能会更改的实现细节。
HashMap
的条目未排序,但它们的迭代顺序(打印 HashMap
时)是确定的,不依赖于插入顺序。
因此,无论输入中元素的顺序如何,您都会看到相同的输出 List
。不过,您不应该依赖该顺序,因为它是一个实现细节。
如果您关心输出中条目的顺序 Map
,您可以修改代码以生成 LinkedHashMap
(默认顺序为插入顺序)或 TreeMap
(键排序的地方)。
顺便说一句,如果您将输入更改为
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)
);
您将在输出中得到不同的顺序:
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=[Germany, Italy]}
Value of mapWithNameAsKey2 in couList2: {Japan=[ASIA], Italy=[EUROPE], Germany=[EUROPE]}
这是因为单个输出 List
s(在当前实现中是 ArrayList
s)的元素是根据插入顺序排序的,插入顺序取决于你的输入 List
.
在质疑这个之前,请阅读文档,内容如下:
There are no guarantees on the type, mutability, serializability, or thread-safety of the Map or List objects returned.
因此,如果您无法判断返回的 Map 的类型,您就无法真正判断将以何种顺序(如果有)。那么目前,HashMap
,但这并不能保证。
问题是你为什么要关心这个?如果是出于学术目的,那是有道理的,如果不是,收集到一些确实保证顺序的东西。
Collectors.groupingBy
接受一个参数,允许您指定您可能需要的实际 Map
实现。