Pourquoi java.util.ArrayList permet-il d’ajouter null?

41

Je me demande pourquoi java.util.ArrayListpermet d'ajouter null. Y a-t-il un cas où je voudrais ajouter nullà un ArrayList?

Je pose cette question parce que dans un projet, nous avions un bogue qui ajoutait du code nullà la ArrayListet il était difficile de localiser la bogue. De toute évidence, un a NullPointerExceptionété lancé, mais pas avant qu'un autre code ait tenté d'accéder à l'élément. Le problème était de savoir comment localiser le code qui a ajouté l' nullobjet. Il aurait été plus facile de ArrayListcréer une exception dans le code où les éléments étaient ajoutés.

Alfredo Osorio
la source
12
Le projet Guava a une page assez intéressante sur ce sujet (ils ne permettent pas nulldans la plupart de leurs collections).
Joachim Sauer
6
Je crois que les réponses données ici couvrent bien la question. Peut-être une chose qui devrait être mentionnée est: ne prenez pas tout ce qui est dans le JDK comme parfait et parfait, et secouez ensuite votre tête en essayant de comprendre pourquoi il est si "parfait". Certaines choses sont des erreurs (honnêtes, à mon humble avis), qui sont restées là en raison de la compatibilité ascendante et c’est tout. Même les créateurs de Java l'admettent, il suffit de lire les livres de Joshua Bloch pour voir sa critique de certaines API Java. Quoi qu'il en soit, votre question est de savoir s'il n'existe pas de moyen plus élégant d'attraper NPE en Java. La réponse est non, mais il devrait y en avoir.
Shivan Dragon
2
Pouvez-vous fournir plus d'informations sur les raisons pour lesquelles cela ne devrait pas être autorisé? S'il s'agit simplement d'une question de goût, le moins restrictif devrait être préféré.
Mare Infinitus
La réponse simple est que nullc'est le moyen par défaut de représenter les données manquantes en Java, que cela vous plaise ou non. En fait, beaucoup de gens ne l'aiment pas et en font un argument pour des choses fonctionnelles de style programmation. La réponse la plus élevée n'a aucun sens / ne rend pas l'essence du problème.
xji
@ JIXiang Vous simplifiez excessivement ce qui nullest. "Missing" n’est que l’une des interprétations possibles de null. Les autres interprétations valides pourraient être «inconnu», «non applicable» ou «non initialisé». Ce qui nulldépend dépend de l'application. Comme dirait la communauté Python, "face à l'ambiguïté, refusez la tentation de deviner". Refuser de conserver la valeur null dans un conteneur parfaitement capable de le faire ne serait que cela - une supposition.
Riwalk

Réponses:

34

Cette décision de conception semble principalement motivée par le nommage.

Name ArrayList suggère au lecteur une fonctionnalité similaire à celle des tableaux - et il est naturel que les concepteurs de Java Collections Framework s’attendent à ce que la grande majorité des utilisateurs d’API s’en remettent à fonctionner de la même manière que les tableaux.

Cela implique notamment le traitement des éléments nuls. L'utilisateur de l'API sachant que ci-dessous fonctionne correctement:

array[0] = null; // NPE won't happen here

serait assez surpris de savoir si un code similaire pour ArrayList lancerait NPE:

arrayList.set(0, null); // NPE => WTF?

Le raisonnement comme ci-dessus est présenté dans les points de contrainte du didacticiel JCF qui suggèrent une similarité étroite entre ArrayList et les tableaux simples:

ArrayList ... offre un accès positionnel à temps constant et est tout simplement rapide ...

Si vous souhaitez qu'une implémentation de la liste n'autorise pas les valeurs NULL, mieux vaut l'appeler de la sorte NonNullableArrayListou quelque chose du genre, afin d'éviter toute confusion chez les utilisateurs d'API.


Note secondaire, il y a une discussion auxiliaire dans les commentaires ci-dessous, avec des considérations supplémentaires à l' appui du raisonnement exposé ici.

moucheron
la source
12
Cette explication n’est pas convaincante, étant donné qu’elle prend LinkedList également en charge les nullentrées de liste.
Stephen C
12
Oui ... mais une explication plus simple et plus plausible (IMO) est que permettre des nullentrées est utile dans de nombreux cas.
Stephen C
7
ArrayList ne s'appelle pas comme ça parce qu'il imite un tableau. Il s’appelle comme ça parce que c’est une liste implémentée comme un tableau. Tout comme TreeMap ne se comporte pas comme un arbre.
Florian F
11
Cette réponse, IMO, est tout simplement fausse. Les valeurs Null sont autorisées car en Java, pour le meilleur ou pour le pire (IMO, pire), null s'utilise beaucoup pour représenter des valeurs non initialisées ou manquantes. Comment at-il obtenu le plus de votes et le chèque "accepter"? Sérieusement, je perds vraiment confiance en StackOverflow ces jours-ci.
user949300
8
Cette réponse est tout simplement fausse. Il ne s'agit que de conjectures non prises en charge sur les valeurs NULL autorisées dans une implémentation de liste. Voici un aperçu des collections Java permettant / interdisant les valeurs NULL; remarquez que cela n’a rien à voir avec la similarité des tableaux.
Andres F.
32

