2015-07-20 12 views
21

Sto provando a verificare se un tipo di account utente corrisponde a uno dei vari Strings.Vantaggi dell'utilizzo di Enums su collezioni

In ufficio è in discussione se questo debba essere rappresentato come enum con ogni voce contenente una stringa diversa o come Set di Strings. Mentre il Set può essere più efficiente, un enum può essere stilisticamente superiore in quanto è più chiaro che viene utilizzato per il flusso logico.

Quali sono i vantaggi di questi due approcci?

+7

Come su [ 'EnumSet'] (http://docs.oracle.com/javase/7/docs/api/java/util/EnumSet.html)? –

+3

Quanto è importante la velocità nella tua applicazione? A meno che tu non abbia effettivamente bisogno delle prestazioni dovresti risolvere il problema correttamente. E se hai bisogno di prestazioni, hai bisogno anche di parametri di riferimento. Se non ne hai, non devi iniziare la discussione sulle prestazioni. – mpkorstanje

+3

È possibile combinare enumerazioni e altre strutture dati in Java: è possibile inserire un HashSet/mappa statico in un enum e aggiungere un metodo statico per accedervi. Riempilo in un blocco statico. In questo modo è possibile aggiungere all'enumerazione più metodi di ricerca come (getByName, getById) ecc. – Traubenfuchs

risposta

22

Infatti, un Set<String> è più efficiente in termini di prestazioni durante la ricerca. Tuttavia, non mi aspetto che tu abbia migliaia di tipi di account, ma diversi, quindi in realtà non sentirai la differenza durante la ricerca. C'è un problema con questo approccio, tuttavia - sarà possibile aggiungere qualsiasi String allo Set, che è fragile.

Il mio preferito preferirebbe utilizzare un enum, specialmente se si non si aspetta che verranno introdotti più tipi di account. E se hai un Set<AccountType> sarai limitato con i valori che puoi aggiungere (ad esempio, potrai aggiungere solo tipi di account, ma non nulla, come l'approccio con un Set<String>). Il problema con questo approccio è il Open/Closed Principle - considera di avere un'istruzione switch su una variabile AccountType con tutti i corrispondenti case s. Quindi, se si introduce una costante nuovaAccountType, è necessario modificare l'istruzione switch (con l'aggiunta di un nuovo case), che interrompe il "principio Aperto/Chiuso". In questo caso, il design migliore sarebbe quello di avere un abstract class/interface, chiamato AccountType, che ha tutti i tipi di account specifici come sottoclassi.

Quindi, ci sono diversi approcci che puoi seguire, ma prima di sceglierne uno, dovresti provare a rispondere a te stesso alla domanda di "Come lo useremo?"

+2

E se la ricerca diventa un problema, è sempre possibile creare una mappa statica nell'enum a cui si accede tramite il metodo di ricerca statica. – mpkorstanje

+0

È possibile ottenere il meglio da enumerazioni e stringhe costruendo una serie di stringhe/mappa dall'enumerazione, ad es. 'mappa finale map = new HashMap <>(); per (finale YourEnum e: YourEnum.values ​​()) map.add (e.name(), e); 'con questo puoi semplicemente usare' map.get() 'per ottenere il valore enum appropriato, o 'null' se non esiste. Questo approccio è significativamente più veloce di 'YourEnum.valueOf(); circa 2 volte più veloce per le stringhe che * sono * membri enum e circa 16 volte più veloce per le stringhe che * non sono * membri enum. –

+0

Oppure puoi usare un 'EnumMap' o' EnumSet' con lo stesso successo :) –

13

Un enum sarebbe meglio poiché i tipi di account (in genere) non cambiano in modo dinamico. Inoltre, l'uso di un enum rende i tipi più precisi - ad es. non c'è modo di mescolare "Hello, World!" con un tipo di account.

+1

Per quanto riguarda le prestazioni, tutte le istanze di un enum sono conosciute in fase di compilazione. Questo probabilmente ha un effetto sulle prestazioni. Non so quale sia più veloce, ma mi piacerebbe vedere un punto di riferimento prima di decidere che uno è più veloce dell'altro. – ReyCharles

6

Le enumerazioni sono ottime perché si ottiene il controllo del tempo di compilazione. I valori non validi semplicemente non verranno compilati quindi 'fallisce velocemente'.

Una raccolta di stringhe è ottima quando si desidera aggiungere un'altra opzione senza compilare/rilasciare una nuova versione dell'applicazione. Se, ad esempio, le opzioni valide sono state configurate in una tabella di database.

3

Vale la pena notare che il metodo valueOf(String) di un enum viene implementato utilizzando il metodo Enum.valueOf(Class,String), che a sua volta viene implementato utilizzando un HashMap.

Ciò significa in sostanza che la ricerca del tipo di account dalla stringa utilizzando AccountTypes.valueOf() è un'operazione O (1) e abbastanza efficiente come un'operazione impostata. È quindi possibile utilizzare il valore restituito (l'oggetto enum effettivo) nel programma, con sicurezza di tipo completo, confronti più rapidi e tutti gli altri vantaggi dell'enumerazione.

1

Nella mia esperienza, suggerisco di usare enum in questo caso. Persino mysql supporta enum per casi d'uso in cui si desidera che una colonna accetti valori da un elenco dichiarato esplicitamente.

3

Sembra a me come il problema è che si sta utilizzando una stringa per rappresentare i dati che possono avere solo pochi, valori noti validi. Un Set può essere utile per convalidare se il valore stringa è valido, ma non impedisce che diventi non valido.

Il mio suggerimento è quello di definire un enum con i tipi di account validi e utilizzare quello sul posto di stringhe. Se si dispone di input provenienti dall'esterno che rappresenta un tipo di account, quindi inserire un metodo statico sull'enumerazione come "fromString" che restituisce un'istanza di enum appropriata, riducendo quindi la finestra in cui i dati non validi devono essere considerati.

è possibile creare un Set di AccountType Enumera istanze, a condizione di implementare le appropriate Comparator, compareTo, o hashCode metodi (a seconda se si è utilizzato TreeSet o HashSet, etc.). Ciò potrebbe essere utile se si dispone di classificazioni dei tipi di account da controllare. Ad esempio, se ci sono "Local Admins", "Global Admins" e "Security Admins", è possibile definire un metodo isAdmin(AccountType t) che ricerca un Set di AccountTypes. Per esempio:

private Set<AccountType> ADMIN_ACCOUNT_TYPES = new HashSet<AccountType>() {{ 
    add(AccountType.LOCAL_ADMIN); 
    add(AccountType.GLOBAL_ADMIN); 
    add(AccountType.SECURITY_ADMIN); 
}}; 

public boolean isAdmin(AccountType t) { 
    return ADMIN_ACCOUNT_TYPES.contains(t); 
} 

Ora, se si dispone di un caso in cui ci sono un sacco di diversi tipi di account, con molti gruppi, e le prestazioni di ricerche è un problema, questo è come si potrebbe risolverlo.

Anche se ad essere onesti, se hai solo pochi tipi di account e raramente cambia, questo può essere over-engineering un po '. Se ci sono solo 2 tipi di account, una semplice istruzione if con controllo di uguaglianza sarà più efficiente di una ricerca nella tabella hash.

Anche in questo caso, le prestazioni potrebbero non rappresentare un problema. Non ottimizzare eccessivamente o ottimizzare prima del tempo.

0

Vorrei usare uno Map<String,Enum> = new HashMap<>(); per il massimo in modo efficiente.