Qual è il vantaggio di attivare le stringhe in Java 7?


19

Quando stavo iniziando a programmare in Java, il fatto che le istruzioni switch non prendessero le stringhe mi frustrava. Quindi, usando Enums, ho realizzato i vantaggi che si ottengono con loro piuttosto che passare attraverso valori grezzi - tipo di sicurezza (che porta un refactoring più semplice) e anche chiarezza per altri sviluppatori.

Sto lottando per pensare a una situazione in cui con SE7 ora deciderò di utilizzare un interruttore con stringhe come input anziché Enums. Se vengono implementati tramite l'attivazione di intere stringhe (ad es. Anziché corrispondenze parziali o regex), non sembra offrire un motivo in meno per modificare il codice.

E con gli strumenti IDE e il rapporto di lettura / scrittura della codifica, sarei molto più felice di generare automaticamente un Enum in più rispetto al passare attorno ai valori di stringa.

Quali vantaggi ci apportano come programmatori? Meno piastra della caldaia?

Non sembra che la lingua richieda questa caratteristica. Anche se forse c'è un caso d'uso che sto trascurando.


Le stringhe sono già molto utilizzate nelle istruzioni switch, ma poiché le persone non potevano usarle direttamente, hanno fatto ricorso a soluzioni alternative come alberi giganti o conversioni in enumerazioni. Entrambe le soluzioni alternative rendono il codice meno leggibile. Entrambe le soluzioni sono soluzioni alternative e perché utilizzare una soluzione alternativa se una soluzione implementata in modo nativo mostra meglio le intenzioni dei programmatori.
Pieter B,

@PieterB Tuttavia, un Enum sta aggiungendo un valore semantico invece di essere una soluzione alternativa, il che porta sicurezza del tipo (ad esempio un errore di battitura verrà rilevato al momento della compilazione piuttosto che portare a un bug). Ci permette anche di refactoring di tutte le istanze della stringa, come usate in quel contesto , senza influire su altri usi di quella stringa (che può accadere abbastanza spesso con oggetti di dominio.)
Anotherdave

Risposte:


12

Per quanto ne so, la domanda è perché avvolgere le costanti String in enum non sia stato considerato sufficiente per coprire le esigenze degli utenti delle lingue. Questo è stato affrontato nella proposta ufficiale presentata alla mailing list JDK 7 (progetto Coin).

Secondo la mia lettura della proposta, l'alternativa all'uso degli enum è stata respinta perché introduce tipi gonfi. Per comodità, la parte pertinente della proposta è citata di seguito, con la dichiarazione relativa alle enumerazioni citate in grassetto :

VANTAGGI PRINCIPALI: Cosa rende la proposta un cambiamento favorevole?

È possibile utilizzare schemi di codifica più regolari per le operazioni selezionate sulla base di una serie di valori di stringa costanti; il significato del nuovo costrutto dovrebbe essere ovvio per gli sviluppatori Java.

PRINCIPALI VANTAGGI: Perché la piattaforma è migliore se la proposta viene adottata?

Prestazioni potenzialmente migliori per il codice di invio basato su stringhe.

GRANDI SVANTAGGI: c'è sempre un costo.

Qualche aumento della complessità di implementazione e test per il compilatore.

ALTERNATIVE: I benefici e i vantaggi possono essere ottenuti in qualche modo senza un cambio di lingua?

No; i test concatenati if-then-else per l'uguaglianza delle stringhe sono potenzialmente costosi e l' introduzione di un enum per le sue costanti commutabili, una per valore di stringa di interesse, aggiungerebbe un altro tipo a un programma senza una buona causa ...


la parte audace è piuttosto sorprendente
Simon Bergot il

1
@Simon bene per me, personalmente, è un trattamento indiretto, "perderemo la concorrenza con C # se continueremo a seguire modalità pre-Java5 per affrontare considerazioni del genere". :) Per un esempio di "modi pre-Java5", fare riferimento a JDK-1223179: accendere le stringhe - inviato nel 1995 e rapidamente chiuso come non risolto : "Non trattenere il respiro. Niente di simile a questo è nei nostri piani ".
moscerino del

Grazie, molto interessante vedere i motivi addotti nella proposta. È ancora sbagliato affermare che stiamo introducendo un tipo in un programma "senza una buona causa": siamo programmatori OO! :)
giorno il

5
@anotherdave "orientato agli oggetti" giustifica l'introduzione di tipi solo quando servono a scopi significativi. Apparentemente, l'opinione prevalente al JCP ha rivelato che l'uso di enum come wrapper senza cervello per le costanti di stringa in switch non si qualifica come significativo
moscerino

1
Wow, sono sorpreso (in senso buono) di vedere la proposta ufficiale contrastare attivamente il tipo gonfio. È rinfrescante. Digitare bloat è un grosso problema in Java.
Ben Lee,

7

