我多次运行此代码(Java 11):
public static void main(String[] args) {
System.out.println("-----------------------");
Set<String> elements = Set.of("Neptunium", "Iodine", "Thallium", "Carbon", "Calcium");
System.out.println(elements);
elements = elements.stream()
.map(n -> n.substring(0, 1))
.collect(Collectors.toSet());
for (String s : elements) {
System.out.print(s);
}
}
结果是:
[Thallium, Carbon, Neptunium, Iodine, Calcium]
CTIN
-----------------------
[Thallium, Calcium, Iodine, Neptunium, Carbon]
CTIN
-----------------------
[Neptunium, Iodine, Calcium, Thallium, Carbon]
CTIN
...
第一组
Set.of("Neptunium", "Iodine", "Thallium", "Carbon", "Calcium");
的顺序是不确定的,正如我所期望的那样。然而第二个Collectors.toSet()
总是一样的。这是什么魔法?
Set.of()
没有定义的迭代顺序,并且可能会发生变化。
集合元素的迭代顺序未指定,并且可能会发生变化。
Collectors.toSet()
未定义使用哪个 Set
实现。
public static <T> Collector<T,?,Set<T>> toSet()
返回一个收集器,将输入元素累积到一个新的
中。不保证返回的 Set 的类型、可变性、可序列化性或线程安全性;如果需要对返回的Set
进行更多控制,请使用Set
。toCollection(Supplier)
目前供应商已硬编码为
HashSet::new
。但未来可能会改变。因此,如果您需要可预测的东西,最好作为供应商传递具体的 Set
实施。因为它当前返回 HashSet
并且您在创建时以相同的顺序传递元素,所以迭代每次都会根据存储桶位置以特定顺序返回数据。这就是为什么结果是一致的。
您可以使用
List
来确定元素的顺序,或者如果您需要 Set
,请使用 LinkedHashSet
。
Set<String> elements = new LinkedHashSet<>(
List.of("Neptunium", "Iodine", "Thallium", "Carbon", "Calcium"));
Set
根据定义,没有定义的遭遇顺序。因此,正如正确的aatwork的答案中所解释的,Set.of
和Collectors.toSet
都不会导致任何特定或一致的遭遇顺序。 迭代 Set
对象时,永远不要期待任何顺序。
SequencedSet
ConcurrentSkipListSet
、
LinkedHashSet
、
TreeSet
。这是一个使用 对象自然排序的示例。
SequencedSet<String> alphabeticalOrder = new TreeSet<>( List.of( "Neptunium", "Iodine", "Thallium", "Carbon", "Calcium" ) ) ;
或指定 进行自定义订购。
SequencedSet<String> orderedByLength = new TreeSet<>( Comparator.comparing( String :: length ) ) ;
orderedByLength.addAll( List.of( "Neptunium", "Iodine", "Thallium", "Carbon", "Calcium" ) ) ;
NavigableSet
SortedSet
。
Java 有两种实现:ConcurrentSkipListSet
、
TreeSet
。使用方法与上面相同:
NavigableSet<String> alphabeticalOrder = new TreeSet<>( List.of( "Neptunium", "Iodine", "Thallium", "Carbon", "Calcium" ) ) ;