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

时间:2018-01-24 17:31:01

标签: java java-7 type-inference diamond-operator java-10

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

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

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

var list = new ArrayList<>();

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

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

谢谢!

3 个答案:

答案 0 :(得分: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<>() {};

答案 1 :(得分:21)

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

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

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

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

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

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

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

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

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

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

答案 2 :(得分: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