Perché java.util.ArrayList consente di aggiungere null?


41

Mi chiedo perché java.util.ArrayListpermetta di aggiungere null. C'è un caso in cui vorrei aggiungere nulla un ArrayList?

Sto ponendo questa domanda perché in un progetto avevamo un bug in cui un po 'di codice si stava aggiungendo nullal codice ArrayListed era difficile individuare dove fosse il bug. Ovviamente è NullPointerExceptionstato lanciato un ma non fino a quando un altro codice ha tentato di accedere all'elemento. Il problema era come individuare il codice che ha aggiunto l' nulloggetto. Sarebbe stato più semplice se avesse ArrayListgenerato un'eccezione nel codice in cui venivano aggiunti gli elementi.


12
Il progetto Guava ha una pagina piuttosto interessante su questo argomento (non sono ammessi nullnella maggior parte delle loro raccolte).
Joachim Sauer,

6
Credo che le risposte fornite qui coprano bene la domanda. Forse una cosa che dovrebbe essere menzionata è: non prendere tutto ciò che è nel JDK come agrifoglio e perfetto, e poi colpire la testa cercando di capire perché è così "perfetto". Alcune cose sono errori (onesti, IMHO), che sono rimasti lì a causa della retrocompatibilità e basta. Anche i creatori di Java lo ammettono, basta leggere i libri di Joshua Bloch per vedere la sua critica di alcune API Java. Ad ogni modo, la tua domanda si riduce al tempo che non esiste un modo più elegante per catturare NPE in Java. La risposta è no, ma ci dovrebbe essere.
Drago Shivan,

2
Potete fornire maggiori informazioni sul perché non dovrebbe essere consentito? Se è solo una questione di gusti, dovrebbe essere preferito il meno restrittivo.
Mare Infinitus,

La semplice risposta è proprio questo nullil modo predefinito di rappresentare i dati mancanti in Java, che ti piaccia o no. In realtà a molte persone non piace e lo rendono un argomento per cose funzionali in stile programmazione. La risposta più votata non ha senso / non cattura l'essenza del problema.
xji,

@JIXiang Stai semplificando troppo ciò che nullè. "Missing" è solo una delle numerose potenziali interpretazioni di null. Altre interpretazioni valide potrebbero essere "Sconosciuto", "Non applicabile" o "Non inizializzato". Ciò che nullrappresenta dipende dall'applicazione. Come direbbe la comunità Python, "Di fronte all'ambiguità, rifiuta la tentazione di indovinare". Rifiutare di tenere nulla in un contenitore perfettamente in grado di farlo sarebbe proprio questo: un'ipotesi.
riwalk

Risposte:


34

Questa decisione di progettazione sembra guidata principalmente dalla denominazione.

Name ArrayList suggerisce di leggere una funzionalità simile alle matrici - ed è naturale per i progettisti di Java Collections Framework aspettarsi che la stragrande maggioranza degli utenti API faccia affidamento sul suo funzionamento simile alle matrici.

Ciò in particolare comporta il trattamento di elementi nulli. Utente API sapendo che di seguito funziona bene:

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

sarei piuttosto sorpreso di scoprire se un codice simile per ArrayList genererebbe NPE:

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

Il ragionamento come sopra è presentato nel tutorial JCF che sottolinea i punti che suggeriscono una stretta somiglianza tra ArrayList e array semplici:

ArrayList ... offre un accesso posizionale a tempo costante ed è semplicemente veloce ...

Se desideri che un'implementazione dell'elenco non consenta null, sarebbe meglio chiamarla come NonNullableArrayListo qualcosa del genere, per evitare di confondere gli utenti API.


Nota a margine c'è una discussione ausiliaria nei commenti qui sotto, insieme ad ulteriori considerazioni a supporto del ragionamento esposto qui.


12
Questa spiegazione non è convincente, considerando che supporta LinkedList anche le nullvoci dell'elenco.
Stephen C,

12
Sì ... ma una spiegazione più semplice e (IMO) più plausibile è che consentire le nullvoci è utile in molti casi.
Stephen C,

7
ArrayList non si chiama così perché imita un array. Si chiama così perché è un elenco implementato come un array. Proprio come una TreeMap non si comporta come un albero.
Florian F,

11
Questa risposta, IMO, è semplicemente sbagliata. I valori null sono consentiti perché in Java, nel bene o nel male, (IMO, peggio), null viene utilizzato molto per rappresentare valori non inizializzati o mancanti. Come ha ottenuto il maggior numero di voti e il controllo "accetta"? Seriamente, sto davvero perdendo fiducia in StackOverflow in questi giorni.
user949300,

