ChatGPT解决这个技术问题 Extra ChatGPT

What is the point of the diamond operator (<>) in Java?

The diamond operator in java 7 allows code like the following:

List<String> list = new LinkedList<>();

However in Java 5/6, I can simply write:

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?

Note that this is not an issue if you use static factory methods, since Java does type inference on method calls.
when you disable warning it's actually useless... :) like for me
It's been answered but it is also in the Java tutorial (around the middle of the page): docs.oracle.com/javase/tutorial/java/generics/…
Nice article about this on dZone.
My view of it is that it is syntactic sugar for List list = new LinkedList(); i.e. keeping it generic

C
ColinD

The issue with

List<String> list = new LinkedList();

is that on the left hand side, you are using the generic type List<String> where on the right side you are using the raw type 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.

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.

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> 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 almost the 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 Collections!


Backward compatibility is great, but not at the expense of complexity please. Why couldn't Java 7 just introduce -compatibility compiler switch whereas if absent then javac will forbid all raw types and enforce strictly generic types only? This will make our codes less verbose as it is.
@Rosdi: Agreed, there's no need for raw types in new code. However, I'd strongly prefer including the Java version number in the source file (instead of (mis)using the command line), see my answer.
I personally don't like the use of diamonds UNLESS you are defining AND instantiating on the same line. List<String> strings = new List<>() is OK, but if you define private List<String> my list;, and then halfway down the page you instantiate with my_list = new List<>(), then it's not cool! What does my list contain again? Oh, let me hunt around for the definition. Suddenly, the benefit of the diamond shortcut goes bye bye.
@rmirabelle How is that different from: my_list = getTheList()? There are several better ways how to deal with this kind of problems: 1. use an IDE that shows you types of variables upon mouse hover. 2. use more meaningful variable names, such as private List<String> strings 3. don't split declaration and initialization of variables unless you really have to.
@Morfidon: Yes, it's still valid for Java 8. I'm pretty sure you should be getting warnings.
O
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.

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.

Using List<String> list = new LinkedList() will get you rawtype warnings.


List<String> list = new LinkedList() is the correct code. You know this and I know this too. And the question (as I understand it) is: why only java compiler doesn't understand that this code is quite secure?
@Roman: List<String> list = new LinkedList() is not the correct code. Sure, it would be nice if it were! And it probably could have been if Java had generics from the beginning and didn't have to deal with backwards compatibility of generic types that used to be non-generic, but it does.
@ColinD Java really needn't to deal with backwards compatibility in each single line. In any Java source file using generics the old non-generic types should be forbidden (you can always use <?> if interfacing to legacy code) and the useless diamond operator should not exist.
R
Roman

This line causes the [unchecked] warning:

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?

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'.


m
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.

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

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.


Have you considered the difference between new ArrayList(anotherList) and new ArrayList<>(anotherList) (especially if it is being assigned to List<String> and anotherList is a List<Integer>)?
@Paul Bellora: No. Surprisingly for me, both compile. The one with diamonds even given no warning. However, I can't see any sense in this, can you elaborate?
Sorry, I didn't explain very well. See the difference between these two examples: ideone.com/uyHagh and ideone.com/ANkg3T I'm just pointing out that it does matter to use the diamond operator instead of a raw type, at least when arguments with generic bounds are being passed in.
Actually I hadn't taken the time to read ColinD's answer - he cites pretty much the same thing.
So, if we are about to introduce a new syntax for raw types, for the few places where it is really needed, why not use something like new @RawType List(). That’s already valid Java 8 syntax and type annotations allow to use it at every place where needed, e.g. @RawType List = (@RawType List) genericMethod();. Considering that raw types currently create a compiler warning unless an appropriate @SuppressWarnings has been placed, @RawType would be a reasonable replacement and a more subtle syntax isn’t needed.
a
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.

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.


a
allprog

All said in the other responses are valid but the use cases are not completely valid IMHO. If one checks out Guava and especially the collections related stuff, the same has been done with static methods. E.g. Lists.newArrayList() which allows you to write

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

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.


B
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,

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.


you don't even have to use that annotation. At least in Eclipse, you can just tell the compiler to not warn you about this and you are fine...
It's better to have the annotation. Not every developers uses Eclipse out here.