Collections.emptyMap () vs new HashMap ()


143

Quali sono alcune delle situazioni in cui posso usare Collections.emptyMap()? La documentazione dice che posso usare questo metodo se voglio che la mia collezione sia immutabile.

Perché dovrei desiderare una collezione vuota immutabile? Qual è il punto?


12
+1 alla domanda perché non ho mai visto quel metodo statico prima
Tim Bender,

potresti anche dare un'occhiata agli obiettivi scala di Google . EmptyMap e immutableMap possono essere utilizzati per creare oggetti immutabili. emptyMap è il punto iniziale. Ogni volta che viene aggiunto un elemento, la mappa stessa viene sostituita da una mappa contenente l'elemento vecchio e i nuovi elementi. Il punto è che gli accessi all'oggetto sono sicuri.
michael_s,

1
È come Objective-C [NSArray array], restituisce un oggetto che sebbene non utilizzabile ma esiste. Quindi puoi giocare con esso come un oggetto normale e non ottenere un errore.
Shane Hsu,

Risposte:


144

Da Effective Java , Articolo # 43 - "Return empty arrays or collections, not null"segnano il ritorno un insieme vuoto e forse anche illustra l'utilizzo di questi emptyList(), emptySet()e emptyMap()metodi sulla classe collezioni di ottenere un insieme vuoto che ha anche l'ulteriore vantaggio di essere immutabile. Da Articolo # 15 "Minimize Mutability" .

Da Collections-emptySet-Collections-emptyList-Collections

È un tipo di linguaggio di programmazione. Questo è per le persone che non vogliono variabili null. Quindi, prima che il set venga inizializzato, possono usare il set vuoto.