8
Questa risposta è chiaramente sbagliata. Si tratta solo di congetture non supportate sul fatto che i null siano ammessi in un'implementazione dell'elenco. Ecco una carrellata di raccolte Java che consentono / non consentono null; notate come non abbia nulla a che fare con la somiglianza con le matrici.
Andres F.

32

Null può essere un valore valido per un elemento di un elenco. Supponiamo che il tuo elenco contenga elementi che rappresentano alcuni dati facoltativi su un elenco di utenti e che sono memorizzati nello stesso ordine degli utenti. Se vengono popolati i dati extra, l'elenco conterrà i dati aggiuntivi, altrimenti lo slot corrispondente a un utente sarà nullo. (Sono sicuro che ci sono esempi migliori, ma hai avuto l'idea)

se non si desidera consentire l'aggiunta di null, è possibile racchiudere l'elenco di array con il proprio wrapper che è stato lanciato quando è stato aggiunto null.


2
Questo sembra un cattivo esempio del perché i null dovrebbero essere consentiti - ci sono modi migliori di rappresentare dati facoltativi rispetto all'uso di valori null in un elenco.
Casablanca,

@casablanca sì, sono totalmente d'accordo, non è un grande esempio.
Sam Holder

Non riesco a trovare una buona ragione per cui una ArrayList contenga null, altre poi brutte sorprese per il prossimo sviluppatore che lo "scopre": /
AndreasScheinert

7
@casablanca Mentre concordo con te sul fatto che i null dovrebbero essere evitati per rappresentare dati facoltativi, in Java, nel bene o nel male, è "tradizionale".
user949300,

2
Un solido caso d'uso: si desidera passare i parametri ad alcune funzioni dinamiche come un elenco. Hai diverse funzioni, ognuna con un diverso set di parametri, quindi hai bisogno di un array di dimensioni dinamiche e puoi sempre passare null come argomento di funzione valido!
Falco,

19

ArrayListconsente null per progettazione. È intenzionale. Dal javadoc :

"[ArrayList è un'implementazione] di array ridimensionabili dell'interfaccia Elenco. Implementa tutte le operazioni elenco facoltative e consente tutti gli elementi, incluso null ."

La risposta al "perché" è che se non fosse ArrayList non sarebbe utilizzabile nei casi in cui è necessario inserire un nullnell'elenco. Al contrario, è possibile impedire a un ArrayList di contenere valori null testando i valori prima di aggiungerli o utilizzando un wrapper che impedisce che ciò accada.

Esiste un caso in cui vorrei aggiungere null a una ArrayList?

Ovviamente, ogni caso in cui nullha un significato distinto. Ad esempio, potrebbe significare che il valore in una determinata posizione nell'elenco non è stato inizializzato o fornito.

Sarebbe stato più semplice se ArrayList avesse generato un'eccezione nel codice in cui venivano aggiunti gli elementi.

È possibile implementare facilmente tale comportamento creando una classe wrapper. Tuttavia, questo non è il comportamento necessario alla maggior parte dei programmatori / applicazioni.


8

Esiste un caso in cui vorrei aggiungere null a una ArrayList?

Certo, per quanto riguarda la pre-allocazione? Vuoi una ArrayListdelle cose che non puoi ancora creare perché non hai abbastanza informazioni. Solo perché non riesci a pensare a un motivo per cui qualcuno potrebbe voler fare qualcosa non lo rende una cattiva idea. Qualunque cosa. (Ora, sono sicuro che qualcuno arriverà e dirà che dovresti invece avere oggetti vuoti che soddisfano un modello di cui leggono su alcuni blog oscuri e che i programmatori dovrebbero davvero essere in grado di scrivere programmi senza mai usare ifdichiarazioni, blah blah.)

Se voi ragazzi avete un contratto che non dovrebbe mai esserci nullin un container, dipende da voi assicurarsi che il contratto sia rispettato, probabilmente nel modo più appropriato affermando. Probabilmente ti sarebbero servite al massimo 10 righe di codice. Java ti rende incredibilmente facile fare questo genere di cose. Il JDK non può leggere la tua mente.


1
L'argomento preallocazione non è valido, poiché è già incorporato in ArrayList con il ensureCapacity(int minCapacity)metodo e il ArrayList(int initialCapacity)costruttore.
Philipp,

7
@Philipp Quali valori metterà in quello spazio?
James,

