44

I have always wondered why Java does not do type inference given that the language is what it is, and its VM is very mature. Google's Go is an example of a language with excellent type inference and it reduces the amount of typing one has to do. Is there any special reason behind this feature not being a part of Java?

  • 3
    backwards compatibility rules in a language as old and popular as java – ratchet freak Jan 18 '13 at 23:43
  • 9
    @ratchetfreak Could type inference not be added in a backwards-compatible way? Older programs would just be providing more type information than necessary. – user76704 Jan 19 '13 at 0:15
  • 1
    It may have some unintended effects when used with Type Erasure. docs.oracle.com/javase/tutorial/java/generics/… – Zachary Yates Jan 19 '13 at 1:09
  • 4
    Note that Java 8 will bring a lot of type inference with its Lambda feature: you can write complex lambdas without mentioning any types and everything being inferred. – Joachim Sauer Jan 19 '13 at 11:12
  • 4
    Local variable type inference is coming to Java: JEP 286: Local-Variable Type Inference – Jimmy Page Mar 14 '16 at 20:00
60

Technically speaking, Java does have type inferencing when using generics. With a generic method like

public <T> T foo(T t) {
  return t;
}

The compiler will analyze and understand that when you write

// String
foo("bar");
// Integer
foo(new Integer(42));

A String is going to be returned for the first call and an Integer for the second call based on what was input as an argument. You will get the proper compile-time checking as a result. Additionally, in Java 7, one can get some additional type inferencing when instantiating generics like so

Map<String, String> foo = new HashMap<>();

Java is kind enough to fill in the blank angle brackets for us. Now why doesn't Java support type inferencing as a part of variable assignment? At one point, there was an RFE for type inferencing in variable declarations, but this was closed as "Will not fix" because

Humans benefit from the redundancy of the type declaration in two ways. First, the redundant type serves as valuable documentation - readers do not have to search for the declaration of getMap() to find out what type it returns. Second, the redundancy allows the programmer to declare the intended type, and thereby benefit from a cross check performed by the compiler.

The contributor who closed this also noted that it just feels "un-java-like", which I am one to agree with. Java's verbosity can be both a blessing and a curse, but it does make the language what it is.

Of course that particular RFE was not the end of that conversation. During Java 7, this feature was again considered, with some test implementations being created, including one by James Gosling himself. Again, this feature was ultimately shot down.

With the release of Java 8, we now get type inference as a part of lambdas as such:

List<String> names = Arrays.asList("Tom", "Dick", "Harry");
Collections.sort(names, (first, second) -> first.compareTo(second));

The Java compiler is able to look at the method Collections#sort(List<T>, Comparator<? super T>) and then the interface of Comparator#compare(T o1, T o2) and determine that first and second should be a String thus allowing the programmer to forgo having to restate the type in the lambda expression.

  • 5
    First, the redundant type serves as valuable documentation - readers do not have to search for the declaration of getMap() to find out what type it returns - yes, if it's HashMap<String, Integer> map = foo.getMap() then I agree - in C# I typically don't use var in such cases, even though I could. But this argument does not hold water if it's HashMap<String, Integer> map = new HashMap<String, Integer>(). This is true redundancy and I see no benefit in having to write the type name twice. And how I would benefit here from a compiler cross check, I don't understand at all. – Konrad Morawski Mar 19 '14 at 15:10
  • 9
    Yes and that's good for generics, but I still miss the equivalent of C#'s var in Java. – Konrad Morawski Mar 19 '14 at 15:25
  • 15
    As for it being "un-java-like", this (cheesy) story comes to mind ;) 9gag.com/gag/2308699/-this-is-how-things-are-done-around-here – Konrad Morawski Mar 19 '14 at 15:27
  • 6
    Further, the return type of a function is often either obvious or unnecessary, and even in cases where it is not your IDE can flag up the type in half a second. – Phoshi Mar 19 '14 at 15:27
  • 8
    I believe the official quote Humans benefit from the redundancy is the real answer to the current question, because every justification I've read seems a gratuitous, unfounded and ridiculous excuse from Java designers: Both C# and C++ have the feature, C# and C++ designers are no less competent than Java's, and everyone is happy using it. What is it that would causes Java developers to be different from C# or C++ developers? This is why I agree with @KonradMorawski, "This is how things are done here" seems again to be the real behind-the-scenes reason for that. – paercebal Feb 8 '15 at 19:28
