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?
-
3backwards compatibility rules in a language as old and popular as java– ratchet freakJan 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.– user76704Jan 19, 2013 at 0:15
-
1It may have some unintended effects when used with Type Erasure. docs.oracle.com/javase/tutorial/java/generics/…– Zachary YatesJan 19, 2013 at 1:09
-
4Note 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 SauerJan 19, 2013 at 11:12
-
4Local variable type inference is coming to Java: JEP 286: Local-Variable Type Inference– Jimmy PageMar 14, 2016 at 20:00
5 Answers
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.
-
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'sHashMap<String, Integer> map = foo.getMap()
then I agree - in C# I typically don't usevar
in such cases, even though I could. But this argument does not hold water if it'sHashMap<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 -
9Yes and that's good for generics, but I still miss the equivalent of C#'s
var
in Java. Mar 19, 2014 at 15:25 -
16As 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
-
6Further, 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.– PhoshiMar 19, 2014 at 15:27
-
9I 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. Feb 8, 2015 at 19:28
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
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.
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.
-
9How does GridBagLayout gridbag = new GridBagLayout(); add to self documentation? Its pure repetition. Dec 9, 2013 at 22:54
-
3It disambiguates from a case where the two types are not the same. You could just as easily assign an instance of a subclass.– jiggyDec 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.– PhoshiMar 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– saraApr 5, 2016 at 12:45
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.