Java 7 中菱形运算符 (<>) 的意义是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4166966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the point of the diamond operator (<>) in Java 7?
提问by tofarr
The diamond operator in java 7 allows code like the following:
java 7 中的菱形运算符允许如下代码:
List<String> list = new LinkedList<>();
However in Java 5/6, I can simply write:
但是在 Java 5/6 中,我可以简单地写:
List<String> list = new LinkedList();
My understanding of type erasure is that these are exactly the same. (The generic gets removed at runtime anyway).
我对类型擦除的理解是,这些是完全一样的。(无论如何,泛型在运行时会被删除)。
Why bother with the diamond at all? What new functionality / type safety does it allow? If it doesn't yield any new functionality why do they mention it as a feature? Is my understanding of this concept flawed?
为什么要为钻石烦恼呢?它允许哪些新功能/类型安全?如果它没有产生任何新功能,为什么他们将其称为功能?我对这个概念的理解有缺陷吗?
采纳答案by ColinD
The issue with
问题与
List<String> list = new LinkedList();
is that on the left hand side, you are using the generictype List<String>
where on the right side you are using the rawtype LinkedList
. Raw types in Java effectively only exist for compatibility with pre-generics code and should never be used in new code unless
you absolutely have to.
是在左侧,您使用的是泛型类型List<String>
,而在右侧,您使用的是原始类型LinkedList
。Java 中的原始类型实际上只是为了与前泛型代码兼容而存在,除非绝对必须,否则不应在新代码中使用。
Now, if Java had generics from the beginning and didn't have types, such as LinkedList
, that were originally created before it had generics, it probably could have made it so that the constructor for a generic type automatically infers its type parameters from the left-hand side of the assignment if possible. But it didn't, and it must treat raw types and generic types differently for backwards compatibility. That leaves them needing to make a slightly different, but equally convenient, way of declaring a new instance of a generic object without having to repeat its type parameters... the diamond operator.
现在,如果 Java 从一开始就有泛型并且没有类型,例如LinkedList
,在它拥有泛型之前最初创建的类型,它可能可以这样做,以便泛型类型的构造函数自动从左侧推断其类型参数- 如果可能的话,作业的一面。但它没有,为了向后兼容,它必须区别对待原始类型和泛型类型。这让他们需要创建一种稍微不同但同样方便的方法来声明泛型对象的新实例,而不必重复其类型参数……菱形运算符。
As far as your original example of List<String> list = new LinkedList()
, the compiler generates a warning for that assignment because it must. Consider this:
就您的原始示例而言List<String> list = new LinkedList()
,编译器会为该赋值生成警告,因为它必须这样做。考虑一下:
List<String> strings = ... // some list that contains some strings
// Totally legal since you used the raw type and lost all type checking!
List<Integer> integers = new LinkedList(strings);
Generics exist to provide compile-time protection against doing the wrong thing. In the above example, using the raw type means you don't get this protection and will get an error at runtime. This is why you should not use raw types.
泛型的存在是为了提供编译时保护,防止做错事。在上面的例子中,使用原始类型意味着你没有得到这种保护,并且会在运行时得到一个错误。这就是为什么你不应该使用原始类型。
// Not legal since the right side is actually generic!
List<Integer> integers = new LinkedList<>(strings);
The diamond operator, however, allows the right hand side of the assignment to be defined as a true generic instance with the same type parameters as the left side... without having to type those parameters again. It allows you to keep the safety of generics with almostthe same effort as using the raw type.
然而,菱形运算符允许将赋值的右侧定义为具有与左侧相同的类型参数的真正泛型实例……而无需再次键入这些参数。它允许您以与使用原始类型几乎相同的努力来保持泛型的安全性。
I think the key thing to understand is that raw types (with no <>
) cannot be treated the same as generic types. When you declare a raw type, you get none of the benefits and type checking of generics. You also have to keep in mind that generics are a general purpose part of the Java language... they don't just apply to the no-arg constructors of Collection
s!
我认为要理解的关键是原始类型(没有<>
)不能与泛型类型相同。当您声明原始类型时,您将无法获得泛型的任何好处和类型检查。您还必须记住,泛型是 Java 语言的通用部分……它们不仅仅适用于Collection
s的无参数构造函数!
回答by Roman
This line causes the [unchecked] warning:
此行导致 [unchecked] 警告:
List<String> list = new LinkedList();
So, the question transforms: why [unchecked] warning is not suppressed automatically only for the case when new collection is created?
所以,问题转变了:为什么 [unchecked] 警告不会仅在创建新集合的情况下自动抑制?
I think, it would be much more difficult task then adding <>
feature.
我认为,这比添加<>
功能要困难得多。
UPD: I also think that there would be a mess if it were legally to use raw types 'just for a few things'.
UPD:我还认为,如果合法地使用原始类型“只是为了一些事情”,那将会是一团糟。
回答by Octavian A. Damiean
Your understanding is slightly flawed. The diamond operator is a nice feature as you don't have to repeat yourself. It makes sense to define the type once when you declare the type but just doesn't make sense to define it again on the right side. The DRY principle.
你的理解有点问题。菱形运算符是一个不错的功能,因为您不必重复自己。在声明类型时定义一次类型是有意义的,但在右侧再次定义它是没有意义的。DRY 原则。
Now to explain all the fuzz about defining types. You are right that the type is removed at runtime but once you want to retrieve something out of a List with type definition you get it back as the type you've defined when declaring the list otherwise it would lose all specific features and have only the Object features except when you'd cast the retrieved object to it's original type which can sometimes be very tricky and result in a ClassCastException.
现在解释有关定义类型的所有模糊。您在运行时删除该类型是正确的,但是一旦您想从带有类型定义的 List 中检索某些内容,您就会将其作为您在声明列表时定义的类型取回,否则它将丢失所有特定功能并且只有对象功能,除非您将检索到的对象强制转换为其原始类型,这有时会非常棘手并导致 ClassCastException。
Using List<String> list = new LinkedList()
will get you rawtype warnings.
使用List<String> list = new LinkedList()
将为您提供原始类型警告。
回答by axtavt
When you write List<String> list = new LinkedList();
, compiler produces an "unchecked" warning. You may ignore it, but if you used to ignore these warnings you may also miss a warning that notifies you about a real type safety problem.
编写时List<String> list = new LinkedList();
,编译器会产生“未检查”警告。你可以忽略它,但如果你过去忽略这些警告,你也可能会错过一个警告,通知你一个真正的类型安全问题。
So, it's better to write a code that doesn't generate extra warnings, and diamond operator allows you to do it in convenient way without unnecessary repetition.
因此,最好编写不会产生额外警告的代码,而菱形运算符允许您以方便的方式进行操作,而无需进行不必要的重复。
回答by Buhake Sindi
The point for diamond operator is simply to reduce typing of code when declaring generic types. It doesn't have any effect on runtime whatsoever.
菱形运算符的重点只是在声明泛型类型时减少代码类型。它对运行时没有任何影响。
The only difference if you specify in Java 5 and 6,
如果您在 Java 5 和 6 中指定,唯一的区别是
List<String> list = new ArrayList();
is that you have to specify @SuppressWarnings("unchecked")
to the list
(otherwise you will get an unchecked cast warning). My understanding is that diamond operator is trying to make development easier. It's got nothing to do on runtime execution of generics at all.
是,你必须指定@SuppressWarnings("unchecked")
的list
(否则你将得到一个unchecked投警告)。我的理解是钻石运营商正在努力使开发更容易。它与泛型的运行时执行完全无关。
回答by maaartinus
In theory, the diamond operator allows you to write more compact (and readable) code by saving repeated type arguments. In practice, it's just two confusing chars more giving you nothing. Why?
理论上,菱形运算符允许您通过保存重复的类型参数来编写更紧凑(和可读)的代码。在实践中,这只是两个令人困惑的字符,更多的是什么都不给你。为什么?
- No sane programmer uses raw types in new code. So the compiler could simply assume that by writing no type arguments you want it to infer them.
- The diamond operator provides no type information, it just says the compiler, "it'll be fine". So by omitting it you can do no harm. At any place where the diamond operator is legal it could be "inferred" by the compiler.
- 没有理智的程序员会在新代码中使用原始类型。因此,编译器可以简单地假设,通过不编写类型参数,您希望它推断它们。
- 菱形运算符不提供类型信息,它只是告诉编译器,“会没事的”。因此,省略它不会造成任何伤害。在菱形运算符合法的任何地方,编译器都可以“推断”它。
IMHO, having a clear and simple way to mark a source as Java 7 would be more useful than inventing such strange things. In so marked code raw types could be forbidden without losing anything.
恕我直言,有一种清晰而简单的方法将源标记为 Java 7 比发明这些奇怪的东西更有用。在如此标记的代码中,可以在不丢失任何内容的情况下禁止原始类型。
Btw., I don't think that it should be done using a compile switch. The Java version of a program file is an attribute of the file, no option at all. Using something as trivial as
顺便说一句,我认为不应该使用编译开关来完成。程序文件的 Java 版本是文件的一个属性,根本没有选项。使用一些微不足道的东西
package 7 com.example;
could make it clear (you may prefer something more sophisticated including one or more fancy keywords). It would even allow to compile sources written for different Java versions together without any problems. It would allow introducing new keywords (e.g., "module") or dropping some obsolete features (multiple non-public non-nested classes in a single file or whatsoever) without losing any compatibility.
可以说清楚(您可能更喜欢更复杂的东西,包括一个或多个花哨的关键字)。它甚至可以将针对不同 Java 版本编写的源代码编译在一起而不会出现任何问题。它将允许引入新的关键字(例如,“模块”)或删除一些过时的功能(单个文件中的多个非公共非嵌套类或其他任何内容)而不会失去任何兼容性。
回答by allprog
All said in the other responses are valid but the use cases are not completely valid IMHO. If one checks out Guavaand especially the collections related stuff, the same has been done with static methods. E.g. Lists.newArrayList()which allows you to write
其他回复中的所有内容都是有效的,但恕我直言,用例并不完全有效。如果检查Guava尤其是与集合相关的东西,静态方法也是如此。例如Lists.newArrayList()允许你写
List<String> names = Lists.newArrayList();
or with static import
或静态导入
import static com.google.common.collect.Lists.*;
...
List<String> names = newArrayList();
List<String> names = newArrayList("one", "two", "three");
Guava has other very powerful features like this and I actually can't think of much uses for the <>.
Guava 有其他非常强大的功能,比如这样,我实际上想不出 <> 有多大用处。
It would have been more useful if they went for making the diamond operator behavior the default, that is, the type is inferenced from the left side of the expression or if the type of the left side was inferenced from the right side. The latter is what happens in Scala.
如果他们将菱形运算符行为设为默认值,即从表达式的左侧推断类型,或者从右侧推断左侧的类型,那将会更有用。后者是 Scala 中发生的事情。