16

Well, first off, type inference has nothing to do with the maturity of the runtime, whether that runtime is a 30 year old CPU or a VM that is so new the bits are still shiny. it's all about the compiler.

That said, it is allowed for generics, the reason why it's not allowed for non-generic types seems to be because of philosophy -- there's nothing preventing the designers from adding it.

Update: looks like java 10 supports it —- http://openjdk.java.net/jeps/286

5

As far as I know, when Java was designed at the beginning of the nineties type inference was not that popular among mainstream languages (but it was already a very well known concept, e.g. in ML). So, I can imagine that type inference was probably not supported because Java was aimed at programmers coming from C++, Pascal, or other mainstream languages that did not have it (principle of least surprise).

Also, one of the design principles of Java is to write things explicitly to make sure that the programmer and the compiler have the same understanding of the code: duplicating information reduces the chances of errors. Of course, it may be a matter of taste whether typing a few more characters is worth the extra safety it provides, but this was the design philosophy followed for Java: write things explicitly.

I do not know if Java will get type inference in the future but IMO that would be a big revolution for the language (as Glenn Nelson mentioned, it was described as "un-java-like") and then one might also consider dropping the name Java in favour of a new name.

If you want to use a JVM language with type inference you can use Scala.

2

I can think of a few possible reasons. One is that explicit typing is self-documenting. Java generally makes this a priority over concision. Another reason might be in cases where the type is somewhat ambiguous. Like when a type or any subtype might satisfy a routine. Let's say you want to use a List, but someone comes along and uses a method exclusive to ArrayList. The JIT would infer an ArrayList and carry on even if you wanted a compilation error.

  • 8
    How does GridBagLayout gridbag = new GridBagLayout(); add to self documentation? Its pure repetition. – Anders Lindén Dec 9 '13 at 22:54
  • 3
    It disambiguates from a case where the two types are not the same. You could just as easily assign an instance of a subclass. – jiggy Dec 10 '13 at 23:25
  • Let's say you want to use a List, but someone comes along and uses a method exclusive to ArrayList. The JIT would infer an ArrayList and carry on even if you wanted a compilation error - I don't understand this bit. Type inference takes place at the moment of instatiating a variable, not calling a method on it. Could you perhaps show an example of what you meant? – Konrad Morawski Mar 19 '14 at 15:13
  • 2
    @KonradMorawski: I assume he means that if a method returns ArrayList, the type will be inferred to that. If you want to treat a type as something other than the return type, you can't use inference. I don't understand how this could ever be a problem in a codebase anywhere near sane, though. – Phoshi Mar 19 '14 at 15:30
  • the JIT would play no part whatsoever in type inference. type inference is a compile-time phenomenon. and if a variable is declared as a reference to a List, trying to access ArrayList members on it won't type check and you get a compilation error – sara Apr 5 '16 at 12:45
0

It contradicts the well-established recommendation to declare variables using the most generic interface that will fit your needs, and initialize them with an appropriate implementing class, like in

Collection<String> names = new ArrayList<>();

Effectively,

var names = new ArrayList<String>();

is nothing but syntactic sugar for

ArrayList<String> names = new ArrayList<String>();

If you want that, your IDE can produce it from the new ArrayList<String>() expression with "one click" (refactor / create local variable), but remember that it contradicts the "use interfaces" recommendation.

protected by gnat Feb 22 '18 at 5:50

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.