Was ist der Vorteil des Einschaltens von Strings in Java 7?

19

Als ich anfing, in Java zu programmieren, frustrierte mich die Tatsache, dass switch-Anweisungen keine Zeichenketten enthielten. Bei der Verwendung von Enums erkannte ich die Vorteile, die Sie mit ihnen erzielen, anstatt Rohwerte weiterzugeben - Typensicherheit (die das Refactoring vereinfacht) und Klarheit für andere Entwickler.

Ich habe Mühe, mir eine Situation vorzustellen, in der ich mit SE7 jetzt einen Schalter mit Zeichenfolgen als Eingaben anstelle von Enums verwende. Wenn sie durch Einschalten ganzer Zeichenfolgen implementiert werden (z. B. anstelle von Teil- oder Regex-Übereinstimmungen), bietet dies anscheinend keinen geringeren Grund für eine Änderung des Codes.

Und mit IDE-Tools und dem Lese- / Schreibverhältnis der Codierung wäre es viel glücklicher, eine zusätzliche Enumeration zu generieren, als Zeichenfolgenwerte weiterzugeben.

Welchen Nutzen bringen sie uns als Programmierer? Weniger Kesselplatte?

Es fühlt sich nicht so an, als würde die Sprache nach dieser Funktion schreien. Obwohl ich vielleicht einen Anwendungsfall übersehen habe.

Ein anderer Dave
quelle
Zeichenfolgen werden bereits häufig in switch-Anweisungen verwendet, aber da die Benutzer sie nicht direkt verwenden konnten, haben sie auf Problemumgehungen wie Riesen zurückgegriffen, wenn sonst Bäume oder Konvertierungen in Aufzählungen. Beide Problemumgehungen machen Code weniger lesbar. Bei beiden Methoden handelt es sich um Problemumgehungen, und warum sollten Sie eine Problemumgehung verwenden, wenn eine nativ implementierte Lösung die Absichten des Programmierers besser erkennen lässt.
Pieter B
@PieterB Vermutlich ist ein Enum jedoch ein zusätzlicher semantischer Wert, anstatt eine Problemumgehung zu sein, was die Typensicherheit erhöht (z. B. wird ein Tippfehler zur Kompilierungszeit abgefangen, anstatt zu einem Fehler zu führen). Es ermöglicht uns auch, alle in diesem Kontext verwendeten Instanzen des Strings
umzugestalten

Antworten:

12

Soweit ich das beurteilen kann, stellt sich die Frage, warum das Einschließen von String-Konstanten in Enum nicht ausreicht, um die Bedürfnisse der Sprachbenutzer abzudecken. Dies wurde in dem offiziellen Feature-Vorschlag behoben, der auf der JDK 7-Mailingliste (Project Coin) angekündigt wurde.

Nach meiner Lektüre des Vorschlags wurde die Alternative der Verwendung von Aufzählungen mit der Begründung verworfen, dass es Typen aufbläht. Der Einfachheit halber wird der relevante Teil des Vorschlags im Folgenden mit fettgedruckten Anweisungsadressen angegeben :

HAUPTVORTEIL: Was macht den Vorschlag zu einer günstigen Änderung?

Regelmäßigere Codierungsmuster können für Operationen verwendet werden, die auf der Grundlage eines Satzes konstanter Zeichenkettenwerte ausgewählt werden. Die Bedeutung des neuen Konstrukts sollte für Java-Entwickler offensichtlich sein.

HAUPTNUTZEN: Warum ist die Plattform besser, wenn der Vorschlag angenommen wird?

Potenziell bessere Leistung für auf Zeichenfolgen basierenden Versandcode.

WICHTIGSTER NACHTEIL: Es fallen immer Kosten an.

Eine erhöhte Implementierungs- und Testkomplexität für den Compiler.

ALTERNATIVEN: Können die Vorteile und Vorteile auf irgendeine Weise genutzt werden, ohne dass sich die Sprache ändert?

Nein; Verkettete if-then-else-Tests für die Gleichheit von Zeichenfolgen sind möglicherweise teuer, und die Einführung einer Enumeration für ihre umschaltbaren Konstanten, eine pro interessierendem Zeichenfolgenwert, würde einem Programm ohne wichtigen Grund einen anderen Typ hinzufügen ...

