Generic static method constrains types too much

后端 未结 3 1673
北海茫月
北海茫月 2021-01-25 05:28

In this answer I attempted to create a static utility method to make a List into a Map:

public static  Map toMa         


        
相关标签:
3条回答
  • 2021-01-25 06:10

    Your last line calls the method toMapBy in which the compiler infers the type Student for T. So it obviously returns a List<Long, Student>.

    But generics aren't covariant!

    That means, you cannot assign a List<Long, Student> to a variable of type List<Long, Person>, because they are not in a subtype relationship.

    The solution is to use the subtype form:

    Map<Long, ? extends Person> peopleById2 = toMapBy(students, Student::getId); // no compiler error
    
    0 讨论(0)
  • 2021-01-25 06:11

    You could add a type parameter for the values of the map so they can be different from T:

    public static <K, V, T extends V> Map<K, V> toMapBy(List<T> list,
            Function<? super T, ? extends K> mapper) {
        return list.stream().collect(Collectors.toMap(mapper, Function.identity()));
    }
    
    0 讨论(0)
  • 2021-01-25 06:17

    With this bit:

    Map<Long, Person> peopleById1 = students.stream()
            .collect(Collectors.toMap(Student::getId, Function.identity()));
    

    Notice that you do not provide arguments to Function.identity(). The compiler is free to infer it as Function.<Person>identity() to resolve the difference imposed by the return value assignment.

    This should be good enough for your purpose:

    public static <K, T> Map<K, T> toMapBy(
        List<? extends T> list, // <- note
        Function<? super T, ? extends K> mapper
    ) {
        ...
    }
    

    Now the elements of the List can be a subtype of the Map values. Or you can define a third parameter like @Alex has suggested.

    0 讨论(0)
提交回复
热议问题