Local Variable Type Inference in Java 10

04.05.2018

Die Local Variable Type Inference ist sicherlich das Feature für das Java 10 bekannt ist – ähnlich wie Generics bei Java 5, oder Lambdas und Streams bei Java 8.

Java 10 ist nun auch schon wieder über einen Monat alt. Höchste Zeit also, um sich das wohl bedeutendste Feature des Releases mal ein wenig näher anzuschauen.

Worum geht es dabei?

Im wesentlichen um die Möglichkeit, dass bei der Deklaration von lokalen Variablen der Typ weggelassen werden kann. Statt Angabe eines Typs schreibt man einfach var.

Das Ganze funktioniert übrigens nur in lokalen Scopes, also innerhalb von Methoden oder Blöcken, nicht aber bei Klassenvariablen oder Methodenparametern. Daher auch der Name Local Variable Type Inference.

Ein paar Beispiele:

var hello = "Hello World!";
var answer = 42;
var pi = 3.14159;
var notTrue = false;
var list = List.of("abc");
var anotherList = new ArrayList<Integer>();

Was bedeutet das? 

Ganz einfach: der Compiler leitet den Typ vom Initialisierungs-Ausdruck ab, so dass man den Typ auf der linken Seite vom Gleichheitszeichen nicht mehr explizit hinschreiben muss. Das heißt also: Die Variable hello aus obigem Beispiel bekommt  den Typ String, die Variable answer den primitiven Datentyp int, pi ist vom Typ double, notTrue ist ein boolean.

Die Variable list bekommt den Typ List; anotherList dagegen den Typ ArrayList<Integer>. Letzteres bedeutet, dass man in Folge auch anotherList.ensureCapacity(42); schreiben kann! Hier wird also eine Methode aufgerufen, die es nur in ArrayList gibt, aber nicht im List-Interface oder anderen List-Implementierungen.

Ist das schlecht? Üblicherweise verwendet man ja das Interface als Typ, um sich nicht an eine konkrete Implementierung zu binden. Im Falle von var lässt sich das jedoch verschmerzen, da sich das Ganze in einem sehr begrenzten Scope abspielt (Stichwort „local“), und eine Änderung der Implementierung daher einen recht überschaubaren Aufwand bedeuten würde.

Was bedeutet es nicht?

Zunächst einmal könnte man vermuten, dass es sich bei var um ein neues Keyword handelt. Doch das ist es nicht. Deswegen funktioniert auch folgendes:

var var = "a variable named var";
System.out.println(var);

Man muss sich also keine Sorgen machen, dass bestehender Code aus früheren Versionen mit Java 10 nicht mehr compiliert, wenn dort Variablen mit dem Namen var vorkommen. Rückwärtskompatibilität ist also gewährleistet.

Weiterhin bedeutet es nicht, dass mit var die dynamische Typisierung in Java Einzug hält. Gerade bei Entwicklern die viel mit JavaScript zu tun haben, könnte leicht dieser Eindruck entstehen. Jedoch ist und bleibt Java eine streng typisierte Sprache, daran ändert auch das var-Feature nichts.

Was ist mit val?

Wer Scala kennt dürfte sich jetzt fragen, ob neben var auch val eingeführt wurde. Mit val werden in Scala Konstanten definiert, also „Variablen“, deren Wert sich nach der Initialisierung nicht mehr ändern darf. Diese Überlegung gab es im Rahmen der Implementierung des Features ebenfalls, doch man entschied sich dagegen, so dass für unveränderliche Werte in Java final var verwendet wird.

Ein paar Feinheiten

Der „Diamond-Operator“ <> sollte im Zusammenhang mit var nicht verwendet werden. Die Deklaration var list = new ArrayList<>(); resultiert nämlich im Typ ArrayList<Object>. Gleichermaßen ergibt var list = List.of() den Typ List<Object>, sowie var opt = Optional.empty(); den Typ Optional<Object>.

Was nicht funktioniert:

var nil = null;    // kompiliert nicht -> von null kann kein Typ abgeleitet werden
var uninitialized; // kompiliert nicht -> die Initialisierung muss immer zusammen mit der Deklaration erfolgen
var x = 0, y = 1;  // kompiliert nicht -> Mehrfachdeklaration u. -Initialisierung ist nicht möglich

Was früher unmöglich war:

var person = new Object() {
   String name = "Arthur";
   int age = 42;
};
System.out.println(person.name + " aged " + person.age);

Vor Java 10 musste man das Objekt person mit dem Typ Object deklarieren. Dadurch ging die Möglichkeit des Zugriffs auf die Felder name und age verloren. Mit var bekommt man einen erweiterten Typ, der auch die beiden Felder beinhaltet, auf die somit auch von außen zugegriffen werden kann. Ein praktischer Nutzen hierfür wollte sich mir allerdings noch nicht so recht erschließen.

Wann verwende ich var?

Nun zur entscheidenden Frage – soll man var nun verwenden oder nicht? Wie immer kann man das nicht mit einem pauschalen Ja oder Nein beantworten. Dies muss jeweils im Einzelfall entschieden werden. Als Faustregel sollte gelten: Ja, wenn es die Lesbarkeit und Verständlichkeit des Codes verbessert. Nein, wenn der Code mit expliziter Typangabe verständlicher ist.

Als Richtlinie gibt es dafür einen Styleguide, der anhand von Beispielen erläutert, wann die Verwendung von var sinnvoll ist und wann nicht:
http://openjdk.java.net/projects/amber

Zurück zur Übersicht

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*Pflichtfelder

*