Mücke
quelle
Der kühne Teil ist ziemlich überraschend
Simon Bergot
1
@ Simon gut zu mir persönlich liest es als indirekte Festlichkeit, "wir werden Konkurrenz zu C # verlieren, wenn wir fortfahren, mit Vor-Java5-Weisen des Umgangs mit Überlegungen so zu haften". :) Ein Beispiel für "Pre-Java5-Methoden" finden Sie in JDK-1223179: Strings einschalten - eingereicht 1995 und schnell geschlossen als Won't Fix : "Halten Sie nicht den Atem an. Nichts Ähnliches ist in unseren Plänen . "
gnat
Vielen Dank, sehr interessant, um die Gründe zu sehen, die im Vorschlag vorgebracht wurden. Es fühlt sich immer noch falsch an zu sagen, dass wir einem Programm einen Typ "ohne guten Grund" hinzufügen - wir sind OO-Programmierer! :)
anotherdave
5
@anotherdave "objektorientiert" rechtfertigt die Einführung von Typen nur, wenn diese einen sinnvollen Zweck erfüllen. Offensichtlich stellte sich bei JCP die vorherrschende Meinung heraus, dass die Verwendung von Enums als hirnlose Wrapper für String-Konstanten in switch nicht als sinnvoll eingestuft werden kann
gnat
1
Wow, ich bin (auf eine gute Weise) überrascht zu sehen, dass der offizielle Vorschlag aktiv gegen Aufblähungen wirkt. Das ist erfrischend. Typ bloat ist ein großes Problem in Java.
Ben Lee
7

Abgesehen davon, dass der Code besser lesbar ist, ergeben sich potenzielle Leistungssteigerungen im if/else ifVergleich zu Vergleichen. Ob sich die Änderung lohnt, hängt davon ab, wie viele Vergleiche Sie durchführen würden. Ein String-Schalter wird als zwei separate Schalterbefehle ausgegeben. Die erste arbeitet auf Hash - Codes, so dass es eine tendenziell zu lookupswitch, wodurch man letztendlich O(log n)Komplexität. Der zweite ist immer perfekt O(1) tableswitch, daher ist die kombinierte Komplexität immer noch vorhanden O(log n). Eine einzelne lineare if/else ifAnweisungskette würde die O(n)Komplexität etwas verschlechtern .

Wenn Sie mehr als beispielsweise drei Zeichenfolgen vergleichen, switchist a wahrscheinlich lesbarer und kompakter. Die Leistung ist wahrscheinlich besser, obwohl Sie kaum einen Unterschied bemerken, es sei denn, Sie führen eine große Anzahl von Vergleichen auf einem Hot-Code-Pfad durch.

Mike Strobel
quelle
1
Ich fragte mich allerdings mehr, warum ich einen Schalter für eine Zeichenfolge anstelle eines Schalters für eine Aufzählung verwenden würde. Ich würde ein großes if/elseBlock-Bad-Practice in Betracht ziehen , aber im Moment hätte ich nicht viel Grund, ein solches zu verwenden.
Anotherdave
Aber dann würde eine Karte in Kombination mit dem Befehlsmuster bei gleicher Komplexität sogar zu einer besseren Lesbarkeit führen, da Sie die zusätzliche Art des Befehls haben
SpaceTrucker 18.11.13
3

Der Schalter für Zeichenfolgen kann verwendet werden, wenn Ihre enumWerte von außerhalb kommen, dh in einer Datenbank gespeichert sind.

Eine andere bemerkenswerte Sache in JDK 7 switchist, dass es viel leistungsfähiger ist als if-elseKonstrukte.

Ein nützlicher Anwendungsfall für schnelle Zeichenfolgen ist das switchAnalysieren von JSON / XML-Streams, wenn Sie zahlreiche Optionen für Knoten- und Attributtypen festlegen müssen. Ich kann mir keine bessere Option dafür vorstellen.

