2009-08-06 7 views
0

Ceci est une question Java.Le moyen le plus rapide de convertir la liste <?> en Liste <ObjectType>

Quel est le moyen le plus rapide de convertir un List<?> en un List<ObjectType>? Je suis conscient que cela est possible grâce à l'itération, veuillez exclure cette option.

Exemple par itération,

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(); 
} 

Merci.

+1

Puisque vous utilisez une liste basée sur la baie, vous avez essayé de pré-allouer 500.000 éléments (ou à peu près autant?). Cela peut donner un coup de pouce de performance. –

+0

Maintenant que j'y pense, une LinkedList éliminerait complètement tout le problème de "mémoire pré-allouée". –

+1

Y a-t-il quelque chose qui supprime des éléments de 'resultList', ou est-ce que' while' est supposé être un 'if'? –

Répondre

5

Il est un peu effrayant, mais selon le contexte que vous pourriez peut-être sortir avec juste la coulée:

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

Je voudrais aller avec cette solution aussi, pour ce problème. –

+0

En général, ce n'est pas sécurisé. –

+0

C'est correct, mais étant donné que l'API est consommée, elle ne peut pas l'être. – Tom

1

Umm ... si vous êtes vraiment affaire avec 500.000 éléments et expreriencing un problème de performance, je mords la balle (l'avertissement « sans contrôle » de balle étant compilateur) et de le jeter:

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

Vous peut alors utiliser l'annotation @SuppressWarnings ("non cochée") pour supprimer l'avertissement. Ce qui précède est, bien sûr, en supposant que resultList ne vous satisfait pas d'une certaine manière (peut-être c'est non modifiable ou tableau-soutenu ou quoi que vous avez). Sinon, vous pouvez simplement le lancer.

1

La bonne solution dépend si vous voulez vous assurer que les éléments que vous mettez dans targetList sont vraiment des cas de ObjectType (ou un sous-type).

Si cela ne vous intéresse pas, l'une des solutions avec un classeur non sécurisé fera l'affaire. Sauf si vous avez besoin de copier, la solution @Toms est meilleure. (Vous devrez peut-être copier si getResults() renvoie une liste liée et votre algorithme doit utiliser beaucoup targetList.get(int).) Mais attention, vous risquez d'obtenir un ClassCastException plus tard si vos hypothèses sont incorrectes. Si vous avez besoin d'être sûr qu'il n'y a pas d'éléments du mauvais type, alors vous devez utiliser une solution basée sur l'itérateur à moins de savoir quel type de List le type getResults() vous donne. (Si vous pouvez lancer le résultat de getResults()-ArrayList, puis l'indexation à l'aide get(int) devrait être plus rapide que d'utiliser un Iterator. D'autre part, si le résultat est un LinkedList, puis en utilisant get(int) pour copier la liste est O(N**2) !!)

Que pensez-vous de cela?

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

Quel est le problème avec l'itération?

Mais comme vous le souhaitez:

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); 

Ou:

:

Je préfère la méthode itération (Avertissement Pas tant que compilé.).

+0

Umm .. n'est pas 'src.toArray()' créer une copie? Donc vous finissez par copier deux fois. –

+0

Oui, bien que cela ne devrait pas être un énorme problème dans le régime des choses (encore mieux que 'LinkedList'!). J'ai oublié le 'toArray' avec l'argument a des limites étranges. –

2

Comme Tom dit plus haut, si vous savez pertinemment que tout dans l'List<?> d'origine est un ObjectType - comme le laisse entendre le code d'itération - coulée à List<ObjectType> fonctionnera très bien.

La seule différence à partir du code d'itération est que, si quelque chose de pas un ObjectType, dans le code d'itération la ClassCastException se produira lorsque vous peuplant targetList, alors qu'avec le casting droite, ça va se produire lorsque vous » re faire sortir les valeurs. .:

par exemple
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); 
    } 
} 

impressions

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 
Questions connexes