Null peut être une valeur valide pour un élément d'une liste. Supposons que votre liste contienne des éléments qui représentent des données optionnelles sur une liste d'utilisateurs et sont stockés dans le même ordre que les utilisateurs. Si les données supplémentaires sont renseignées, votre liste contiendra les données supplémentaires, sinon l'emplacement correspondant à un utilisateur sera nul. (Je suis sûr qu'il y a de meilleurs exemples, mais vous voyez l'idée)

Si vous ne souhaitez pas autoriser l'ajout de valeurs NULL, vous pouvez envelopper la liste de tableaux avec votre propre wrapper qui indique que la valeur null a été ajoutée.

Sam Holder
la source
2
Cela semble être un mauvais exemple de la raison pour laquelle les valeurs NULL devraient être autorisées - il existe de meilleurs moyens de représenter des données facultatives que d’utiliser des valeurs NULL dans une liste.
Casablanca
@casablanca ouais tout à fait d'accord, ce n'est pas un bon exemple.
Sam Holder
Je ne trouve pas de bonne raison pour qu'une liste de tableaux (ArrayList) contienne des valeurs null, sinon de mauvaises surprises pour le prochain développeur: pour la "découvrir": /
AndreasScheinert le
7
@casablanca Bien que je convienne avec vous, il convient d'éviter les valeurs nulles pour représenter des données facultatives, en Java, pour le meilleur ou pour le pire, c'est "traditionnel".
user949300
2
Cas d'utilisation solide: vous souhaitez transmettre les paramètres à une fonction dynamique sous forme de liste. Vous avez plusieurs fonctions, chacune avec un ensemble de paramètres différent, vous avez donc besoin d'un tableau de taille dynamique et vous pouvez toujours passer null comme argument de fonction valide!
Falco
19

ArrayListautorise null par conception. C'est intentionnel. Du javadoc :

"[ArrayList est] une implémentation de tableau redimensionnable de l'interface List. Implémente toutes les opérations de liste facultatives et autorise tous les éléments, y compris null ."

La réponse à "pourquoi" est que si ce n'était pas le cas, ArrayList ne serait pas utilisable dans les cas où il est nécessaire de mettre un nulldans la liste. En revanche, vous pouvez empêcher un ArrayList de contenir des valeurs NULL en testant les valeurs avant de les ajouter ou en utilisant un wrapper qui empêche cela de se produire.

Y a-t-il un cas où je voudrais ajouter null à un ArrayList?

De toute évidence, tout cas où nulla une signification distincte. Par exemple, cela peut signifier que la valeur à une position donnée de la liste n’a pas été initialisée ni fournie.

Cela aurait été plus facile si ArrayList avait généré une exception dans le code dans lequel les éléments étaient ajoutés.

Vous pouvez facilement implémenter ce comportement en créant une classe wrapper. Cependant, ce n'est pas le comportement que la plupart des programmeurs / applications ont besoin.

Stephen C
la source
8

Y a-t-il un cas où je voudrais ajouter null à un ArrayList?

Bien sûr, qu'en est-il de la pré-allocation? Vous voulez une ArrayListchose que vous ne pouvez pas créer encore parce que vous n'avez pas assez d'informations. Ce n'est pas parce que vous ne pouvez imaginer une raison pour laquelle quelqu'un pourrait vouloir faire quelque chose que ce ne soit pas une mauvaise idée. Peu importe. (Maintenant, je suis sûr que quelqu'un va venir et dire que vous devriez plutôt avoir des objets vides qui correspondent à certains motifs sur lesquels ils ont lu sur un blog obscur et que les programmeurs devraient vraiment être capables d'écrire des programmes sans jamais utiliser d' ifinstructions, blah blah.)

Si vous avez un contrat qui ne devrait jamais figurer nulldans un conteneur, il vous appartient de vous assurer que ce contrat est respecté, probablement de manière plus appropriée en affirmant. Cela vous aurait probablement pris au maximum 10 lignes de code. Java vous simplifie incroyablement la tâche. Le JDK ne peut pas lire dans vos pensées.