Andrey Chaschev
quelle
1
"Der Wechsel für Strings ist unersetzlich, wenn Ihre Enum-Werte von außen kommen, dh in einer Datenbank gespeichert sind.": Können Sie das näher erläutern? Die Zeichenfolgen in der switch-Anweisung sind fest codiert: Sobald die Zeichenfolgen in der Datenbank geändert werden, ist Ihr Code veraltet.
Giorgio,
Nun, Sie haben Recht - enums kann in diesem Fall aufgrund der statischen Natur von Java verwendet werden. Als ich dies schrieb, dachte ich über eine RoleSicherheitsbibliothek nach, die in der Regel als Klasse bereitgestellt wird und nicht abgelegt werden kann enum. Ein anderer Fall ist ein dynamisch kompilierter Java / Groovy-Code - in dieser Situation, die jedoch selten vorkommt, sind String-Schalter möglicherweise die bessere Option.
Andrey Chaschev
2

Einfachheit

String in Switch-Unterstützung ist nützlich für die Verarbeitung von Daten ohne Konvertierung in Enum oder if-elseLogik. Manchmal ist es einfach einfacher, String einzuschalten.

Aus dem Funktionsvorschlag der JDK 7-Mailingliste (Project Coin) ( @gnat answer )

Die Einführung einer Aufzählung für die umschaltbaren Konstanten, eine pro interessierendem Zeichenfolgewert, würde einem Programm ohne wichtigen Grund einen anderen Typ hinzufügen ...

If-Else-Version

Dies ist kurz, aber viele if'ssind schwer zu lesen. Und das ist langsam.

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");
}

Enum-Version

Aufzählungen müssen definiert werden, das ist gut, wird aber manchmal nicht benötigt.

enum Color {RED, GREEN}

Verarbeitung wie gewohnt

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 - Strings in switch-Statements-Version

Wir können verarbeiten, ohne zusätzliche Typen zu konvertieren und zu definieren.

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");
}
MᴀʀɪᴜsᴀʀɪᴜS
quelle
7
Hiermit wird jedoch nicht die Frage beantwortet, warum Sie hier Zeichenfolgen anstelle von Aufzählungen verwenden sollten.
Dave Newton
0

Die meisten Verbesserungen in einer Sprache bestehen darin, den Code besser lesbar zu machen. Ich bevorzuge jeden Tag lesbaren Code.

Sie können dies nicht glauben, aber versuchen Sie:

public enum JettStaff {
  ADRIAN("Adrian German") {
    public String toString() {
      return name + " ([email protected])";
    }
  },
  ARJIT("Arjit Sengupta") {
    public String toString() {
      return name + " ([email protected])";
    }
  },

  // and on for the rest...

