Generalized Target-Type Inference in Java – Java中的泛化目标类型推理

最后修改: 2018年 6月 13日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

Type Inference was introduced in Java 5 to complement the introduction of generics and was substantially expanded in following Java releases, which is also referred to as Generalized Target-Type Inference.

类型推理是在Java 5中引入的,以补充泛型的引入,并在随后的Java版本中得到大幅扩展,这也被称为广义的目标类型推理。

In this tutorial, we’ll explore this concept with code samples.

在本教程中,我们将通过代码样本来探讨这个概念。

2. Generics

2.通用型

Generics provided us with many benefits such as increased type safety, avoiding type casting errors and generic algorithms. You can read more about generics in this article.

泛型为我们提供了许多好处,如增加类型安全、避免类型转换错误和通用算法。你可以在这篇文章中阅读更多关于泛型的内容。

However, the introduction of generics resulted in the necessity of writing boilerplate code due to the need to pass type parameters. Some examples are:

然而,由于需要传递类型参数,引入generics导致必须编写模板代码。一些例子是。

Map<String, Map<String, String>> mapOfMaps = new HashMap<String, Map<String, String>>();
List<String> strList = Collections.<String>emptyList();
List<Integer> intList = Collections.<Integer>emptyList();

3. Type Inference Before Java 8

3.Java 8之前的类型推理

To reduce the unnecessary code verbosity due, Type Inference was introduced to Java which is the process of automatically deducing unspecified data types of an expression based on the contextual information.

为了减少不必要的代码冗长,类型推断被引入到Java中,它是根据上下文信息自动推断表达式的非指定数据类型的过程。

Now, we can invoke the same generic types and methods without specifying the parameter types. The compiler automatically infers the parameter types when needed.

现在,我们可以在不指定参数类型的情况下调用相同的通用类型和方法。编译器会在需要时自动推断出参数类型。

We can see the same code using the new concept:

我们可以看到使用新概念的相同代码。

List<String> strListInferred = Collections.emptyList();
List<Integer> intListInferred = Collections.emptyList();

In the above example, based on the expected return types List<String> and List<Integer>, the compiler is able to infer the type parameter to the following generic method:

在上面的例子中,根据预期的返回类型List<String>List<Integer>,编译器能够推断出以下泛型方法的类型参数。

public static final <T> List<T> emptyList()

As we can see, the resulting code is concise. Now, we can call generic methods as an ordinary method if the type parameter can be inferred.

正如我们所见,所产生的代码是简洁的。现在,如果可以推断出类型参数,我们可以像普通方法一样调用通用方法。

In Java 5, we could do Type-Inference in specific contexts as shown above.

在Java 5中,我们可以在特定的环境中进行类型推理,如上图所示。

Java 7 expanded the contexts in which it could be performed. It introduced the diamond operator <>. You may read more about the diamond operator in this article.

Java 7扩展了可执行的上下文。它引入了钻石运算符<>。您可以在此文章中阅读有关钻石运算符的更多信息。

Now, we can perform this operation for generic class constructors in an assignment context. One such example is:

现在,我们可以在赋值上下文中对泛型类构造函数进行这种操作。一个这样的例子是。

Map<String, Map<String, String>> mapOfMapsInferred = new HashMap<>();

Here, the Java Compiler uses the expected assignment type to infer the type parameters to HashMap constructor.

这里,Java编译器使用预期的赋值类型来推断HashMap构造器的类型参数。

4. Generalized Target-Type Inference – Java 8

4.广义的目标类型推理 – Java 8

Java 8 further expanded the scope of Type Inference. We refer to this expanded inference capability as Generalized Target-Type Inference. You may read the technical details here.

Java 8进一步扩展了类型推理的范围。我们将这种扩展的推理能力称为广义的目标类型推理。您可以阅读技术细节这里

Java 8 also introduced Lambda Expressions. Lambda Expressions do not have an explicit type.  Their type is inferred by looking at the target type of the context or situation. The Target-Type of an expression is the data type that the Java Compiler expects depending on where the expression appears.

Java 8还引入了Lambda表达式。Lambda表达式没有明确的类型。 它们的类型是通过查看上下文或情况的目标类型来推断的。表达式的目标类型是Java编译器根据表达式出现的位置所期望的数据类型。

Java 8 supports inference using Target-Type in a method context. When we invoke a generic method without explicit type arguments, the compiler can look at the method invocation and corresponding method declarations to determine the type argument (or arguments) that make the invocation applicable.

Java 8支持在方法上下文中使用Target-Type进行推理。当我们调用一个没有明确类型参数的通用方法时,编译器可以查看方法调用和相应的方法声明,以确定使该调用适用的类型参数(或参数)。

Let us look into an example code:

让我们看看一个示例代码。

static <T> List<T> add(List<T> list, T a, T b) {
    list.add(a);
    list.add(b);
    return list;
}

List<String> strListGeneralized = add(new ArrayList<>(), "abc", "def");
List<Integer> intListGeneralized = add(new ArrayList<>(), 1, 2);
List<Number> 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.

在代码中,ArrayList<>没有明确提供类型参数。所以,编译器需要推断它。首先,编译器查看了add方法的参数。然后,它查看在不同的调用中传递的参数。

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<String>, ArrayList<Integer> and ArrayList<Number>.

然后,编译器执行调用类型推理分析以确定参数的类型。预期的目标类型也被用于此分析中。它将三个实例中的参数推断为ArrayList<String>ArrayList<Integer>ArrayList<Number>

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

目标类型推理允许我们不为lambda表达式参数指定类型。

List<Integer> intList = Arrays.asList(5, 2, 4, 2, 1);
Collections.sort(intList, (a, b) -> a.compareTo(b));

List<String> 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.

这里,参数ab没有明确定义类型。 它们的类型在第一个Lambda Expression中被推断为Integer,在第二个中被推断为String

5. Conclusion

5.总结

In this quick article, we reviewed Type Inference, that along with generics and Lambda Expression enables us to write concise Java code.

在这篇文章中,我们回顾了类型推理,它与泛型和Lambda表达式一起,使我们能够编写简洁的Java代码。

As usual, the full source code can be found over on Github.

像往常一样,完整的源代码可以在Github上找到over