Oltre a rendere il codice più leggibile, ci sono potenziali miglioramenti delle prestazioni rispetto ai if/else ifconfronti. Il valore della modifica dipende dal numero di confronti da effettuare. Un interruttore di stringa verrà emesso come due istruzioni di interruttore separate. Il primo opera su codici hash, quindi tende ad essere una complessità lookupswitchche alla fine produce O(log n). Il secondo è sempre un perfetto O(1) tableswitch, quindi la complessità combinata è ancora O(log n). Una singola catena lineare di if/else ifistruzioni darebbe una O(n)complessità leggermente peggiore .

Se stai confrontando più di, diciamo, tre stringhe, allora a switchè probabilmente più leggibile e compatto. Probabilmente funzionerà meglio, anche se è improbabile che notiate una differenza a meno che non stiate facendo un gran numero di confronti su un percorso di hot code.


1
Mi chiedevo di più perché avrei usato un interruttore su una stringa piuttosto che un interruttore su un enum. Considererei una if/elsebrutta pratica in blocco, ma al momento non avrei molte ragioni per usarne una.
AnotherDave

Ma poi una mappa in combinazione con il modello di comando produrrebbe anche più leggibilità con la stessa complessità perché hai il tipo extra del comando
SpaceTrucker

3

Lo switch per le stringhe può essere utilizzato quando i enumvalori provengono dall'esterno, ovvero memorizzati in un database.

Un'altra cosa degna di nota in JDK 7 switchè che è molto più performante dei if-elsecostrutti.

E un buon caso d'uso per stringhe veloci switchpotrebbe essere l'analisi del flusso JSON / XML quando è necessario eseguire molti switch su tipi di nodo e attributo. Non riesco a pensare a nessuna opzione migliore per questo.


1
"Il passaggio per le stringhe è insostituibile quando i tuoi valori enum provengono dall'esterno, cioè memorizzati in un database.": Puoi approfondire questo? Le stringhe nell'istruzione switch sono codificate: non appena le stringhe nel database vengono modificate, il codice non è aggiornato.
Giorgio,

Bene, hai ragione - enumin questo caso è possibile utilizzare a causa della natura statica di Java. Quando stavo scrivendo questo, stavo pensando a Roleda una libreria di sicurezza che di solito viene fornita come una classe e non può essere inserita enum. Un altro caso è un codice Java / Groovy compilato dinamicamente - in questa situazione, che è comunque rara, gli switch di stringa potrebbero essere un'opzione migliore.
Andrey Chaschev,

2

Semplicità

Le stringhe nel supporto Switch sono utili per l'elaborazione dei dati senza conversione in enum o if-elselogica. A volte è più semplice attivare String.

Dalla proposta di funzionalità alla mailing list JDK 7 (project Coin) ( risposta @gnat )

l'introduzione di un enum per le sue costanti commutabili, una per valore di stringa di interesse, aggiungerebbe un altro tipo a un programma senza una buona causa ...

Versione If-Else

Questo è breve, ma molti if'ssono difficili da leggere. E questo è lento.

if (color.equals("red")) {
    System.out.println("Color is Red");
} else if (color.equals("green")) {
    System.out.println("Color is Green");
} else {
    System.out.println("Color not found");
}

Versione Enum

Gli enum devono essere definiti, questo è buono, ma a volte non è necessario.

enum Color {RED, GREEN}

Elaborazione come al solito

try {
    switch (Color.valueOf(color)) {
        case RED:
            System.out.println("Color is Red");
            break;
        case GREEN:
            System.out.println("Color is Green");
            break;
    }
} catch (IllegalArgumentException e) {
    System.out.println("Color not found");
}

JDK 7 - Stringhe nella versione di istruzioni switch

Siamo in grado di elaborare senza convertire e definire tipi aggiuntivi.

switch (color) {
    case "red":
        System.out.println("Color is Red");
        break;
    case "green":
        System.out.println("Color is Green");
        break;
    default:
        System.out.println("Color not found");
}

7
Questo non affronta la domanda, però: perché dovresti usare stringhe invece di enum qui?
Dave Newton,

0

La maggior parte dei miglioramenti in qualsiasi lingua è di facilitare la lettura del codice. Preferisco il codice leggibile a fantasia ogni giorno.

Potresti non crederci, ma prova:

public enum JettStaff {
  ADRIAN("Adrian German") {
    public String toString() {
      return name + " (dgerman@indiana.edu)";
    }
  },
  ARJIT("Arjit Sengupta") {
    public String toString() {
      return name + " (asengupt@indiana.edu)";
    }
  },

  // and on for the rest...

  private String name;

  public JettStaff(String n) { this.name = n; }
}

JettStaff x = JettStaff.SUZANNE;
System.out.println(x);

Non sono chiaro sul tuo esempio di codice rispetto ai tuoi commenti sopra. Intendi l'Enum come esempio di qualcosa che è difficile da leggere?
un'altra volta,


2
Questo è molto inventato; stai fingendo che l'enum non abbia un campo email o che questa non sia una classe.
Dave Newton,