La scelta ovvia è quella di inserire a nullnelle voci pre-allocate (ma non ancora utilizzate ) di ArrayList; ma possiamo lasciarlo ensureCapacityfare e tuttavia non consentire altre funzioni come setfarlo. Le ragioni fornite altrove sembrano più forti.
David K,

@DavidK: ha senso dire che dovrebbe essere possibile setun articolo per qualsiasi valore che potrebbe essere restituito da get. Anche se un normale tentativo di getun elemento per il quale lo spazio era stato allocato ma mai scritto dovesse generare un'eccezione anziché restituirla null, sarebbe comunque utile disporre di una coppia di metodi che consentirebbe list1.setOrEraseIfNull(index, list2.getOrReturnNull(index))piuttosto che richiedereif (list2.valueSet(index)) list1.set(index, list2.get(index)); else list1.unset(index);
supercat

1
@DavidK: il tentativo di leggere una voce che è stata allocata ma non ancora scritta deve restituire null o generare un'eccezione; è più facile averlo restituire null.
supercat

4

Questa sembra essere più una questione filosofica (software) qui.

ArrayList poiché una classe di utilità è progettata per essere utile in un ampio contesto di possibili casi d'uso.

Contrariamente all'affermazione nascosta secondo cui l'accettazione di null come valore valido dovrebbe essere scoraggiata, ci sono molti esempi in cui il valore null è perfettamente legale.

Il singolo motivo più importante nullè l' do not knowequivalente di qualsiasi tipo di riferimento, inclusi i tipi di framework. Ciò implica che null non può essere sostituito in nessun caso da una versione più fluida del nothingvalore.

Quindi, supponiamo che memorizzi gli Integer 1, 3, 7 nel tuo arraylist nel suo indice corrispondente: a causa di alcuni calcoli, vuoi ottenere l'elemento all'indice 5, quindi ciò che l'array dovrebbe restituire è: "nessun valore memorizzato". Ciò potrebbe essere ottenuto restituendo null o NullObject . Nella maggior parte dei casi, la restituzione del valore null incorporato è sufficientemente espressiva. Dopo aver chiamato un metodo che può restituire null e usare il suo valore restituito, un controllo del valore restituito contro null è abbastanza comune nel codice moderno.


4

La dichiarazione

File f = null;

è valido e utile (non credo di dover spiegare il perché). È anche utile disporre di una raccolta di file, alcuni dei quali potrebbero essere nulli.

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

L'utilità di raccolte che possono contenere oggetti null procede direttamente dall'utilità di oggetti che possono essere null. È davvero così semplice.


2

È più facile accettare tutto, che essere restrittivi e poi provare ad aprire il tuo design dopo il fatto.

Ad esempio, cosa succede se oracle / sun forniscono solo NonNullableArrayList, ma si desidera poter aggiungere un valore Null all'elenco. Come lo faresti? Probabilmente dovresti creare un oggetto completamente diverso, non puoi usare ext nonNullableArrayList. Invece se hai un ArrayList che accetta tutto, puoi facilmente estenderlo e sovrascrivere l'aggiunta, dove non accetta valori null.


2
Non sono d'accordo. Consentire troppo è più difficile da correggere una volta che il malfunzionamento ha visto un uso diffuso. Se i progettisti linguistici consentissero i null in una fase successiva, ciò non spezzerebbe i programmi esistenti, ma non è vero il contrario.
Andres F.

2
Ma sono d'accordo. Si tratta di massimizzare la funzionalità. È possibile utilizzare un elenco che accetta valori null anche se non sono necessari. Non è possibile utilizzare un elenco che rifiuta i null se sono necessari null.
Florian F,

-1

Utilità di null?

Tanto quando vai con un Elenco di elenchi per modellare una piastra di vita reale 2D con posizioni diverse. La metà di quelle posizioni potrebbe essere vuota (in coordinate casuali) mentre quelle riempite non rappresentano un semplice int o String ma sono rappresentate da un oggetto complesso. Se vuoi mantenere le informazioni sulla posizione, devi riempire i punti vuoti con null in modo che il tuo list.get (x) .get (y)non porta a brutte sorprese. Per contrastare le eccezioni nulle è possibile verificare la presenza di null (molto popolare) oppure è possibile utilizzare un facoltativo (che trovo utile in questo caso). L'alternativa sarebbe quella di riempire i punti vuoti con oggetti "spazzatura" che possono portare a tutti i tipi di disordine lungo la strada. Se il tuo controllo null fallisce o viene dimenticato da qualche parte, Java ti avviserà. D'altra parte, un oggetto segnaposto "indesiderato" che non viene controllato correttamente può passare inosservato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.