[英]Using the Java 8 Streams API, can sorted() be relied upon when calling Collectors.toSet()?
這是java.util.stream.Collectors
類的toSet()
方法的實現:
public static <T>
Collector<T, ?, Set<T>> toSet() {
return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
(left, right) -> { left.addAll(right); return left; },
CH_UNORDERED_ID);
}
我們可以看到,它使用HashSet
並調用add
。 從HashSet
文檔中 ,“它不能保證集合的迭代順序;特別是,它不能保證訂單在一段時間內保持不變。”
在下面的代碼,一個List
的String
是流,分類收集到Set
:
public static void main(String[] args) {
Set<String> strings = Arrays.asList("c", "a", "b")
.stream()
.sorted()
.collect(Collectors.toSet());
System.out.println(strings.getClass());
System.out.println(strings);
}
這提供了輸出:
class java.util.HashSet
[a, b, c]
輸出已排序。 我認為這里發生的事情是,盡管HashSet
文檔提供的合同規定了排序不是它提供的,但實現恰好按順序添加。 我想這可能會在未來的版本中發生變化/在JVM之間變化,而更明智的方法是做一些像Collectors.toCollection(TreeSet::new)
這樣的事情。
調用Collectors.toSet()
時可以依賴sorted()
Collectors.toSet()
嗎?
此外,“它不能保證訂單在一段時間內保持不變”究竟是什么意思? (我想add
, remove
,調整底層數組的大小?)
答案是不。 將項目添加到集合后,您不能依賴任何訂單。 來自JDK源代碼(HashSet.java):
/**
* Returns an iterator over the elements in this set. The elements
* are returned in no particular order.
*
* @return an Iterator over the elements in this set
* @see ConcurrentModificationException
*/
public Iterator<E> iterator() {
return map.keySet().iterator();
}
現在,在JDK的早期版本中,即使訂單無法保證,您通常也會以相同的插入順序獲取項目(除非對象的類實現了 要么是對象的創建順序,要么是對象上hashCode()
,然后您將獲得訂單由hashCode()
決定。hashCode()
的調用順序。 正如@Holgar在下面的評論中提到的,在HotSpot中它是后者。 你甚至不能指望它,因為這也有例外,因為序列號不是hashCode生成器中的唯一成分。
我最近聽到了Stuart Marks (負責重寫Java 9中Collections主要部分的人)的演講,他說他們已經將隨機化添加到集合的迭代順序(由新的集合工廠創建)在Java 9中。如果你想聽到會話,他談到的部分就會從這里開始 - 好的談話,強烈推薦的方式!
因此,即使您曾經依賴於集合的迭代順序,一旦轉移到Java 9,您應該停止這樣做。
總而言之,如果您需要訂購,您應該考慮使用SortedSet
, LinkedHashSet
或TreeSet
要回答這個問題,您必須了解HashSet
的實現方式。 顧名思義, HashSet
是使用哈希表實現的 。 基本上,哈希表是由元素哈希索引的數組。 散列函數(在Java中,對象的散列由object.hashCode()
計算)基本上是滿足一些條件的函數:
.equals()
彼此具有相同的哈希值 因此,當你修改一個“已排序”的HashSet
(它被理解為“迭代器保留元素的自然順序”)時,這是由於幾個巧合:
hashCode
的自然順序 如果查看String
類hashCode()
方法,您將看到對於單字母字符串,哈希代碼對應於字母的Unicode索引(代碼點) - 因此在這種特定情況下,只要哈希表是足夠小,元素將被排序。 然而,這是一個巨大的巧合
而且,這與在流上調用sorted()
的事實無關 - 它只是由於hashCode()
的實現方式,因此也是哈希表的排序。 因此,問題的簡單答案是“不”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.