Why diamond operator is used for Type Inference in

2019-01-14 17:35发布

List<String> list = new ArrayList(); will result in compiler warning.

However the following example compiles without any warning: List<String> list = new ArrayList<>();

I'm curious why introducing of diamond operator is needed at all. Why not just have type inference on constructor if type argument is absent (as its already done for static methods in java and exploited by collection libraries like google guava)

EDIT: Using millimoose answer as starting point I looked what type erasure actually is and it's not just removing all type information. Compiler actually does a bit more(copied from official doc):

  • Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
  • Insert type casts if necessary to preserve type safety.
  • Generate bridge methods to preserve polymorphism in extended generic types.

6条回答
Anthone
2楼-- · 2019-01-14 17:40

The definitive answer would have to come from someone who designed that feature, but I'm assuming it's to distinguish this from using raw types, which make the compiler do something different altogether for the sake of compatibility. An expression with a raw type in it is processed subtly differently than one that involves generics, an example is found in this SO question: Generic screws up non-related collection

查看更多
The star\"
3楼-- · 2019-01-14 17:48

The interesting cases are where calling the constructor with the diamond and as a rawtype successfully compiles but produces different code. Such examples are possible when mixed with the method overloading feature. IIRC, there's was an example somewhere on the OpenJDK coin mailing list (no, I'm not going to try to find it).

It was not acceptable to have exactly the same code successfully come on Java SE 6 and Java SE 7 but produce different results.

For my money, I would have omitted the diamond and given a warning (treat as an error) if different code would have been produced by the inference algorithm chosen in 7 (essentially the same as for method generic-type inference from J2SE 5.0). If you've written such code, it's probably non-obvious to work out if it's compileable or not anyway.

查看更多
小情绪 Triste *
4楼-- · 2019-01-14 17:49

If your project is built on maven, add the below in pom.xml under tag. It works perfectly.. <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins>

查看更多
劫难
5楼-- · 2019-01-14 17:55

The full syntax required by compiler of java 5 and 6 is:

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

They decided to simplify the syntax for us and allow not to write the same type parameters at both sides of assignment operator. However the <> operator is still required to make sure you understand what you are doing. By writing new ArrayList<>() you say "I understand I am creating instance of generic type and the generic parameter is as one I declared at the left side of the assignment."

查看更多
太酷不给撩
6楼-- · 2019-01-14 17:59

This is part of an improvement to Java Generics in Java 7.
Before you would have had to write

final List<String> list = new ArrayList<String>();

Now you can write

final List<String> list = new ArrayList<>();

Which is equivalent - the compiler will work it out for you. This is not the same as

final List list = new ArrayList();

Which is an untyped List.

查看更多
欢心
7楼-- · 2019-01-14 18:01

The Java developers try very hard to avoid changing the behavior of existing programs. List<String> list = new ArrayList(); does compile, and creates a raw ArrayList. If type inference were applied to it the result would be an ArrayList<String>, changing its behavior and possibly causing run time errors elsewhere in the program.

============================================================================

After further consideration, and a comment by @millimoose, I see that the changes in behavior would be local to the initializer, and detected at compile time. Consider the following program:

import java.util.ArrayList;
import java.util.List;


public class Test {
  public static void main(String[] args) throws Exception {
    List<Integer> integers = new ArrayList<Integer>();
    integers.add(Integer.valueOf(3));
    integers.add(Integer.valueOf(4));
    List<String> list = new ArrayList(integers);
    System.out.println(list);
  }
}

Without type inference, it runs and prints [3, 4], despite the undesirable situation of a List<String> that contains Integer references.

With type inference, it would not compile because the ArrayList(Collection<? extends E> c) does not allow use of a List<Integer> as argument when creating an ArrayList<String>.

查看更多
登录 后发表回答