45

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?

14
  • 3
    backwards compatibility rules in a language as old and popular as java Jan 18, 2013 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, 2013 at 0:15
  • 1
    It may have some unintended effects when used with Type Erasure. docs.oracle.com/javase/tutorial/java/generics/… Jan 19, 2013 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. Jan 19, 2013 at 11:12
  • 4
    Local variable type inference is coming to Java: JEP 286: Local-Variable Type Inference
    – Jimmy Page
    Mar 14, 2016 at 20:00

5 Answers 5

61

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.

12
  • 7
    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. Mar 19, 2014 at 15:10
  • 9
    Yes and that's good for generics, but I still miss the equivalent of C#'s var in Java. Mar 19, 2014 at 15:25
  • 16
    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 Mar 19, 2014 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, 2014 at 15:27
  • 9
    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, 2015 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.

5
  • 9
    How does GridBagLayout gridbag = new GridBagLayout(); add to self documentation? Its pure repetition. Dec 9, 2013 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, 2013 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? Mar 19, 2014 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, 2014 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, 2016 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.

1
  • It only matters in the field outside that class.
    – Xwtek
    Sep 25, 2020 at 9:12

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