4
@ user2860598 Se stai cercando di fare un punto, usa un esempio pertinente. Inoltre, non risolve il problema della diteggiatura di una costante di stringa.
Dave Newton,

1
@ user2860598 La risposta che hai collegato sta dicendo che sono stati introdotti e che in precedenza potevano essere "approssimati" con un Enum. Il mio punto era che l'uso dell'Enum sembra essere ancora preferibile, anche con la loro introduzione.
AnotherDave

0

Gli Enum sono fantastici e dovresti usare quelli al posto delle stringhe quando hai la possibilità di farlo. Ma ci sono alcune volte in cui non è possibile, ad esempio quando è necessario lavorare con alcuni oggetti esterni provenienti da fuori Java. Immagina di dover analizzare qualcosa. Come la risposta del server, la configurazione, il file di registro o qualcosa di simile: hai un sacco di opzioni che stai cercando e non c'è modo che possano essere enumerazioni. Quindi in Java <7 saresti bloccato con un sacco di

  if (something.equals("foo")) {
    // foo processing
  } else 
  if (something.equals("bar")) {
   // bar processing
  }

Puoi comunque usare gli enum in questo caso semplicemente cercando di ottenerli per nome e / o fornendo una routine String-> Enum personalizzata ma a volte non è possibile o semplicemente non pratico (cioè quando dovresti creare troppi enum)

TLDR : dovresti assolutamente usare Enums quando lavori esclusivamente con codice Java ma non è sempre possibile con oggetti esterni. Spero che la mia spiegazione abbia un senso.


Se hai a che fare con i dati al di fuori, e si conosce già abbastanza per sapere che cosa avete bisogno nelle vostre ifdichiarazioni, allora si dovrebbe essere avvolgendolo in ogni caso , il che significa che si potrebbe ancora utilizzare enumerazioni, o un modello di comando, ecc
Dave Newton

@DaveNewton sì, puoi ancora usare enum ma come ho affermato nella mia risposta, a volte non è pratico come nel caso in cui finiresti per creare un affamato di enum da usare solo una volta nel tuo codice durante l'analisi.

@dimoniy Ma se dovessi creare centinaia di valori di Enum, ciò non significherebbe con un'alternativa switch dovresti avere centinaia di dichiarazioni di casi? Se ci sono così tante variabili, preferirei sicuramente la sicurezza dei tipi di enum.
AnotherDave

0

Non sono d'accordo con l'opinione che sia un codice più pulito e leggibile quando lo usi Stringsnelle istruzioni switch e pensi che sia una cattiva pratica di programmazione. Se si modifica il valore che si utilizza per archiviare, è necessario modificarlo ogni volta che si verifica un altro passaggio. Questo non va bene dato che stai inserendo valori hardcoded in ogni bir del tuo codice. Cosa farai se un giorno deciderai di cambiare uno di questi valori codificati? Cerca e sostituisci ogni sua copia?

Se disponi di alcuni valori hardcoded che esegui istruzioni if-elseif, usare valori primitivi costanti per loro è molto meglio prima di Java 1.5 solo perché porta la sicurezza dei tipi.

OK, ci saranno situazioni in cui otterrai valori String (da richiesta HTTP, file ecc.) E convertirli in valori primitivi è un po 'doloroso. Ma Enumfacciamo un buon lavoro a questo punto. Perché quando vuoi cambiare il valore che immagazzini in Enum, cambialo quando lo dichiari. Non è necessario modificare nient'altro nel tuo codice. (Naturalmente è necessario modificare i valori memorizzati altrove).

Di certo se stai solo implementando un codice sporco e pigro, è perfetto. Non vuoi impegnarti a codificare molti messaggi Enum, ma in un software complesso su larga scala che ti ucciderà.


-1

Se sai quali informazioni arrivano e che potrebbero essere solo di 5 stati, usa un Enum. Tuttavia, se i possibili stati potrebbero essere oltre 9000 e devi solo trovare 42, utilizzare uno switch è meglio perché non vuoi digitare tutti quegli stati.

Un Enum tende ad essere la scelta della maggior parte nella maggior parte dei casi a meno che non siano sconosciuti i possibili stati o ce ne siano molti e se ne preoccupino solo alcuni.

Ma perché l'hanno introdotto ora? Era solo una modifica che consentiva un codice più pulito.

In 1.5 ti hanno anche permesso di creare corpi personalizzati anche per Enum.


Ma non assegnereste semplicemente gli altri 8958 valori possibili allo stato di uno Enum?
AnotherDave

@anotherdave Questo è dove il defaultin switchentra in gioco. Non so che puoi avere uno stato predefinito con Enum, a meno che tu non stabilisca uno stato predefinito, ma questo codice viene gonfiato mentre a switchè molto più pulito da usare.

3
Sembra strano dire che uno UNKNOWNstato su un Enum è gonfio, ma un defaultcaso su un interruttore non lo è.
giorno il
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.