Nota: sotto il codice è solo un esempio (modificarlo in base al caso d'uso):

private Set myset = Collections.emptySet();

void initSet() {
   myset = new HashSet();
}
void deleteSet() {
   myset = Collections.emptySet();
}

Questi metodi offrono un paio di vantaggi:

  1. Sono più concisi perché non è necessario digitare esplicitamente il tipo generico della raccolta, in genere è solo dedotto dal contesto della chiamata al metodo.

  2. Sono più efficienti perché non si preoccupano di creare nuovi oggetti; semplicemente riutilizzano un oggetto vuoto e immutabile esistente. Questo effetto è generalmente molto minore, ma occasionalmente (bene, raramente) importante.


15
+1 per il riferimento effettivo a Java. Un aspetto: consiglierei di parametrizzare Sete HashSetnei tuoi esempi, poiché il punto centrale del emptySet()metodo e degli amici (al contrario delle costanti Collections.EMPTY_SETecc.) È che giocano bene con i generici. Inoltre, l'utilizzo di una funzione (tipi non elaborati) che è stato deprecato dal momento che Java 5 non è un buon aiuto per l'insegnamento.
Daniel Pryden,

4
Rimango non convinto ... Non è tutto il punto di usare un Collectioninvece di nullevitare di Exceptionsessere gettato sulle seguenti operazioni? L'uso di una collezione immutabile porterebbe solo a qualche altra sorta di eccezione che immagino. E l'assegnazione non nullè certamente meno efficiente dell'assegnazione di una costante immutabile.
Fgysin ripristina Monica il

14
@fgysin: se si dispone di un'API in cui i client devono modificare la raccolta, quindi sì, non ha senso restituire una raccolta immutabile. Ma se si dispone di un'API in cui si restituisce una raccolta che i client non devono modificare e su cui devono semplicemente iterare, restituire una vista alla raccolta sottostante ha perfettamente senso al fine di assicurarsi che un client "cattivo" non modifichi accidentalmente raccolte di proprietà da te. Restituire una raccolta vuota anziché nulla significa che il client non deve effettuare un controllo null prima di utilizzare la raccolta, rendendo più chiaro il codice client.
Jean Hominal,

4
public boolean setExists() { return !myset.equals(Collections.emptySet()); }
Assylias,

5
Nel tuo esempio stai controllando esplicitamente l'insieme vuoto e lo stai usando come valore sentinella e la tua classe è mutabile. Il tuo piccolo esempio usa sentinelle e mutabilità, che è esattamente ciò che Collections.emptySet () sta cercando di prevenire.
Marc O'Morain,

33

È vero, nella mia esperienza personale, molto utile nei casi in cui un'API richiede una raccolta di parametri, ma non hai nulla da fornire. Ad esempio, potresti avere un'API simile a questa e che non consente riferimenti null:

public ResultSet executeQuery(String query, Map<String, Object> queryParameters);

Se hai una query che non accetta alcun parametro, è sicuramente un po 'dispendioso creare una HashMap, che comporta l'allocazione di un array, quando potresti semplicemente passare nella' Mappa vuota 'che è effettivamente una costante, il modo in cui è implementata in java.util.Collections.


22

Perché dovrei desiderare una collezione vuota immutabile? Qual è il punto?

Ci sono due concetti diversi che sembrano strani se visti insieme. Ha più senso quando trattate i due concetti separatamente.

  • In primo luogo, dovresti preferire utilizzare una collezione immutabile piuttosto che una collezione mutevole, ove possibile. I benefici dell'immunità sono ben documentati altrove .

  • In secondo luogo, è preferibile utilizzare una raccolta vuota anziché utilizzare null come sentinella. Questo è ben descritto qui . Significa che avrai un codice molto più pulito, più facile da capire, con meno posti dove nascondere i bug.

Pertanto, quando si dispone di codice che richiede una mappa, è meglio passare una mappa vuota piuttosto che nulla per indicare l'assenza di una mappa. E la maggior parte delle volte che usi una mappa, è meglio usare una mappa immutabile. Questo è il motivo per cui esiste una funzione di praticità per creare una mappa vuota immutabile.


8

Ci sono un paio di casi in cui preferiresti utilizzare mappe, elenchi, set o altri tipi di raccolte immutabili.

Il primo e probabilmente il più importante caso d'uso è ogni volta che si restituisce un risultato di una query o un calcolo che restituisce un insieme (o elenco o mappa) di risultati, è preferibile utilizzare strutture di dati immutabili.

In questo caso, preferisco di gran lunga restituire versioni immutabili di queste in quanto ciò riflette l'immutabilità fattuale di un set di risultati di un calcolo molto più chiaramente - indipendentemente da ciò che fai con i dati in seguito, l'insieme di risultati che hai ricevuto dalla tua query non dovrebbe modificare.

Il secondo caso d'uso comune è quando è necessario fornire un argomento come input per un metodo o un servizio. A meno che non ti aspetti che la raccolta di input venga modificata dal servizio o dal metodo (che di solito è una cattiva idea di design), passare in una raccolta immutabile invece di quella mutabile potrebbe essere la scelta ragionevole e sicura in molti casi.

Lo considero una convenzione "pass by value" .

Più in generale - è una pratica sensata utilizzare una struttura di dati immutabile ogni volta che i dati attraversano i confini del modulo o del servizio. Questo rende molto più facile ragionare sulle differenze tra input / output (immutabili) e stato interno mutabile.

Come effetto collaterale molto vantaggioso di ciò vi è una maggiore sicurezza e sicurezza dei thread dei moduli / servizi e garantisce una separazione più chiara delle preoccupazioni.

Un'altra buona ragione per usare i Collections.empty*()metodi è la loro notevole mancanza di verbosità. Nell'era pre-Java7, se avevi una collezione generica, dovevi spargere annotazioni di tipo generico ovunque.

Basta confrontare queste due dichiarazioni:

Map<Foo, Comparable<? extends Bar>> fooBarMap = new HashMap<Foo, Comparable<? extends Bar>>();

contro:

Map<Foo, Comparable<? extends Bar>> fooBarMap = Collections.emptyMap();

Quest'ultimo vince chiaramente la leggibilità in due modi importanti:

  1. Nella prima dichiarazione, l'intera istanza di una mappa vuota è sepolta nel rumore delle dichiarazioni di tipo generico, rendendo una dichiarazione essenzialmente banale molto più criptica di quanto debba essere.
  2. Oltre alla notevole mancanza di annotazioni di tipo generico sul lato destro, la seconda versione afferma chiaramente che la mappa è inizializzata su una mappa vuota. Inoltre, sapendo che questo metodo restituisce una mappa immutabile, ora è più facile per me trovare dove fooBarMapviene assegnato un altro valore non vuoto semplicemente cercando /fooBarMap =/.

5

Per uno, puoi cavartela con la condivisione di riferimento. Un new HashMap()etc richiederà un oggetto allocato, e possibilmente alcuni elementi extra per contenere i dati, ma è necessaria solo una copia di una raccolta vuota immutabile (elenco, set, mappa o qualsiasi altro simile). Questo lo rende una scelta ovvia quando un metodo che stai chiamando deve accettare una mappa ma non ha bisogno di modificarla.

Suggerisco di dare un'occhiata a Effective Java di Josh Bloch , che elenca alcuni attributi molto belli di oggetti immutabili (inclusa la sicurezza dei thread).


3

Può essere utile quando hai una funzione che restituisce un immutable collectione in qualche situazione non ci sono dati da restituire, quindi invece di tornare nullpuoi restituireemptyMap()

Rende il tuo codice più semplice e previene NullPointerException


3

Il più delle volte usiamo a constructorper creare un nuovo empty map. Ma Collections methodsoffrono un paio di vantaggi per creare un empty maputilizzostatic method java.util.Collections.emptyMap()

  1. Sono più concisi perché non è necessario digitare esplicitamente il tipo generico della raccolta, in genere è solo dedotto dal contesto della chiamata al metodo.

  2. Sono più efficienti perché non si preoccupano di creare nuovi oggetti; semplicemente riutilizzano un oggetto vuoto e immutabile esistente. Questo effetto è generalmente molto minore, ma occasionalmente (bene, raramente) importante.


2

Perché dovrei desiderare una collezione vuota immutabile? Qual è il punto?

Per lo stesso motivo che avresti usato Collections.unmodifiableMap()ad un certo punto. Si desidera restituire un'istanza di Map che genera un'eccezione se l'utente tenta di modificarla. È solo un caso speciale: la Mappa vuota.


1

Perché dovrei desiderare una collezione vuota immutabile? Qual è il punto?

Per gli stessi motivi per cui potresti desiderare oggetti immutabili. Principalmente perché puoi dormire tranquillamente di notte sapendo che più thread possono accedere alla stessa istanza di un oggetto e che vedranno tutti gli stessi valori. Non avere elementi in una raccolta è ancora un valore valido, che vorresti mantenere.

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.