Java 10:Java 7的Diamond推理是否适用于本地类型推断?

问题描述 投票:34回答:3

JEP 286,我们看到我们将能够在JDK 10(18.3)中使用局部类型推断(var)。 JEP表示以下编译,这是预期的:

var list = new ArrayList<String>();  // infers ArrayList<String>

我很想知道如果我们尝试以下内容会发生什么:

var list = new ArrayList<>();

我在第二个片段中提出的建议是否会编译?如果是这样(我怀疑),ArrayList会接受Object作为它的通用类型吗?

我自己尝试一下,但我无法访问任何我可以安装早期版本的机器。

谢谢!

java java-7 type-inference diamond-operator java-10
3个回答
28
投票

是的,var和钻石运营商可以合并在一起。编译器将推断出最具体的泛型类型:

var list = new ArrayList<>(); // Infers ArrayList<Object>
var list = new ArrayList<>(List.of(1, 2, 3)); // Infers ArrayList<Integer>

你甚至可以将它们与匿名类结合起来:

var list = new ArrayList<>() {};

21
投票

“与......合作”是一个模糊的问题,因此您可能会得到模糊的答案。

类型推断不是介意阅读;这只是约束解决。可用的类型约束越少,您遇到失败的可能性就越大或结果令人惊讶(推断出您不期望的类型,例如Object。)

Diamond说:我需要的类型可能已经存在于左侧,为什么在右侧重复它们。

局部变量类型推断说:我需要的类型可能已经存在于右侧,为什么在左侧重复它们。

通用方法调用说:我需要的类型可能已经存在于参数中,为什么要重复它们作为见证。

如果程序中有足够的类型信息,而没有清单构造函数类型参数或左侧的目标类型,那么一切都会好的。例如:

List<String> anotherList = ...
var list = new ArrayList<>(anotherList);

在这里,编译器能够通过查看构造函数的参数类型(采用ArrayList的参数)来推断Collection<? extends E>的类型参数。所以它在RHS上推断T=String,然后能够在LHS上推断出ArrayList<String>

换句话说,编译器将根据您提供的信息执行所需的操作。您提供的信息越少,它就越有可能失败,或者没有做您想做的事情。

那就是说,我认为你问的是错误的问题。你可以遗漏多少的问题不应该由“编译器让我遗漏多少”来驱动,而是“我对程序的可读性造成了多大的伤害”。阅读代码比编写代码更重要。省去你可能遗漏的所有东西,不太可能最大限度地提高可读性。您应该努力留下足够的空间,以确保在面对您的计划时没有读者感到困惑。


12
投票

是的,它会编译。代码中的var

var list = new ArrayList<>();

应该推断为类型ArrayList<Object>(我相信人们可能无法确定由于擦除而导致的元素的确切类型),这与使用如下代码相同:

ArrayList list = new ArrayList<>(); 
// without the type of the element of list specified

其中list最终被推断为ArrayList<Object>


来自Brian的FAQ on the mailing list: -

如果我们要求双方推断会怎么样?

如果你说:

var x = new ArrayList<>() 

然后你要求编译器推断出List的类型参数和x的类型。

但是你没有为编译器提供足够的类型信息来做好工作。

在大多数情况下,您将收到一个信息丰富的编译器错误,告诉您要求您的头脑被阅读。在某些情况下,我们将回归推断Object,正如我们目前所做的那样:

Object o = new ArrayList<>()  // always inferred ArrayList<Object> here
© www.soinside.com 2019 - 2024. All rights reserved.