When I compile the following code:
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Stream;
public class Testcase
{
public static <T, K, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableMap1(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper)
{
return null;
}
public static <T, K, V> MapCollectorBuilder<T, K, V, ? extends Map<K, V>, ImmutableMap<K, V>>
toImmutableMap2(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper)
{
return null;
}
public final class MapCollectorBuilder<T, K, V, A extends Map<K, V>, R extends Map<K, V>>
{
/**
* @return a new collector
*/
public Collector<T, A, R> build()
{
return null;
}
}
public void main(String[] args)
{
Function<String, String> keyMapper = i -> i;
Function<String, Integer> valueMapper = Integer::valueOf;
ImmutableMap<String, Integer> map1 = Stream.of("1", "2", "3")
.collect(Testcase.toImmutableMap1(keyMapper, valueMapper));
MapCollectorBuilder<String, String, Integer, Map<String, Integer>, ImmutableMap<String, Integer>> builder
= Testcase.
<String, String, Integer, Map<String, Integer>, ImmutableMap<String, Integer>>toImmutableMap2(
keyMapper, valueMapper);
ImmutableMap<String, Integer> map2 = Stream.of("1", "2", "3").collect(builder.build());
}
}
I get the following error:
Testcase.java:[45,35] method toImmutableMap2 in class Testcase cannot be applied to given types;
required: java.util.function.Function<? super T,? extends K>,java.util.function.Function<? super T,? extends V>
found: java.util.function.Function<java.lang.String,java.lang.String>,java.util.function.Function<java.lang.String,java.lang.Integer>
reason: actual and formal argument lists differ in length
but as far as I can tell, the argument list is correct.
toImmutableMap1()
compile while toImmutableMap2()
does not?toImmutableMap2()
compile properly?UPDATE: If I replace the 5 type parameters with <String, String, Integer>
I get this new compiler error:
incompatible types: Testcase.MapCollectorBuilder<String,String,Integer,CAP#1,ImmutableMap<String,Integer>> cannot be converted to Testcase.MapCollectorBuilder<String,String,Integer,Map<String,Integer>,ImmutableMap<String,Integer>>
where CAP#1 is a fresh type-variable:
CAP#1 extends Map<String,Integer> from capture of ? extends Map<String,Integer>
Currently you're trying to specify 5 type arguments here:
Testcase.
<String, String, Integer, Map<String, Integer>, ImmutableMap<String, Integer>>toImmutableMap2(
... but the method only has 3 type parameters:
public static <T, K, V> ComplexReturnTypeHere<...> toImmutableMap2
You can fix that by changing the call to:
Testcase.<String, String, Integer>toImmutableMap2(...)
But that changes the error message to:
Testcase.java:44: error: incompatible types:
Testcase.MapCollectorBuilder<String,String,Integer,CAP#1,ImmutableMap<String,Integer>>
cannot be converted to
Testcase.MapCollectorBuilder<String,String,Integer,Map<String,Integer>,
ImmutableMap<String,Integer>>
That can in turn be fixed by changing the return type of the method declaration:
public static <T, K, V>
MapCollectorBuilder<T, K, V, Map<K, V>, ImmutableMap<K, V>>
toImmutableMap2(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper)
The difference here is the second type argument in MapCollectorBuilder
- Map<K, V>
instead of ? extends Map<K, V>
.
Alternatively, you could change the declaration of builder
to:
MapCollectorBuilder<String, String, Integer, ? extends Map<String, Integer>, ImmutableMap<String, Integer>> builder
(Mind you, personally at this point it feels like it's falling into the realm of "incredibly hard to read and understand" code...)
See more on this question at Stackoverflow