James
la source
1
Votre argument de préallocation n'est pas valide car il est déjà construit dans ArrayList avec la ensureCapacity(int minCapacity)méthode et le ArrayList(int initialCapacity)constructeur.
Philipp
7
@Philipp Quelles valeurs va-t-il mettre dans cet espace?
James
Le choix évident est de mettre un nulldans les entrées pré-allouées (mais non encore utilisées ) du ArrayList; mais nous pouvons laisser ensureCapacityfaire cela et ne pas autoriser d’autres fonctions telles que setle faire. Les raisons données ailleurs semblent plus fortes.
David K
@ DavidK: Il est logique de dire qu'il devrait être possible à setun élément à n'importe quelle valeur qui pourrait être retournée par get. Même si une tentative normale sur getun élément pour lequel de l'espace avait été attribué mais qui n'avait jamais été écrit devait renvoyer une exception plutôt que de revenir null, il serait toujours utile de disposer d'une paire de méthodes qui permettraient list1.setOrEraseIfNull(index, list2.getOrReturnNull(index))plutôt que d'exigerif (list2.valueSet(index)) list1.set(index, list2.get(index)); else list1.unset(index);
supercat
1
@DavidK: Toute tentative de lecture d'une entrée allouée mais non encore écrite doit renvoyer null ou renvoyer une exception. il est plus facile de le renvoyer null.
Supercat
4

Cela semble être davantage une question philosophique (logicielle) ici.

ArrayList en tant que classe d’utilité est conçu pour être utile dans un large contexte de cas d’utilisation possibles.

Contrairement à votre affirmation cachée selon laquelle l'acceptation de null en tant que valeur valide devrait être découragée, il existe de nombreux exemples dans lesquels la valeur null est parfaitement légale.

La raison la plus importante est que nullest l' do not knowéquivalent de tout type de référence, y compris les types de cadres. Cela implique que null ne peut en aucun cas être remplacé par une version plus fluide de la nothingvaleur.

Supposons donc que vous stockiez les entiers 1, 3, 7 dans votre arraylist à son index correspondant: En raison de certains calculs, vous voulez obtenir l'élément à l'index 5, votre tableau devrait donc renvoyer: "aucune valeur stockée". Cela pourrait être réalisé en renvoyant null ou un NullObject . Dans la plupart des cas, renvoyer la valeur null intégrée est suffisamment expressif. Après avoir appelé une méthode pouvant renvoyer null et utiliser sa valeur renvoyée, une vérification de la valeur renvoyée par rapport à null est assez courante dans le code moderne.

Mare Infinitus
la source
4

La déclaration

File f = null;

est valable et utile (je ne pense pas avoir besoin d'expliquer pourquoi). Il est également utile d’avoir une collection de fichiers dont certains peuvent être nuls.

List<File> files = new ArrayList<File>();
// use my collection of files
// ....
// not using this one anymore:
files.set(3, null);

L'utilité des collections pouvant contenir des objets nuls découle directement de l'utilité des objets pouvant être nuls. C'est vraiment aussi simple que ça.

x-code
la source
2

Il est plus facile de tout accepter que d’être restrictif, puis d’essayer d’ouvrir votre projet après coup.

Par exemple, si Oracle / Sun fournissait uniquement NonNullableArrayList, mais que vous souhaitiez pouvoir ajouter un Null à votre liste. Comment le ferais-tu? Vous auriez probablement à créer un objet entièrement différent, vous ne pourriez pas utiliser une extension de NonNullableArrayList. Au lieu de cela, si vous avez un ArrayList qui prend tout, vous pouvez facilement l'étendre et redéfinir l'ajout s'il n'accepte pas les valeurs NULL.

NiteRain
la source
2
En désaccord. Laisser trop est plus difficile à corriger une fois que le comportement défectueux a été largement utilisé. Si les concepteurs de langage autorisaient les valeurs NULL à un stade ultérieur, cela ne casse pas les programmes existants, mais l'inverse n'est pas vrai.
Andres F.
2
Mais je suis d'accord. Il s’agit de maximiser la fonctionnalité. Vous pouvez utiliser une liste qui accepte les valeurs NULL même si vous n'en avez pas besoin. Vous ne pouvez pas utiliser une liste qui refuse les valeurs NULL si vous en avez besoin.
Florian F
-1

Utilité de null?

Cela est tout à fait le cas lorsque vous utilisez une liste de listes pour modéliser une plaque 2D réelle avec différentes positions. La moitié de ces positions peuvent être vides (en coordonnées aléatoires), tandis que celles remplies ne représentent pas un simple int ou String, mais sont représentées par un objet complexe. Si vous souhaitez conserver les informations de position, vous devez remplir les zones vides avec null pour que votre liste.get (x) .get (y)ne conduit pas à de mauvaises surprises. Pour contrer les exceptions nulles, vous pouvez rechercher la valeur null (très populaire) ou utiliser une option (que je trouve pratique dans ce cas). L’alternative serait de remplir les espaces vides avec des objets «indésirables» qui peuvent causer toutes sortes de dégâts sur la route. Si votre contrôle nul échoue ou est oublié quelque part, Java vous le fera savoir. D'autre part, un objet de substitution "indésirable" mal contrôlé peut passer inaperçu.

Nanobody
la source