web-dev-qa-db-fra.com

Pourquoi ne pouvez-vous pas avoir "List <List <String >>" en Java?

En Java, pourquoi la ligne de code suivante ne fonctionne-t-elle pas?

List<List<String>> myList = new ArrayList<ArrayList<String>>();

Cela fonctionne si je le change en

List<ArrayList<String>> myList = new ArrayList<ArrayList<String>>();

Au début, je pensais que vous ne pouviez peut-être pas avoir de listes d’interface, mais je peux créer un List<Runnable> très bien.

Des idées?

28
Nosrettap

Les types génériques sont plus pédants.

List signifie List ou tout sous-type, mais <List> signifie seulement List. Si vous voulez un sous-type, vous devez avoir <? extends List>

Je suppose que vous pouvez utiliser

List<List<String>> myList = new ArrayList<List<String>>();

La raison pour laquelle vous ne pouvez pas faire cela est que vous pouvez utiliser une référence à une référence et avec un niveau d'indirection supplémentaire, vous devez faire attention.

// with one level of indirection its simple.
ArrayList alist = new ArrayList();
List list = aList; // all good
list = new LinkedList(); // alist is still good.

Avec les génériques, vous pouvez avoir deux niveaux d'indirection qui peuvent vous donner des problèmes, donc ils sont plus pédants pour éviter ces problèmes.

// with two levels of indirection
List<ArrayList> alist = new ArrayList<ArrayList>();
List<List> list = (List) alist; // gives you a warning.
list.add(new LinkedList()); // adding a LinkedList into a list of ArrayList!!
System.out.println(alist.get(0)); // runtime error

empreintes

Exception in thread "main" Java.lang.ClassCastException: Java.util.LinkedList
     cannot be cast to Java.util.ArrayList
42
Peter Lawrey

Commençons par ceci:

    ArrayList<ArrayList<String>> myList = new ArrayList<ArrayList<String>>();

Cela crée un ArrayList dont les éléments sont ArrayLists.

Supposons maintenant que nous puissions attribuer cela à 

    List<List<String>> myList2 = myList.

Maintenant, nous devrions pouvoir faire ceci:

    myList2.add(new LinkedList<String>());

Mais cela signifie que nous avons ajouté une liste LinkedList à une liste dont les éléments sont supposés être ArrayLists. Ooops !!!

En réalité, l'attribution de myList à myList2 n'est pas légale ... et cela garantit qu'il n'est pas possible d'ajouter le mauvais type de List<String> à l'objet ArrayList<ArrayList<String>>. (Non Peter, ce n'est pas juste pédantisme :-))

9
Stephen C

Seule la collection de niveau supérieur peut être déclarée en tant que classe d'implémentation, tandis que celles imbriquées doivent rester des interfaces jusqu'à ce que vous créiez des instances:

List<List<String>> rootList = new ArrayList<List<String>>(); 

et ensuite, lorsque vous créez un élément à intégrer, vous en faites une implémentation:

List<String> nodeList = new ArrayList<String>();
rootList.add(nodeList);
3
amphibient

Sa comparaison Type du côté gauche (déclaration) au Type du côté droit (instanciation). À gauche, votre type est List<String> alors qu'à droite, c'est ArrayList<String>. Si se plaindre de la différence.

Veuillez mettre à jour le côté droit (instatiation) en tant que Liste i.e. 

   List<List<String>> myList = new ArrayList<List<String>>();

Cela devrait bien fonctionner.

1
Yogendra Singh

list<list<string>> l1=new list<list<string>>(); est autorisé si la liste en contient une autre.

public final class CPanelXMLBuilder extends PanelXMLBuilder {

    public CPanelXMLBuilder(AuthenticatedUser pAuthenticatedUser, Map<String, Object> pSessionMap, Map<String, Object> pRequestMap, String pPanelTemplate) throws Exception {
        super(pAuthenticatedUser, pSessionMap, pRequestMap, pPanelTemplate, null);
    }

    public Map<String, Object> buildXMLDocument(List<List<String>> pDetailsList) {

        if (pDetailsList.size() == 1) {
            List<String> pCustomerDetail = pDetailsList.get(0);
            xmlDocument.getRootElement().getChild("E_SHOW1").setText(pCustomerDetail.get(0));
            xmlDocument.getRootElement().getChild("E_SHOW2").setText(pCustomerDetail.get(1));
            xmlDocument.getRootElement().getChild("E_SHOW3").setText(pCustomerDetail.get(2));
            xmlDocument.getRootElement().getChild("E_SHOW4").setText(pCustomerDetail.get(3));
            xmlDocument.getRootElement().getChild("E_SHOW5").setText(pCustomerDetail.get(4));
            xmlDocument.getRootElement().getChild("ServerTimestamp").setText(pCustomerDetail.get(5).substring(0, 19));
        } else {
            xmlDocument.getRootElement().getChild("AlertType").setText("INFO");
            xmlDocument.getRootElement().getChild("Alert").setText("There is no matching record.");
        }

        requestMap.put(RequestMapKeys.XML_DOCUMENT, xmlDocument);

        return requestMap;
    }

}
0
baswaaj

Je sais que c'est une vieille question mais je voulais juste partager mon idée.

Au lieu de faire une liste de listes, je fais personnellement une liste de type [] (List<Type[]> listArray = new ArrayList<Type[]>();), je génère une liste distincte de type (List<Type> list = new ArrayList<Type>();), puis .add(list.toArray()). De cette façon, il est plus clair et facile à lire que la syntaxe List of Lists, qui prête à confusion.

Par exemple, dans un projet récent où j'avais un fichier d'entrée où chaque ligne avec seulement un "0" signifiait une nouvelle ligne dans l'original (c'était un algorithme de cryptage):

String[] input = getInputContents(inFile);
List<String> currentBuffer = new ArrayList<String>();
List<String[]> buffers = new ArrayList<String[]>();

for(String line : input) {
    if(line.equals("0")) {
        buffers.add((String[])currentBuffer.toArray());
        currentBuffer = new ArrayList<String>();
    } else {
        currentBuffer.add(line);
    }
}
0
RyanBreaker