簡體   English   中英

用於過濾Java流的最有效的收集?

[英]Most efficient collection for filtering a Java Stream?

我將幾個Thing存儲在一個Collection中。 單個Thing是唯一的,但它們的類型不是唯一的。 它們的存儲順序也無關緊要。

我想使用Java 8的Stream API來通過以下代碼搜索它的特定類型:

Collection<Thing> things = ...;
// ... populate things ...
Stream<Thing> filtered = things.stream.filter(thing -> thing.type.equals(searchType));

是否有一個特定的Collection可以使filter()更有效率?

我傾向於不認為,因為過濾器必須遍歷整個集合。

另一方面,如果集合是由Thing.type索引的某種樹,則filter()可能能夠利用這一事實。 有什么辦法可以做到這一點?

諸如filter之類的流操作並非專門用於在特殊情況下發揮優勢。 例如, IntStream.range(0, 1_000_000_000).filter(x -> x > 999_999_000)實際上將迭代所有輸入數字,它不能僅“跳過”前999_999_000。 因此,您的問題就減少了,以找到最高效的迭代集合。

通常在Spliterator.forEachRemaining方法(對於非短路流)和Spliterator.tryAdvance方法(對於短路流)中執行迭代,因此您可以查看相應的splitter實現並檢查其效率如何。 。 在我看來,最有效的方法是數組(通過Arrays.asList裸或包裝到列表中):它的開銷最小。 ArrayList也相當快,但是對於短路操作,它將在每次迭代時檢查modCount (以檢測並發修改),這會增加非常小的開銷。 HashSetLinkedList類的其他類型的速度相對較慢,盡管在大多數應用程序中,這種差異實際上是微不足道的。

請注意,應謹慎使用並行流。 例如, LinkedList的拆分非常差,與連續情況相比,您可能會遇到較差的性能。

關於這個問題,最重要的要理解的是,當您將lambda表達式傳遞給特定的庫(例如Stream API)時,該庫收到的所有內容都是功能接口的實現,例如Predicate的實例。 它不知道該實現將執行的操作,因此無法利用諸如通過比較過濾排序的數據之類的方案。 流庫根本不知道Predicate在進行比較。

實現這種優化的實現需要了解和理解代碼的JVM和了解語義的庫的交互。 至少在我看來,這種事情在當前的實現中不會發生,並且目前還很遙遠。

如果源是樹或排序列表,並且您希望從中受益,以進行過濾,則在創建流之前,必須使用對源進行操作的API進行處理。 例如,假設我們有一個TreeSet並希望對其進行過濾以獲取特定范圍內的項目,例如

// our made-up source
TreeSet<Integer> tree=IntStream.range(0, 100).boxed()
    .collect(Collectors.toCollection(TreeSet::new));
// the naive implementation
tree.stream().filter(i -> i>=65 && i<91).forEach(i->System.out.print((char)i.intValue()));

我們可以改為:

tree.tailSet(65).headSet(91).stream().forEach(i->System.out.print((char)i.intValue()));

這將利用排序/樹的性質。 當我們有一個排序列表時,說

List<Integer> list=new ArrayList<>(tree);

利用排序的性質更加復雜,因為集合本身不知道它是經過排序的,並且不提供直接利用該性質的操作:

int ix=Collections.binarySearch(list, 65);
if(ix<0) ix=~ix;
if(ix>0) list=list.subList(ix, list.size());
ix=Collections.binarySearch(list, 91);
if(ix<0) ix=~ix;
if(ix<list.size()) list=list.subList(0, ix);
list.stream().forEach(i->System.out.print((char)i.intValue()));

當然,這里的流操作僅是示例性的,當您要做的只是forEach時,您根本不需要流。

據我所知,普通流媒體沒有這種區別。

但是,當您使用易於設計的集合(例如,LinkedList上的ArrayList或任何類型的Set)使用並行流時,可能會更好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM