2009-08-06 88 views
0

這是一個Java問題。將列表<?>轉換爲列表的最快方式<ObjectType>

什麼是將List<?>轉換爲List<ObjectType>的最快方法?我知道這是可能的迭代,請排除該選項。

實施例通過迭代,

final List<ObjectType> targetList = new ArrayList<ObjectType>(); 
// API returns List<?> so I have no choice. 
List<?> resultList = resultSet.getResults(); 

// This is slow. Average list size is 500,000 elements. 
while (resultList != null && !resultList.isEmpty()) { 
    for (final Object object : resultList) { 
     final ObjectType objectType = (ObjectType) object; 
     targetList.add(objectType); 
    } 
    resultSet = someService.getNext(resultSet); 
    resultList = resultSet.getList(); 
} 

感謝。

+1

由於您使用的是基於陣列的列表,你嘗試過預分配500000元(或約儘可能多的?)。這可能會提高性能。 – 2009-08-06 04:09:36

+0

現在我想到了,LinkedList將完全消除整個「預分配內存」問題。 – 2009-08-06 04:12:52

+1

是否有東西從'resultList'移除元素,或者'while'應該是'if'? – 2009-08-06 04:30:37

回答

5

這是一個有點嚇人,但根據上下文,你可能只用鑄造脫身:

final List<ObjectType> targetList = (List<ObjectType>)problemSolver.getResults(); 
+0

我也會去解決這個問題。 – 2009-08-06 04:33:12

+0

通常,這不是類型安全的。 – 2010-08-23 14:35:31

+0

這是正確的,但考慮到API不能被使用。 – Tom 2010-08-25 16:45:54

1

嗯......如果你真的處理500,000元和expreriencing性能問題,我硬着頭皮(子彈是編譯器的「未登記」的警告),並投它:

List<ObjectType> targetList = new ArrayList<ObjectType>((List<ObjectType>) resultList); 

你然後可以使用@SuppressWarnings(「unchecked」)註釋來抑制警告。

以上是當然,假設​​不以某種方式滿足你(也許它是不可修改或陣列支持或你有什麼)。否則,你可以簡單地施放它。

1

正確的解決方案取決於您是否要確保你投入targetList元素真的是ObjectType實例(或一個子類型)。

如果你不在乎,一個帶有不安全類型轉換的解決方案將會執行。除非你需要複製,@Toms解決方案更好。 (如果getResults()返回一個鏈表,並且您的算法需要使用targetList.get(int),則可能需要複製。)但請注意,如果您的假設不正確,稍後可能會收到意外的ClassCastException

如果您需要確保沒有錯誤類型的元素,那麼您必須使用基於迭代器的解決方案,除非您知道getResults()爲您提供哪種類型的List類型。 (如果你都可以投射到getResults()ArrayList結果,然後使用get(int)索引應該比使用Iterator更快。在另一方面,如果結果是一個LinkedList,然後使用get(int)複製的清單是O(N**2) !!)

這個怎麼樣?

final List<?> resultList = problemSolver.getResults(); 

List<ObjectType> targetList; 
if (resultList == null || resultList.isEmpty()) { 
    targetList = Collections.empyList(); 
} else { 
    int len = resultList.size(); 
    // it is important to preallocate the ArrayList with the 
    // right size ... to conserve space and avoid copy on realloc 
    // of the list's private backing array. 
    targetList = new ArrayList<ObjectType>(len); 
    if (resultList instanceof ArrayList) { 
     // Copy using indexing - O(N) for ArrayLists 
     ArrayList<?> arrayList = (ArrayList) resultList; 
     for (int i = 0; i < len; i++) { 
      targetList.add((ObjectType) (arrayList.get(i))); 
     } 
    } else { 
     // Copy using iterator - O(N) for all sane List implementations, 
     // but with a larger C than the best case for indexing. 
     for (Object obj : resultList) { 
      targetList.add((ObjectType) obj); 
     } 
    } 
} 
0

迭代有什麼問題?

但如你所願:

final List<?> src = ...; 
final int len = src.size(); 
final SomeType[] dstArray = new SomeType[len]; 
src.<SomeType>toArray(dstArray); 
final List<SomeType> dst = java.util.Arrays.asList(dstArray); 

或者:

我更喜歡迭代法(免責聲明與其說是編譯。)。

+0

嗯.. 。不'src.toArray()'創建一個副本?所以你最終雙重複制。 – 2009-08-06 07:46:40

+0

是的,雖然這不應該是事物的計劃中的一個大問題(仍然比'LinkedList'!更好!)。我忘記了帶有參數的'toArray'具有奇怪的界限。 – 2009-08-06 07:55:32

2

當湯姆上面說的,如果你知道一個事實,即一切都在原來的List<?>ObjectType - 通過迭代代碼暗示 - 鑄造List<ObjectType>會工作得很好。

從迭代碼的唯一區別是,如果有什麼的ObjectType,在迭代碼,當你填充targetList,在ClassCastException會發生,而與直投,它會在你」發生重新獲得價值。例如: -

public static void main(String[] args) { 
    List<?> list = Arrays.<Object> asList('I', "am", "not", "homogeneous"); 
    List<Character> targetList = (List<Character>) list; 

    int index = 0; 
    try { 
     for (Character c : targetList) { 
      System.out.println(c); 
      index++; 
     } 
    } finally { 
     System.out.println("Reached " + index); 
    } 
} 

打印

I 
Exception in thread "main" java.lang.ClassCastException: java.lang.String 
cannot be cast to java.lang.Character 
    at Foo.main(Foo.java:100) 
Reached 1 
相關問題