Home > Informatik > Begriffe und Konzepte > Typinferenz

Typinferenz

Definition

Typinferenz

Typinferenz bezeichnet die Fähigkeit des Java-Compilers, den Datentyp eines Ausdrucks automatisch aus dem Kontext abzuleiten, zu inferieren. Anstatt jeden Typ explizit hinzuschreiben (z. B. String s = "Hallo"), "errät" der Compiler den Typ anhand des zugewiesenen Wertes.

Vorteile
  • Der Code wird etwas kürzer und damit lesbarer.
  • Die Namen der Variablen und ihr Inhalt rücken in den Vordergrund, nicht der Datentyp.
  • Der Schreibstil von Java nähert sich dem Schreibstil moderner Programmiersprachen wie Python an, ohne aber an Typsicherheit zu verlieren.

Typinferenz mit var

Seit Java 10 ist für lokale Variablen (und nur für diese!) das Schlüsselwort var eingeführt worden [2].

Vorher:

Gegenstand g = new Gegenstand();

String message = "Hallo Welt";

int zahl = 42;

Mit var:

var g = new Gegenstand();

var message = "Hallo Welt";

zahl = 42;

Der Compiler sieht, dass die Variable g ein Objekt der Klasse Gegenstand ist und weiß sofort, dass g vom Typ Gegenstand ist. Die Variable message wird sofort als String erkannt, und die Variable zahl sofort als int.

Wichtige Regeln zum Umgang mit var

Typinferenz in Java ist nicht gleichbedeutend mit dynamischer Typisierung wie in anderen Programmiersprachen. Java bleibt statisch typisiert (siehe Typsysteme).

  • Var darf nur lokal verwendet werden.
  • Instanzvariablen von Klassen dürfen nicht mit var deklariert werden, sondern nur auf die herkömmliche Weise.
  • Man muss einer Variablen, die mit var deklariert wurde, sofort einen gültigen Wert zuweisen.

    var x = 3; → wird als int-Variable erkannt

    var y = 3.1415; → wird als double-Variable erkannt

    var name = "Meier"; → wird als String-Variable erkannt

  • Man darf einer var-Variablen nicht den Wert null zuweisen!
  • Man sollte var nur dann nutzen, wenn der Typ offensichtlich ist.

    var kunde = new Kunde(); // Typ ist offensichtlich Kunde
    var daten = service.getInfo(); // Typ ist nicht offensichtlich; hier nicht verwenden!

    Bei dem zweiten Beispiel muss man erst in der Dokumentation der Klassen nachschauen, welchen Datentyp die Methode getInfo() eigentlich zurückliefert. Das erschwert die Lesbarkeit des Codes enorm!

Typinferenz beim Diamond-Operator

Vor Java 7 musste man bei der Verwendung von Generics beispielsweise schreiben

ArrayList <String> namensliste = new ArrayList <String>();

Seit Java 7 kann man den Diamant-Operator einsetzen:

ArrayList <String> namensliste = new ArrayList <>();

Bei der Initialisierung des ArrayList-Objekts muss also nicht mehr der Datentyp (hier String) angegeben werden, sondern es reicht <>, dieses Klammerpaar wird als Diamant-Operator bezeichnet. Der Compiler erkennt automatisch, dass hier eine String-ArrayList erzeugt werden soll.

Diamant-Operator und var

In dem Buch "Java ist auch eine Insel" [1] sind folgende Beispiele angegeben:

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

var list2 = new ArrayList<String>();

var list3 = new ArrayList<>();

Das erste Beispiel entspricht dem, was wir bereits gesagt haben, allerdings mit dem Unterschied, dass der Typ auf der linken Seite die Oberklasse von ArrayList ist.

Das zweite Beispiel ist interessant, weil hier auf die Typangabe <String> auf der linken Seite verzichtet wird; dafür muss dann der Typ aber auf der rechten Seite der Initialisierung stehen.

Das dritte Beispiel wird kompiliert, allerdings weiß der Compiler nicht, welche Datentypen in der ArrayList gespeichert werden sollen und nimmt daher einfach den Datentyp Object an.

ChatGPT zu Typinferenz in Java

Diese HTML-Section wurde komplett von ChatGPT 5.2 geschrieben und von mir nicht bearbeitet!
Nach einer ersten Durchsicht scheint der Text völlig in Ordnung zu sein, allerdings geht ChatGPT am Ende auf Begriffe ein, die in den ersten Semestern kaum behandelt werden, zum Beispiel Lamda-Ausdrücke.

Unter Typinferenz versteht man in Java, dass der Compiler einen fehlenden Typ in einer Deklaration aus dem Kontext ableitet. Wichtig: Java bleibt dabei statisch typisiert. Der Typ wird also zur Compile-Zeit festgelegt, nicht erst zur Laufzeit.

Grundidee

In vielen Situationen ist der Typ "offensichtlich", weil rechts vom Zuweisungsoperator bereits ein Ausdruck steht, der den Typ eindeutig festlegt. Statt den Typ doppelt zu schreiben, kann man ihn teilweise weglassen. Die Typinferenz dient daher vor allem der Reduktion von Boilerplate (wiederholtem, wenig aussagekräftigem Code) und verbessert oft die Lesbarkeit.

Typische Formen der Typinferenz in Java
1) Lokale Variablen mit var (seit Java 10)

Mit var kann man den Typ lokaler Variablen dem Compiler überlassen. Der tatsächliche Typ ist trotzdem eindeutig vorhanden (und kann z. B. von der IDE angezeigt werden).

				var name = "Müller";        // Typ: String
				var anzahl = 12;            // Typ: int
				var liste = new ArrayList<String>();  // Typ: ArrayList<String>
					

Wichtige Einschränkungen:

  • var funktioniert nur bei lokalen Variablen (nicht bei Feldern/Attributen, nicht bei Parametern, nicht bei Rückgabetypen).
  • Eine Initialisierung ist Pflicht: var x; ist nicht erlaubt.
  • var x = null; ist nicht erlaubt, weil der Typ dann nicht ableitbar ist.
2) Generics: Diamond-Operator <> (seit Java 7)

Bei generischen Klassen kann der Compiler die Typparameter oft aus der linken Seite ableiten. Dann genügt rechts der Diamond-Operator:

				ArrayList<String> namen = new ArrayList<>();
				HashMap<String, Integer> map = new HashMap<>();
					

Das ist ebenfalls Typinferenz: Die Typargumente auf der rechten Seite werden aus der Deklaration links erschlossen.

3) Typinferenz bei Methodenaufrufen (insbesondere bei Generics)

Auch bei generischen Methoden kann Java Typparameter aus den Argumenten und dem erwarteten Ergebnistyp ableiten. Das sieht man oft bei Hilfsmethoden wie List.of(...) oder bei eigenen generischen Methoden.

4) Zieltyp (Target Typing) bei Lambdas und Methodenreferenzen

Ein Lambda-Ausdruck hat nicht "von sich aus" einen Typ. Der Typ ergibt sich aus dem funktionalen Interface, das erwartet wird (z. B. Runnable, Predicate<T>, Function<T,R>). Auch das ist eine Form von Typinferenz: Der Kontext legt fest, welche Parameter- und Rückgabetypen gemeint sind.

Was Typinferenz nicht ist
  • Keine dynamische Typisierung: Der Typ ändert sich nicht zur Laufzeit. Eine Variable, die als var deklariert ist, hat trotzdem einen festen Typ.
  • Kein "Typ ist egal": Typinferenz bedeutet nicht, dass Java auf Typprüfung verzichtet. Im Gegenteil: Die Typprüfung läuft wie gewohnt, nur der Typ wird automatisch eingesetzt.
Vorteile und Risiken

Vorteile: Weniger Wiederholungen, kompakterer Code, bei langen generischen Typen oft deutlich besser lesbar.

Risiken: Wenn der Initialisierungsausdruck komplex ist, kann var die Lesbarkeit verschlechtern, weil man den Typ "im Kopf" rekonstruieren muss. Außerdem können unerwartete Typen entstehen, wenn man sich über Literale oder Rückgabetypen täuscht.

Mini-Beispiel: "Offensichtlich" vs. "unklar"

Gut lesbar:

				var liste = new ArrayList<String>();
					

Eher ungünstig, wenn man den Rückgabetyp nicht kennt:

				var ergebnis = berechneIrgendetwas(a, b, c);
					

Hier ist oft ein ausgeschriebener Typ (oder zumindest ein sprechender Methodenname) didaktisch sinnvoll.

Quellen:

  1. Ullenboom: Java ist auch eine Insel, Rheinwerk Computing 2023.
  2. Balzert, Arinir: Objektorientiert Programmieren, 4. Auflage, Springer-Verlag Berlin 2025.