After reading this question , I started thinking about common methods in Java 8 . In particular, what happens to generic type parameters when methods are bound.
In this question I will use some common methods from Guava ImmutableMap , but my question is more general and can be applied to all related common methods.
Consider ImmutableMap.of generic method that has this signature:
public static <K, V> ImmutableMap<K, V> of(K k1, V v1)
If we use this generic method to declare a Map , the compiler correctly describes the generic types:
Map<String, String> map = ImmutableMap.of("a", "b");
I know that with Java 8, the mechanism of the compiler output mechanisms has been improved, i.e. it displays the general types of methods from the context, which in this case is the destination.
Context can also be a method call:
void someMethod(Map<String, String> map) {
In this case, the generic types ImmutableMap.of are inferred from the generic types of the someMethod argument, i.e. Map<String, String> map .
But when I try to use ImmutableMap.builder() and chain methods to build my map, I get a compilation error:
Map<String, String> map = ImmutableMap.builder() .put("a", "b") .build();
Mistake:
Error:(...) java: incompatible types: ImmutableMap<Object, Object> cannot be converted to Map<String, String>
(I just deleted the package names from the error message).
I understand the error and why this is happening. The first method in the chain is ImmutableMap.builder() , and the compiler has no context for outputting type parameters, so it discards <Object, Object> . Then, the ImmutableMap.Builder.put method ImmutableMap.Builder.put called with the arguments "a" and "b" and finally, the ImmutableMap.Builder.build() method is ImmutableMap.Builder.build() , which returns ImmutableMap<Object, Object> . This is why I get an incompatible type error: when I try to assign this instance of ImmutableMap<Object, Object> my variable Map<String, String> map , the compiler complains.
I even know how to solve this error: I could either split the method chain into two lines so that the compiler can now output type-type parameters:
ImmutableMap.Builder<String, String> builder = ImmutableMap.builder(); Map<String, String> map = builder.put("a", "b").build();
Or I can explicitly specify type parameters:
Map<String, String> map = ImmutableMap.<String, String>builder() .put("a", "b") .build();
So my question is not how to solve / work around this, but why do I need to explicitly provide type parameters when binding common methods. Or, in other words, why the compiler cannot output type parameters to the method chain, especially when the method chain is on the right side of the task? If it were possible, would it break something else (I mean, related to a system like generics)?
EDIT
Here is a question with a question about the same , however, the only answer it has does not give a clear explanation why the compiler does not output type parameters in the method chain. All it has is a link to a small paragraph in JSR-000335 Lambda Expressions for JavaTM programming for the final version for evaluation (spec part D):
There was some interest in allowing the output of "chain": in a (). b (), passing type information from call b to call a. This adds another dimension to the complexity of the inference algorithm, since partial information must go both ways; it only works when erasing the return type a () is fixed for all instances (e.g. List). This feature does not fit well with the poly expression model, since the type of target cannot be easily obtained; but perhaps with additional improvements that may be added in the future.
So, I can rephrase my original question as follows:
- What will be these additional improvements?
- How is it that transferring partial information in both directions will make the output algorithm more complicated?
- Why will this only work when the erase of the return type () is fixed for all instances (e.g. List)? In fact, what does this mean that erasing the return type of a method is fixed for all instances?
- Why doesn't this function fit very well into the expression model? In fact, what is a poly-expression model? And why in this case it is impossible to easily obtain the target type?