Looking at the type inference for generic types in the following example, I cannot say why methodAutoTypeInference
works fine, but methodNotCompilable
(which is almost the same) fails to compile and to manage it the compiler requires additional tricks like methodWorkaroundTypeHint
or methodWorkaroundTypeCast
.
What is the problem with methodNotCompilable
causing the compiler to be unsure that the expression type and the method result type are compatible?
Stream<CharSequence> methodAutoTypeInference() {
return Stream.of("a");
}
Stream<CharSequence> methodNotCompilable() {
return Stream.of("a").distinct();
// incompatible types: java.util.stream.Stream<java.lang.String>
// cannot be converted to java.util.stream.Stream<java.lang.CharSequence>
}
Stream<CharSequence> methodWorkaroundTypeHint() {
return Stream.<CharSequence>of("a").distinct();
}
Stream<CharSequence> methodWorkaroundTypeCast() {
return Stream.of((CharSequence) "a").distinct();
}
This answer from JDK Developers themselves sort of covers the same area. Just notice that Stuart Marks says : "It might be possible for the compiler to be enhanced to cover this case in a future release". Though the case there is around lambdas
, this is not very different than you have. It's just the way compiler (at the moment) works. And we are "stuck" with this.
You can sort of look under the resolution of how a compiler thinks about return Stream.of("a").distinct();
and decides what type to use, via:
javac --debug=verboseResolution=all
which in an un-documented flag. If you compile with that flag, you will see some big output:
with actuals: no arguments
with type-args: no arguments
candidates:
#0 applicable method found: Object()
DeleteMe.java:60: Note: resolving method of in type Stream to candidate 1
return Stream.of("a").distinct();
^
phase: BASIC
with actuals: String
with type-args: no arguments
candidates:
#0 not applicable method found: <T#1>of(T#1...)
(cannot infer type-variable(s) T#1
(argument mismatch; String cannot be converted to T#1[]))
#1 applicable method found: <T#2>of(T#2)
(partially instantiated to: (String)Stream<String>)
where T#1,T#2 are type-variables:
T#1 extends Object declared in method <T#1>of(T#1...)
T#2 extends Object declared in method <T#2>of(T#2)
DeleteMe.java:60: Note: Deferred instantiation of method <T>of(T)
return Stream.of("a").distinct();
^
instantiated signature: (String)Stream<String>
target-type: <none>
where T is a type-variable:
T extends Object declared in method <T>of(T)
DeleteMe.java:60: Note: resolving method distinct in type Stream to candidate 0
return Stream.of("a").distinct();
^
phase: BASIC
with actuals: no arguments
with type-args: no arguments
candidates:
#0 applicable method found: distinct()
where T is a type-variable:
T extends Object declared in interface Stream
DeleteMe.java:60: error: incompatible types: Stream<String> cannot be converted to Stream<CharSequence>
return Stream.of("a").distinct();
^
1 error
I guess the most important part is this : (partially instantiated to: (String)Stream<String>)
You can see that the resolution of what type T
is, is done a method call basis; not of the whole chain of calls. If it would would, btw, this would complicate compilers works quite a lot. For a simple chain like this, things might look trivial, but it gets far, far more tricky and involved when there are many. Especially, when you find out about non-denotable types
, which will even further complicate this.
It's a compiler's feature. When you write Stream.of("a");
without return statement and generic type for method of() compiler gets the type from methods parameter "a" (Stream<String>
).
When you write return Stream.of("a");
compiler gets the type from the return type (Stream<CharSequence>
) because you don't set generic type.
And when you write return Stream.of("a").distinct();
compiler get type from method's parameter (Stream<String>
too), for calling .distinct()
or .sorted()
In other words, you don't set generic type for a method of(), and the compiler got it from the method's return type when you don't have another stream's method, and got type from variable's type if you have other stream's methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With