From JEP 286, we see that we'll be able to utilize local type inference (var
) in JDK 10 (18.3). The JEP states that the following compiles, which is expected:
从JEP 286开始,我们看到我们将能够在JDK 10(18.3)中使用本地类型推断(var)。 JEP表示以下编译,这是预期的:
var list = new ArrayList<String>(); // infers ArrayList<String>
I'm curious to know what would happen if we attempt the following:
我很想知道如果我们尝试以下内容会发生什么:
var list = new ArrayList<>();
Will what I proposed in the second snippet even compile? If so (which I doubt), would the ArrayList
accept Object
as its generic type?
我在第二个片段中提出的建议是否会编译?如果是这样(我怀疑),ArrayList是否会接受Object作为其泛型类型?
I'd try this myself, but I don't have access to any machines which I can install early releases on.
我自己尝试一下,但是我无法访问任何我可以安装早期版本的机器。
Thanks!
3 个解决方案
#1
27
Yes, var
and the diamond operator can be combined together. The compiler will infer the most specific generic type:
是的,var和钻石操作符可以组合在一起。编译器将推断出最具体的泛型类型:
var list = new ArrayList<>(); // Infers ArrayList<Object>
var list = new ArrayList<>(List.of(1, 2, 3)); // Infers ArrayList<Integer>
And you can even combine them with an anonymous class:
你甚至可以将它们与匿名类结合起来:
var list = new ArrayList<>() {};
#2
20
"Work with" is a vague question, so you're likely to get vague answers.
“与...合作”是一个模糊的问题,因此您可能会得到模糊的答案。
Type inference is not mind reading; it's just constraint solving. The fewer type constraints available, the more likely you are to encounter failure or a surprising result (inferring a type that you didn't expect, such as Object
.)
类型推断不是介意阅读;这只是约束解决。可用的类型约束越少,您遇到失败的可能性就越大或结果令人惊讶(推断出您不期望的类型,例如Object。)
Diamond says: the types I need are probably already present on the left hand side, why repeat them on the right.
Diamond说:我需要的类型可能已经存在于左侧,为什么在右侧重复它们。
Local variable type inference says: the types I need are probably already present on the right hand side, why repeat them on the left.
局部变量类型推断说:我需要的类型可能已经存在于右侧,为什么在左侧重复它们。
Generic method invocation says: the types I need are probably already present in the arguments, why repeat them as witnesses.
通用方法调用说:我需要的类型可能已经出现在参数中,为什么要重复它们作为见证。
If sufficient type information is available in the program without either manifest constructor type arguments or a target type on the left, everything will be fine. For example:
如果程序中有足够的类型信息,而没有清单构造函数类型参数或左侧的目标类型,那么一切都会好的。例如:
List<String> anotherList = ...
var list = new ArrayList<>(anotherList);
Here, the compiler is able to infer the type parameter of ArrayList
by looking at the type of the argument to the constructor (the one that takes Collection<? extends E>
). So it infers T=String
on the RHS, and then is able to infer ArrayList<String>
on the LHS.
这里,编译器能够通过查看构造函数的参数类型(采用Collection
的参数)来推断ArrayList的类型参数。因此它在RHS上推断出T = String,然后能够在LHS上推断出ArrayList
In other words, the compiler is going to do what it can given the information you've given it. The less information you give it, the more likely it will either fail, or not do what you want.
换句话说,编译器将根据您提供的信息执行所需的操作。您提供的信息越少,它就越有可能失败,或者不做您想做的事情。
That said, I think you've asked the wrong question. The question of how much you can leave out should not be driven by "how much will the compiler let me leave out", but "how much damage am I doing to the readability of my program." Reading code is more important than writing code. Leaving out everything you can possibly leave out is unlikely to maximize readability. You should strive to leave in enough to ensure that no reader is confused when confronted with your program.
那就是说,我认为你问的是错误的问题。你可以遗漏多少的问题不应该由“编译器让我遗漏多少”来驱动,而是“我对程序的可读性造成多大的伤害”。阅读代码比编写代码更重要。省略所有可能遗漏的东西,不太可能最大限度地提高可读性。您应该努力留下足够的空间,以确保在面对您的计划时没有读者感到困惑。
#3
13
Yes, it would compile. The var in the code
是的,它会编译。代码中的var
var list = new ArrayList<>();
shall be inferred as type ArrayList<Object>
(I believe one can precisely not determine the exact type of the element there due to erasure) which would be same as making use of a code such as:-
应该推断为类型ArrayList
ArrayList list = new ArrayList<>();
// without the type of the element of list specified
where list
is eventually ended up inferred as ArrayList<Object>
.
其中list最终被推断为ArrayList
From the FAQ on the mailing list by Brian :-
来自Brian的邮件列表中的常见问题解答: -
What happens if we ask for inference on both sides?
如果我们要求双方推断,会发生什么?
If you say:
如果你说:
var x = new ArrayList<>()
then you're asking for the compiler to infer both the type argument to
List
, and the type ofx
.那么你要求编译器推断出List的类型参数和x的类型。
But you've not provided enough type information for the compiler to do a good job.
但是你没有为编译器提供足够的类型信息来做好工作。
In most cases, you'll get an informative compiler error telling you that you're asking for your mind to be read. In some cases, we'll fall back to inferring
Object
, as we currently do with:在大多数情况下,你会得到一个信息丰富的编译器错误,告诉你,你要求你的头脑被阅读。在某些情况下,我们将回归到推断对象,正如我们目前所做的那样:
Object o = new ArrayList<>() // always inferred ArrayList<Object> here
#1
27
Yes, var
and the diamond operator can be combined together. The compiler will infer the most specific generic type:
是的,var和钻石操作符可以组合在一起。编译器将推断出最具体的泛型类型:
var list = new ArrayList<>(); // Infers ArrayList<Object>
var list = new ArrayList<>(List.of(1, 2, 3)); // Infers ArrayList<Integer>
And you can even combine them with an anonymous class:
你甚至可以将它们与匿名类结合起来:
var list = new ArrayList<>() {};
#2
20
"Work with" is a vague question, so you're likely to get vague answers.
“与...合作”是一个模糊的问题,因此您可能会得到模糊的答案。
Type inference is not mind reading; it's just constraint solving. The fewer type constraints available, the more likely you are to encounter failure or a surprising result (inferring a type that you didn't expect, such as Object
.)
类型推断不是介意阅读;这只是约束解决。可用的类型约束越少,您遇到失败的可能性就越大或结果令人惊讶(推断出您不期望的类型,例如Object。)
Diamond says: the types I need are probably already present on the left hand side, why repeat them on the right.
Diamond说:我需要的类型可能已经存在于左侧,为什么在右侧重复它们。
Local variable type inference says: the types I need are probably already present on the right hand side, why repeat them on the left.
局部变量类型推断说:我需要的类型可能已经存在于右侧,为什么在左侧重复它们。
Generic method invocation says: the types I need are probably already present in the arguments, why repeat them as witnesses.
通用方法调用说:我需要的类型可能已经出现在参数中,为什么要重复它们作为见证。
If sufficient type information is available in the program without either manifest constructor type arguments or a target type on the left, everything will be fine. For example:
如果程序中有足够的类型信息,而没有清单构造函数类型参数或左侧的目标类型,那么一切都会好的。例如:
List<String> anotherList = ...
var list = new ArrayList<>(anotherList);
Here, the compiler is able to infer the type parameter of ArrayList
by looking at the type of the argument to the constructor (the one that takes Collection<? extends E>
). So it infers T=String
on the RHS, and then is able to infer ArrayList<String>
on the LHS.
这里,编译器能够通过查看构造函数的参数类型(采用Collection
的参数)来推断ArrayList的类型参数。因此它在RHS上推断出T = String,然后能够在LHS上推断出ArrayList
In other words, the compiler is going to do what it can given the information you've given it. The less information you give it, the more likely it will either fail, or not do what you want.
换句话说,编译器将根据您提供的信息执行所需的操作。您提供的信息越少,它就越有可能失败,或者不做您想做的事情。
That said, I think you've asked the wrong question. The question of how much you can leave out should not be driven by "how much will the compiler let me leave out", but "how much damage am I doing to the readability of my program." Reading code is more important than writing code. Leaving out everything you can possibly leave out is unlikely to maximize readability. You should strive to leave in enough to ensure that no reader is confused when confronted with your program.
那就是说,我认为你问的是错误的问题。你可以遗漏多少的问题不应该由“编译器让我遗漏多少”来驱动,而是“我对程序的可读性造成多大的伤害”。阅读代码比编写代码更重要。省略所有可能遗漏的东西,不太可能最大限度地提高可读性。您应该努力留下足够的空间,以确保在面对您的计划时没有读者感到困惑。
#3
13
Yes, it would compile. The var in the code
是的,它会编译。代码中的var
var list = new ArrayList<>();
shall be inferred as type ArrayList<Object>
(I believe one can precisely not determine the exact type of the element there due to erasure) which would be same as making use of a code such as:-
应该推断为类型ArrayList
ArrayList list = new ArrayList<>();
// without the type of the element of list specified
where list
is eventually ended up inferred as ArrayList<Object>
.
其中list最终被推断为ArrayList
From the FAQ on the mailing list by Brian :-
来自Brian的邮件列表中的常见问题解答: -
What happens if we ask for inference on both sides?
如果我们要求双方推断,会发生什么?
If you say:
如果你说:
var x = new ArrayList<>()
then you're asking for the compiler to infer both the type argument to
List
, and the type ofx
.那么你要求编译器推断出List的类型参数和x的类型。
But you've not provided enough type information for the compiler to do a good job.
但是你没有为编译器提供足够的类型信息来做好工作。
In most cases, you'll get an informative compiler error telling you that you're asking for your mind to be read. In some cases, we'll fall back to inferring
Object
, as we currently do with:在大多数情况下,你会得到一个信息丰富的编译器错误,告诉你,你要求你的头脑被阅读。在某些情况下,我们将回归到推断对象,正如我们目前所做的那样:
Object o = new ArrayList<>() // always inferred ArrayList<Object> here