  private String name;

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

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

quelle
Ihr Codebeispiel und Ihre obigen Kommentare sind unklar. Meinen Sie das Enum als Beispiel für etwas, das schwer zu lesen ist?
Anotherdave
2
Das ist sehr erfunden; Sie tun so, als ob die Aufzählung kein E-Mail-Feld hätte oder dies keine Klasse wäre.
Dave Newton
4
@ user2860598 Wenn Sie versuchen, einen Punkt zu verdeutlichen, verwenden Sie ein relevantes Beispiel. Es geht auch nicht darum, eine String-Konstante fett zu fingern.
Dave Newton
1
@ user2860598 Die Antwort, die Sie verlinkt haben, besagt, dass sie eingeführt wurden und dass sie zuvor mit einer Aufzählung "angenähert" werden konnten. Mein Punkt war, dass die Verwendung von Enum noch vorzuziehen scheint, auch mit ihrer Einführung.
Anotherdave
0

Enums sind großartig und Sie sollten diese anstelle von Strings verwenden, wenn Sie dazu in der Lage sind. Es gibt jedoch Situationen, in denen dies nicht möglich ist, beispielsweise wenn Sie mit externen Objekten von außerhalb von Java arbeiten müssen. Stellen Sie sich vor, Sie müssen etwas analysieren. Wie Serverantwort, Konfiguration, Protokolldatei oder ähnliches: Sie haben eine Reihe von Optionen, nach denen Sie suchen, und es gibt keine Möglichkeit, dass diese Aufzählungen sein könnten. In Java <7 steckst du also fest

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

Sie können in diesem Fall weiterhin Aufzählungen verwenden, indem Sie nur versuchen, diese nach Namen abzurufen, und / oder indem Sie eine benutzerdefinierte String-> Enum-Routine bereitstellen. Manchmal ist dies jedoch nicht möglich oder einfach nicht praktikabel (dh, wenn Sie zu viele Aufzählungen erstellen müssten).

TLDR : Sie sollten unbedingt Enums verwenden, wenn Sie ausschließlich mit Java-Code arbeiten, dies ist jedoch nicht immer mit externen Objekten möglich. Ich hoffe meine Erklärung macht Sinn.


quelle
Wenn Sie mit externen Daten zu tun haben und bereits genug wissen, um zu wissen, was Sie in Ihren ifAnweisungen benötigen , sollten Sie sie trotzdem einpacken , was bedeutet, dass Sie weiterhin Aufzählungen oder ein Befehlsmuster usw. verwenden können
Dave Newton
@ DaveNewton Ja, Sie können immer noch Aufzählungen verwenden, aber wie ich in meiner Antwort angegeben habe, ist es manchmal nicht praktisch, wenn Sie eine Reihe von Aufzählungen erstellen, die nur einmal während des Parsens in Ihrem Code verwendet werden sollen.
@dimoniy Aber wenn Sie Hunderte von Enum-Werten erstellen müssten, würde das nicht bedeuten, dass Sie mit einer Switch-Alternative Hunderte von case-Anweisungen haben müssten? Wenn es so viele Variablen gibt, würde ich definitiv die Typensicherheit von Aufzählungen vorziehen.
Anotherdave
0

Ich bin nicht der Meinung, dass es sauberer und lesbarer Code ist, wenn Sie Stringsin switch-Anweisungen verwenden, und denke, dass es eine schlechte Programmierpraxis ist. Wenn Sie den Wert ändern, den Sie zum Speichern verwenden, müssen Sie ihn bei jedem Switch oder if-elseif-Vorkommen ändern. Dies ist nicht gut, da Sie jedem Teil Ihres Codes fest codierte Werte zuweisen. Was machen Sie, wenn Sie eines Tages einen dieser hartcodierten Werte ändern? Suchen und ersetzen Sie jede Kopie davon?

Wenn Sie einige hartcodierte Werte haben, die Sie mit if-elseif-Anweisungen ausführen, ist die Verwendung von konstanten Grundwerten vor Java 1.5 viel besser, nur weil dies die Typensicherheit erhöht.

OK, es wird Situationen geben, in denen Sie Zeichenfolgenwerte erhalten (von HTTP-Anforderungen, Dateien usw.), und die Konvertierung in die primitiven Werte ist sehr schmerzhaft. Aber Enuman diesem Punkt machen wir einen guten Job. Wenn Sie den in Enum gespeicherten Wert ändern möchten, müssen Sie ihn nur bei der Deklaration ändern. An Ihrem Code müssen keine weiteren Änderungen vorgenommen werden. (Sie müssen natürlich die Werte ändern, die woanders gespeichert sind).

Natürlich ist es perfekt, wenn Sie nur einen schmutzigen und faulen Code implementieren. Sie möchten nicht viele Enums programmieren , sondern komplexe Software in großem Maßstab, die Sie umbringen wird.


quelle
-1

Wenn Sie wissen, welche Informationen eingehen und dass es sich nur um 5 Zustände handeln kann, verwenden Sie ein Enum. Wenn die möglichen Zustände jedoch über 9000 liegen und Sie nur 42 finden müssen, ist es besser, einen Schalter zu verwenden, da Sie nicht alle diese Zustände ausschreiben möchten.

In den meisten Fällen ist eine Aufzählung die beste Wahl, es sei denn, die möglichen Zustände sind unbekannt oder es gibt viele, und Sie kümmern sich nur um wenige.

Aber warum haben sie es jetzt eingeführt? Es war nur eine Änderung, die saubereren Code ermöglichte.

In Version 1.5 konnten Sie auch benutzerdefinierte Körper für Enums erstellen.


quelle
Aber würden Sie nicht einfach die anderen 8958 möglichen Werte dem einen Enum-Status zuweisen?
Anotherdave
@anotherdave Hier wird die defaultin switchum Spiel kommt. Ich weiß nicht, dass Sie einen Standardzustand mit haben können Enum, es sei denn, Sie machen einen Standardzustand, aber dann wird dieser Code nur aufgebläht, während a switchviel sauberer zu verwenden ist.
3
Es scheint seltsam zu sagen, dass ein UNKNOWNZustand auf einem Enum aufgedunsen ist, ein defaultFall auf einem Switch jedoch nicht.
Anotherdave