Typinferenz für lokale Variablen in Java 10, Teil 1

Seite 3: Worauf sollte man bei der Verwendung achten?

Inhaltsverzeichnis

Wenn man sich grundsätzlich für die Verwendung von var entschieden hat, gibt es einige Details und Fallstricke zu beachten. Den wichtigsten Aspekt hat der Artikel bereits ausgiebig besprochen: gute Variablennamen.

Direkt an zweiter Stelle steht eine aussagekräftige Initialisierung: Die rechte Seite einer Deklaration mit var sollte klarmachen, welchen Typ die Variable hat. Ein Kostruktoraufruf wie new URL("...") kommt dabei super weg – hier ist der Typ eindeutig. Bei Methodenaufrufen wie codefx.openConnection() ist die Lage weniger eindeutig, aber bei häufig verwendeten APIs mit sprechenden Namen kann man davon ausgehen, dass Entwickler den Typ oder zumindest seine Intention ableiten können.

Methoden, die man selten verwendet, die keinen guten Namen haben oder bei denen nicht offensichtlich ist, auf welchem Zustand sie operieren, sollten eher nicht var verwenden. Bei einer Zeile wie

var id = create();

ist der Typ nur schwer zu erkennen. Allerdings ist hier weniger var das Problem als create() – den Methodennamen kann man vielleicht noch verbessern.

Bei der Deklaration gibt es zwei technische Fallstricke zu beachten:

  • Sind Generics im Spiel, sollten Entwickler nicht den Diamond-Operator verwenden, denn ohne Typinformation auf der linken Seite kommt es zur Ableitung des allgemeinsten zulässigen Typs, also meist Object:
  // this delcares an 'ArrayList<Object>'
var users = new ArrayList<>();


  • Zahlliterale wie 42 beziehungsweise 0x2A ergeben immer ein int als Ableitung. Wer long benötigt, kann L anhängen, also 42L. Für byte oder short gibt es keine Abkürzung – hier ist der Typ explizit anzugegeben.

Damit der Typ einer Variable immer im Blickfeld bleibt, sollte ihr Geltungsbereich nicht allzu groß sein. Es gilt die Anzahl der Zeilen zwischen der Deklaration und der letzten Verwendung zu minimieren. Hier erzeugt var allerdings weniger einen neuen Umstand als einen existierenden zu betonen, denn diese Praxis trägt auch bei expliziten Typen zur Lesbarkeit des Codes bei.

Zuletzt sei noch etwas zu Interfaces und ihren Implementierungen gesagt. Es ist generell gute Praxis, Variablen den allgemeinsten Typ zu geben, der die an sie gestellten Anforderungen erfüllt. Am besten drückt sich das wohl in einer Zeile wie

List<String> names = new ArrayList<>();

aus, bei der man names als List deklariert und nicht als ArrayList. Dadurch ist es einfacher, die konkrete Implementierung auszutauschen, wenn neue Umstände das erfordern.

Die Zeile

var names = new ArrayList<String>(); 

deklariert names allerdings als ArrayList. Das ist im ersten Moment etwas ungewöhnlich. Da man var aber nur mit lokalen Variablen verwendet und diese innerhalb einer Methode nur einen kleinen Wirkungsbereich haben sollten, stellt sich das nicht als großes Problem heraus. Es ist unwahrscheinlich, dass aus dieser Deklaration versehentlich kritische Abhängigkeiten auf ArrayList entstehen, die einen späteren Austauch gegen LinkedList erschweren oder gar verhindern.

Aufpassen muss man allerdings beim Extrahieren von Methoden, Parametern oder Feldern – insbesondere mit IDE-Unterstützung. Dabei geschieht es schnell, dass versehentlich der konkrete Typ Teil der Signatur der neuen Methode oder des Parameters/Felds wird. Damit ist sein Geltungsbereich auf einmal nicht mehr ein paar Zeilen, sondern die ganze Klasse oder gar darüber hinaus. Das macht es wesentlich einfacher, sich versehentlich auf den konkreten Typ statt auf das Interface zu verlassen.

Viele Sprachen, die var anbieten, haben ein zweites Schlüsselwort, mit dem man verhindern kann, dass die Variable neu zugewiesen wird. So deklariert man zum Beispiel in JavaScript mit const url = "..." eine Variable url, die niemals einen neuen Wert erhalten kann. Umfragen und Erfahrungen mit Prototypen haben aber ergeben, dass in der Community keine Einigkeit darüber herrscht, wie das in Java aussehen sollte.

Deswegen hat man für Java 10 beschlossen, es zunächst bei var zu belassen. Wer sicherstellen will, dass eine solche Variable nicht neu zugewiesen wird, kann wie gewohnt final voranstellen:

final var codefx = new URL("http://codefx.org");
final var connection = codefx.openConnection();
final var reader = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
readFirstLines(reader);