Letzte Variablenzuweisung mit try / catch

73

Da ich glaube, dass dies eine gute Programmierpraxis ist, mache ich alle meine (lokalen oder Instanz-) Variablen, finalwenn sie nur einmal geschrieben werden sollen.

Ich stelle jedoch fest, dass Sie eine Variable nicht endgültig machen können, wenn eine Variablenzuweisung eine Ausnahme auslösen kann:

final int x;
try {
    x = Integer.parseInt("someinput");
}
catch(NumberFormatException e) {
    x = 42;  // Compiler error: The final local variable x may already have been assigned
}

Gibt es eine Möglichkeit, dies zu tun, ohne auf eine temporäre Variable zurückzugreifen? (oder ist dies nicht der richtige Ort für einen endgültigen Modifikator?)

dtech
quelle
1
Ich bezweifle, dass Sie dies ohne eine temporäre Variable tun können.
NPE
10
final int x = makeX();bestimmt. (Try-Catch-In-Funktion)
Joop Eggen
2
Schockierend, dass das JDK noch keine hattryParse .
TJ Crowder
11
Um ganz klar zu sein, der Compilerfehler ist falsch, nicht wahr? Es gibt keinen Umstand, unter dem x im angegebenen Beispiel zweimal zugewiesen werden könnte.
jaco0646
4
@ jaco0646, es verlangt vom Compiler viel, dass er dies im Allgemeinen erhält, wenn der try-Block mehrere Zeilen enthält, in denen die Ausnahme auftreten kann. Es wäre jedoch schön, einen Ausnahmefall für diesen Zweck zu haben, um festzustellen, wann die Zuweisung die letzte Aussage im Versuch ist.
Joshua Goldberg

Antworten:

66

Eine Möglichkeit, dies zu tun, besteht darin, eine (nicht final) temporäre Variable einzuführen , aber Sie sagten, dass Sie das nicht wollten.

Eine andere Möglichkeit besteht darin, beide Zweige des Codes in eine Funktion zu verschieben:

final int x = getValue();

private int getValue() {
  try {
    return Integer.parseInt("someinput");
  }
  catch(NumberFormatException e) {
    return 42;
  }
}

Ob dies praktikabel ist oder nicht, hängt vom genauen Anwendungsfall ab.

Alles in allem xkönnte der praktischste allgemeine Ansatz darin bestehen, sie nicht zu belassen , solange es sich um eine lokale Variable mit angemessenem Umfang handelt final.

Wenn es sich andererseits xum eine Mitgliedsvariable handelt, würde ich empfehlen, finalwährend der Initialisierung eine nicht temporäre Variable zu verwenden :

public class C {
  private final int x;
  public C() {
    int x_val;
    try {
      x_val = Integer.parseInt("someinput");
    }
    catch(NumberFormatException e) {
      x_val = 42;
    }
    this.x = x_val;
  }
}
NPE
quelle
Für einen lokalen Bereich stimme ich Ihnen zu, dies tritt jedoch am häufigsten bei Instanzvariablen auf.
dtech
Ich denke, es könnte einen Fehler widerspiegeln, der keinen statischen Verweis auf die nicht statische Methode getValue () geben kann.
Daher
1
Wenn this.x ein Objekttyp wie Integer ist, brauchen Sie (leider) etwas mehr. Wenn Sie x_val nicht deklariert lassen, beschwert sich der Compiler, dass es möglicherweise nicht initialisiert wurde. Wenn der Fallback für den catch-Block null ist, müssen Sie vorab auf null initialisieren und entweder aus Gründen der Übersichtlichkeit redundant null im catch zuweisen (das ist meine Präferenz) oder einen leeren catch haben.
Joshua Goldberg
Was @JoshuaGoldberg sagt, gilt auch für primitive Typen. Wir haben genau das gleiche Codemuster, bei dem das Mitglied in der Rolle this.xein Primitiv ist boolean, ebenso wie die lokale Variable. Selbst mit Java 9 erhalten wir "<thing_in_the_role_of_ x_val> wurde möglicherweise nicht initialisiert". Das Fehlen einer Kontrollflussanalyse für diese Situation ist frustrierend, kann aber leicht umgangen werden.
Ti Strga
-1

Nein, es ist nicht der richtige Ort. Stellen Sie sich vor, Sie haben mehr als 1 Anweisung in Ihrem Try-and-Catch-Block. Die erste lautet: x = 42. Nach einigen anderen Anweisungen schlägt der Try-Block fehl und geht zum Catch-Block, in dem Ihre Sprich x = 30. Jetzt hast du x zweimal definiert.

SomeJavaGuy
quelle
13
Der Compiler ist klug genug zu wissen, welche Anweisungen welche Ausnahmen auslösen. Es ist möglicherweise nicht in allen Fällen möglich, aber genau wie der Compiler Sie in einigen Fällen über toten Code usw. informieren kann, sollte er in der Lage sein, herauszufinden, ob final funktionieren würde.
Stefan
Um das zu unterstützen, was @Stefan gesagt hat, kann Clang dies beim Kompilieren von Swift herausfinden.
Franklin Yu