2017-04-10 20 views
3

我有一個包含大量元素的列表。在處理這個列表時,在某些情況下,我希望將列表分割成更小的子列表,並且在某些情況下我想處理整個列表。Java:創建用於處理的列表塊

private void processList(List<X> entireList, int partitionSize) 
{ 
    Iterator<X> entireListIterator = entireList.iterator(); 
    Iterator<List<X>> chunkOfEntireList = Iterators.partition(entireListIterator, partitionSize); 
    while (chunkOfEntireList.hasNext()) { 
     doSomething(chunkOfEntireList.next()); 
     if (chunkOfEntireList.hasNext()) { 
      doSomethingOnlyIfTheresMore(); 
     } 
    } 

我使用com.google.common.collect.Iterators創建分區。所以在這裏我要分區大小爲100名單的情況下文檔here 的鏈接,我叫

processList(entireList, 100); 

現在,當我不想創建列表的塊,我想我可以通過整型。 MAX_VALUE作爲partitionSize。

processList(entireList, Integer.MAX_VALUE); 

但是,這導致我的代碼出去的內存。有人可以幫我嗎?我錯過了什麼?什麼是迭代器在內部做什麼,我該如何克服這一點?

編輯:我還需要內部的「if」子句做些事情,只有當有更多的列表要處理。即我需要迭代器的hasNext()函數。

回答

6

因爲Iterators.partition()內部使用給定的分區長度填充數組,所以出現內存不足錯誤。分配的數組始終是分區大小,因爲在迭代完成之前,元素的實際數量是未知的。 (本來是可以避免的問題,如果他們已經在內部使用的ArrayList;我猜的設計師決定,陣列將提供在通常情況下更好的性能。)

使用Lists.partition()將避免這個問題,因爲它委託給List.subList(),這是隻有基礎列表的視圖

private void processList(List<X> entireList, int partitionSize) { 
    for (List<X> chunk : Lists.partition(entireList, partitionSize)) { 
     doSomething(chunk); 
    } 
} 
0

正常情況下,分區時會爲給定的partitionSize分配一個新的列表。所以在這種情況下顯然會出現這樣的錯誤。當您只需要單個分區時,爲什麼不使用原始列表?可能的解決方案。

  1. 創建一個單獨的重載方法,你不會拿大小。
  2. 當您不需要任何分區時,將大小傳遞爲-1。在方法中檢查值,如果-1則將原始列表放入chunkOfEntireList,。
+0

我認爲這樣做。但是這讓我的代碼變得非常難看。除了Iterators.partition()之外,還有其他解決方案可以嘗試嗎? –

+0

你可以創建一個partiotion方法..然後在那個方法中你可以實現任何2個建議的解決方案。它不會讓代碼變得醜陋 – stinepike

0

假設你正在試圖通過並行處理列表的塊來解決並行性,它可能是更好的考慮類似的MapReduce,或者星火作爲一個更大的框架包括流程管理。

然而,作爲整體應用程序的一部分,您可以考慮節點本地變體 - 包括可能的Java 8 Streams。請注意您的List<X>也提供parallelStream()方法。