IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Collection et Stream Java Discussion :

Investigations sur la méthode Arrays.asList()


Sujet :

Collection et Stream Java

  1. #1
    Rédacteur
    Avatar de CyberChouan
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    2 752
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 752
    Par défaut Investigations sur la méthode Arrays.asList()
    J'utilise un service externe qui me renvoi un tableau d'objets. J'ai ensuite besoin de travailler sur ces données (ajout, suppression...). Je pense donc tout naturellement à transformer ce tableau en liste, bien plus facile à manipuler de manière "objet".

    Je regarde donc si cette transformation n'est pas déjà fournie par Sun, pour ne pas réinventer la roue: bingo! Je tombe sur la méthode statique Arrays.asList(), que j'ajoute à mon code rapidement sans trop regarder plus loin.

    Et c'est là que les soucis commencent... lorsque je veux supprimer des données de cette liste. Voici une simplification de ma méthode:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public removeObject(List l) {
       Iterator i = l.iterator();
       while(i.hasNext()) {
          if(estASupprimer(i.next())) {
             i.remove();
          }
       }
    }
    Jusque là, rien de choquant... (du moins j'espère). Si ce n'est que... ça ne marche pas avec une liste obtenue par Arrays.asList(): UnsupportedOperationException

    En investiguant, j'ai trouvé l'explication:
    Arrays.asList() renvoie une ArrayList... mais pas une java.util.ArrayList comme on a l'habitude de les utiliser. Elle renvoie une instance d'une classe interne: Arrays$ArrayList.

    L'explication est donnée dans la javadoc: cette classe donne une liste de taille fixe (pas de méthodes add(), remove(), ...). Le tableau passé en paramètre à la création de la liste reste lié à celle-ci, et toute modification de la liste modifie en même temps le tableau associé. C'est cette contrainte qui impose la taille fixe.

    Soit... mais bilan: je n'ai pas trouvé de classe native de Sun fournissant une méthode pour créer une liste à partir du tableau, tout en me permettant de manipuler librement celle-ci par la suite.

    Si je n'ai pas suffisamment cherché, merci de me corriger.

    Note: inutile de chercher... ce post ne contient pas de question (j'ai trouvé l'explication de mon unsupportedOperationException en lisant la javadoc). Ce post est juste là afin d'éviter que d'autres personnes ne fassent la même bétise que moi, en croyant (au père Noël) gagner du temps à ne pas lire comment se comporte une classe avant de l'utiliser.

    PS: oui, il m'arrive encore parfois de rêver que des personnes feront une recherche avant de poster une question...

    Moralité:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public static List getTrueListFromFalseList(List l) {
       return new ArrayList(l); // ou LinkedList au choix
    }
    Avant de poster, pensez à regarder la FAQ, les tutoriaux, la Javadoc (de la JRE que vous utilisez) et à faire une recherche
    Je ne réponds pas aux questions techniques par MP: les forums sont faits pour ça
    Mes articles et tutoriaux & Mon blog informatique

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,



    Si tu veux manipuler une vrai liste il faut que tu la crées :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    	List<String> list = new ArrayList<String>( Arrays.asList(array) );
    Ou mieux (on évite une classe intermédiaire) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	List<String> list = new ArrayList<String>();
    	Collections.addAll(list, array);

    Je rappelle juste que la plupart des méthodes de l'interface Collection (et de ses sous-interfaces) sont optionnelles : il n'y a rien de choquant à ce qu'elle ne soit pas implémenté

    a++

  3. #3
    Rédacteur
    Avatar de CyberChouan
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    2 752
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 752
    Par défaut
    Oui, merci. C'est également la conclusion à laquelle j'étais arrivé
    Avant de poster, pensez à regarder la FAQ, les tutoriaux, la Javadoc (de la JRE que vous utilisez) et à faire une recherche
    Je ne réponds pas aux questions techniques par MP: les forums sont faits pour ça
    Mes articles et tutoriaux & Mon blog informatique

  4. #4
    Membre chevronné
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    442
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 442
    Par défaut
    Juste pour ajouter une remarque sans grand intérêt :

    Ce qui me pose vraiment problème avec le parcours des collections Java, c'est la méthode "remove" de Iterator qui throw une UnsupportedOperationException sur les objets pour lesquels elle ne peut s'appliquer.

    Je trouve que c'est un gros problème de conception que d'offrir des fonctionnalités qui seront interdite à l'exécution, je ne comprends pas pourquoi il n'a pas été conçu un Iterator en lecture/seule et un Iterator en lecture/suppression...

    Enfin bon, a priori ça ne va pas être revu tout de suite alors il va falloir s'y faire ou créer ses propres itérateurs en attendant...

  5. #5
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Parce que ce problème ne se retrouve pas seulement pour la méthode remove() de l'iterator. Plusieurs méthodes des collections sont en effet optionnelles !



    Déjà si on duplique l'interface Iterator afin d'avoir un ReadOnlyIterator il faudrait dupliquer aussi l'interface Collection et toutes ses sous interfaces, pour distinguer les Collections qui utiliserait un Iterator des "ReadOnlyCollections" qui utiliserait un ReadOnlyIterator...

    Si on ajoute à cela les méthodes optionnelles de l'interface Collection (add(), addAll(), remove(), removeAll(), retainAll(), clear()) il faudrait déjà 8 interfaces différentes... ce qui n'est pas forcément mieux que la solution actuelle...


    je ne sais pas s'il existe un pattern "propre" pour gérer des méthodes optionnelles...

    a++

  6. #6
    Membre chevronné
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    442
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 442
    Par défaut
    On pourrait envisager Iterator extends ReadOnlyIterator et Collection extends ReadOnlyCollection, cela ne me choque pas du tout...

    Mais bon les 2 points de vue son discutables, après c'est une question de goût et surtout de compromis

  7. #7
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Duc Lebowski Voir le message
    On pourrait envisager Iterator extends ReadOnlyIterator et Collection extends ReadOnlyCollection, cela ne me choque pas du tout...
    Oui je suis d'accord avec toi sur le principe, mais il aurait également fallu faire cela pour toutes les méthodes optionnelles de Collection, ce qui aurait multiplier le nombre d'interface surtout si l'on souhaite différencier les méthodes une à une (on pourrait vouloir implémenter add() mais pas addAll() par exemple).

    Sans compter les méthodes optionnelles des interfaces filles...


    a++

  8. #8
    Membre Expert
    Avatar de natha
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    2 346
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2006
    Messages : 2 346
    Par défaut
    Hello,

    Personnellement ça fait un moment que j'utilise les méthodes de la classe Arrays, dont principalement #asList().

    J'ai eu le même problème à un moment donné en voulant modifier la liste fournie mais plutôt par un Collections#sort(List) qui bien évidemment n'a pas fonctionné.

    Je trouve finalement ça normal que la méthode Arrays#asList me renvoie un truc tout simple pour plusieurs raisons. La première => les performances, il est plus efficace de créer une implémentation minimale de List, la seconde => qui sait quel type de liste j'aurais besoin ensuite pour ma manip ? Une ArrayList ? Une LinkedList ? Une List d'une autre librairie ? ou encore une implémentation perso ? On peut faire la transformation facilement au besoin alors autant la faire en connaissance de cause afin de savoir exactement ce qu'on manipule, et ceci dans tous les cas.

    Voilà pour mon grain de sel
    Bonne soirée

  9. #9
    Membre émérite Avatar de yann2
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 897
    Par défaut
    Bonsoir

    Citation Envoyé par Duc Lebowski Voir le message
    On pourrait envisager Iterator extends ReadOnlyIterator et Collection extends ReadOnlyCollection, cela ne me choque pas du tout...

    Mais bon les 2 points de vue son discutables, après c'est une question de goût et surtout de compromis
    Le problème est que la relation d'héritage doit pouvoir se traduire par "est un".
    Donc, en procédant de cette manière on dit :
    Une collection modifiable est une collection en lecture seule !
    On n'utilise pas l'héritage parce qu'on a "besoin" des opérations de la classe dont on hérite ! Moi ça me choque (Mais non ! Je ne suis pas aigri ).

    yann

  10. #10
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 907
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 907
    Billets dans le blog
    54
    Par défaut
    Pourtant une telle relation existe deja dans Swing avec plusieurs modeles et objets utilitaires declares non-mutables dans leurs interfaces (ex : TreeNode), etendus dans une interface ou une classe abstraite mutable (MutableTreeNode) ayant elle-meme une implementation concrete par defaut (DefaultMutableTreeNode).

    Non, le principal point noir de ce procede est une multiplication des interfaces a tout va, on ne s'en sort plus.

    D'un autre cote avec la methode actuelle, c'est au devellopeur de faire l'effort de checker s'il recoit une UnsupportedOperationException (ou un truc du genre) lorsqu'il appelle les methode optionnelles ou de prendre l'habitude de recopier les collections obtenues dans la classe concrete appropriee qui implemente toutes les methodes optionnelles dont il a besoin (il se doit de toute facon de le faire pour des raisons de performance, voir post de natha).
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  11. #11
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 190
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public removeObject(List l) {
       Iterator i = l.iterator();
       while(i.hasNext()) {
          if(estASupprimer(i.next())) {
             i.remove();
          }
       }
    }
    Tu supprimes des éléments de i alors que tu itéres dessus.

    Dans tous les cas, il me semble que l'on ne peut pas modifier un iterator sur le quel on itére.

  12. #12
    Rédacteur
    Avatar de CyberChouan
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    2 752
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 752
    Par défaut
    Citation Envoyé par LGnord Voir le message
    Tu supprimes des éléments de i alors que tu itéres dessus.
    Certes

    Citation Envoyé par LGnord Voir le message
    Dans tous les cas, il me semble que l'on ne peut pas modifier un iterator sur le quel on itére.
    Le "Dans tous les cas" est exagéré... effectivement, on ne peut pas modifier n'importe comment une liste sur laquelle on itère (car l'iterator pourrait justement se retrouver "décalé"...), et on peut donc se retrouver avec des ConcurrentModificationException.

    Cependant, la méthode que je donne est parfaitement licite et tu pourras vérifier qu'elle fonctionne pour des ArrayList, LinkedList (par exemple). En effet, le "iterator.remove()" est une méthode qui permet de supprimer de la liste l'élément courant que l'itérateur pointe, de manière propre et sans que l'itérateur ne se perde.
    Avant de poster, pensez à regarder la FAQ, les tutoriaux, la Javadoc (de la JRE que vous utilisez) et à faire une recherche
    Je ne réponds pas aux questions techniques par MP: les forums sont faits pour ça
    Mes articles et tutoriaux & Mon blog informatique

  13. #13
    Rédacteur
    Avatar de CyberChouan
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    2 752
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 752
    Par défaut
    Je ne comptais pas particulièrement lancer de troll sur le sujet, mais puisqu'il est parti, je vais me faire une joie d'y participer!

    Je trouve que la notion même d'une "interface avec des méthodes facultatives" est paradoxale. Pour moi, une interface est un "contrat".
    Lorsque j'utilise un objet dont le type est une interface, je m'attends à ce que l'objet, indépendemment de son implémentation, remplisse le contrat en question dans sa totalité et me donne un résultat correct à l'appel des méthodes de l'interface.

    Si je dois m'intéresser au type réel de l'objet qui est sous l'interface pour savoir si il remplira bien ou non ses fonctions, on perd complètement l'intérêt de l'interface.

    Du coup, à mon avis, les "méthodes facultatives" devraient sortir de l'interface, pour ne laisser dans celle-ci que celles qui sont obligatoires. Et si j'ai besoin de méthodes supplémentaires "en plus du contrat défini par l'interface", là je m'intéresserai à l'implémentation réelle qui est faite.

    Exemple: lorsque j'ai besoin de getFirst(), getlast(), removeFirst(), removeLast(), je sais que je ne pourrai pas utiliser n'importe quelle liste, mais que celle dont j'ai besoin est la LinkedList. Et donc là on est dans le cas que je trouve "normal": ces méthodes spécifiques à une implémentation ne figurent pas dans l'interface. Si je décide d'utiliser une "List", alors je m'attend à recevoir n'importe quel type d'objet implémentant l'interface, et je renonce donc à utiliser ces méthodes spécifiques à une implémentation donnée.

    Bien sûr, ce n'est que mon point de vue sur la question, et je conçois tout à fait qu'il soit discutable...
    Avant de poster, pensez à regarder la FAQ, les tutoriaux, la Javadoc (de la JRE que vous utilisez) et à faire une recherche
    Je ne réponds pas aux questions techniques par MP: les forums sont faits pour ça
    Mes articles et tutoriaux & Mon blog informatique

  14. #14
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 907
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 907
    Billets dans le blog
    54
    Par défaut
    Citation Envoyé par moi
    c'est au devellopeur de faire l'effort de checker s'il recoit une UnsupportedOperationException (ou un truc du genre) lorsqu'il appelle les methode optionnelles
    Citation Envoyé par javadoc
    remove

    boolean remove(Object o) Removes the first occurrence of the specified element from this list, if it is present (optional operation). If this list does not contain the element, it is unchanged. More formally, removes the element with the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))) (if such an element exists). Returns true if this list contained the specified element (or equivalently, if this list changed as a result of the call).

    Specified by:
    remove in interface Collection<E>
    Parameters:
    o - element to be removed from this list, if present
    Returns:
    true if this list contained the specified element
    Throws:
    ClassCastException - if the type of the specified element is incompatible with this list (optional)
    NullPointerException - if the specified element is null and this list does not permit null elements (optional)
    UnsupportedOperationException - if the remove operation is not supported by this list
    Et pourtant le contrat est tres clair, cette methode PEUT LEVER une UnsupportedOperationException, si jamais cela arrive la faute en incombe donc au devellopeur, pas a l'interface. L'implementation de la methode remove() est optionnelle, elle peut optionnellement lever une ClassCastException et une NullPointerException, mais quand elle n'est pas implementee elle DOIT lever une UnsupportedOperationException (c'est la seule des 3 exceptions qui n'est pas optionnelle).
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

Discussions similaires

  1. [Sequoia] Votre avis sur la Méthode
    Par Zorro dans le forum Autres
    Réponses: 5
    Dernier message: 21/05/2008, 16h02
  2. [POO] ajout méthodes sur l'objet Array
    Par kimcharlene dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 24/04/2008, 16h40
  3. Conseils sur la méthode de développement objet métier
    Par RamDevTeam dans le forum Langage
    Réponses: 5
    Dernier message: 08/12/2005, 18h14
  4. [WebServices][axis] question sur la méthode service()
    Par Nycos62 dans le forum Services Web
    Réponses: 9
    Dernier message: 21/04/2005, 09h32
  5. Réponses: 3
    Dernier message: 16/04/2004, 16h51

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo