Generalisierte Zieltypinferenz in Java

1. Einleitung

Type Inference wurde in Java 5 eingeführt, um die Einführung von Generika zu ergänzen, und in den folgenden Java-Versionen, die auch als Generalized Target-Type Inference bezeichnet werden, erheblich erweitert.

In diesem Tutorial werden wir dieses Konzept anhand von Codebeispielen untersuchen.

2. Generika

Generika boten uns viele Vorteile wie erhöhte Typensicherheit, Vermeidung von Typumwandlungsfehlern und generische Algorithmen. Weitere Informationen zu Generika finden Sie in diesem Artikel.

Die Einführung von Generika führte jedoch dazu, dass Boilerplate-Code geschrieben werden musste, da Typparameter übergeben werden mussten . Einige Beispiele sind:

Map
    
      mapOfMaps = new HashMap
     
      (); List strList = Collections.emptyList(); List intList = Collections.emptyList();
     
    

3. Geben Sie Inference Before Java 8 ein

Um die unnötige Ausführlichkeit des Codes zu verringern, wurde Type Inference in Java eingeführt. Dabei werden automatisch nicht spezifizierte Datentypen eines Ausdrucks basierend auf den Kontextinformationen automatisch abgeleitet.

Jetzt können wir dieselben generischen Typen und Methoden aufrufen, ohne die Parametertypen anzugeben. Der Compiler leitet die Parametertypen bei Bedarf automatisch ab.

Mit dem neuen Konzept können wir denselben Code sehen:

List strListInferred = Collections.emptyList(); List intListInferred = Collections.emptyList(); 

Im obigen Beispiel kann der Compiler basierend auf den erwarteten Rückgabetypen List und List den Typparameter auf die folgende generische Methode ableiten:

public static final  List emptyList() 

Wie wir sehen können, ist der resultierende Code präzise. Jetzt können wir generische Methoden als gewöhnliche Methode aufrufen, wenn der Typparameter abgeleitet werden kann.

In Java 5 können wir Typinferenz in bestimmten Kontexten durchführen, wie oben gezeigt.

Java 7 erweiterte die Kontexte, in denen es ausgeführt werden konnte. Es wurde der Diamantoperator eingeführt. Weitere Informationen zum Diamantoperator finden Sie in diesem Artikel.

Jetzt können wir diese Operation für generische Klassenkonstruktoren in einem Zuweisungskontext ausführen. Ein solches Beispiel ist:

Map
    
      mapOfMapsInferred = new HashMap();
    

Hier verwendet der Java-Compiler den erwarteten Zuweisungstyp, um die Typparameter auf den HashMap- Konstruktor abzuleiten .

4. Generalisierte Zieltypinferenz - Java 8

Java 8 hat den Umfang der Typinferenz weiter erweitert. Wir bezeichnen diese erweiterte Inferenzfunktion als Generalized Target-Type Inference. Die technischen Details können Sie hier lesen.

Java 8 führte auch Lambda Expressions ein. Lambda-Ausdrücke haben keinen expliziten Typ. Ihr Typ wird abgeleitet, indem der Zieltyp des Kontexts oder der Situation betrachtet wird. Der Zieltyp eines Ausdrucks ist der Datentyp, den der Java-Compiler erwartet, je nachdem, wo der Ausdruck angezeigt wird.

Java 8 unterstützt die Inferenz mit Target-Type in einem Methodenkontext. Wenn wir eine generische Methode ohne explizite Typargumente aufrufen, kann der Compiler den Methodenaufruf und die entsprechenden Methodendeklarationen überprüfen, um das Typargument (oder die Argumente) zu bestimmen, die den Aufruf anwendbar machen.

Schauen wir uns einen Beispielcode an:

static  List add(List list, T a, T b) { list.add(a); list.add(b); return list; } List strListGeneralized = add(new ArrayList(), "abc", "def"); List intListGeneralized = add(new ArrayList(), 1, 2); List numListGeneralized = add(new ArrayList(), 1, 2.0);

In the code, ArrayList does not provide the type argument explicitly. So, the compiler needs to infer it. First, the compiler looks into the arguments of the add method. Then, it looks into the parameters passed at different invocations.

It performs invocation applicability inference analysis to determine whether the method applies to these invocations. If multiple methods are applicable due to overloading, the compiler would choose the most specific method.

Then, the compiler performs invocation type inference analysis to determine the type arguments.The expected target types are also used in this analysis. It deduces the arguments in the three instances as ArrayList, ArrayList and ArrayList.

Target-Type inference allows us to not specify types for lambda expression parameters:

List intList = Arrays.asList(5, 2, 4, 2, 1); Collections.sort(intList, (a, b) -> a.compareTo(b)); List strList = Arrays.asList("Red", "Blue", "Green"); Collections.sort(strList, (a, b) -> a.compareTo(b));

Here, the parameters a and b do not have explicitly defined types. Their types are inferred as Integer in the first Lambda Expression and as String in the second.

5. Conclusion

In diesem kurzen Artikel haben wir die Typinferenz besprochen, die es uns zusammen mit Generika und Lambda-Ausdruck ermöglicht, präzisen Java-Code zu schreiben.

Wie immer finden Sie den vollständigen Quellcode auf Github.