У меня проблема с дженериками в java, в частности с подстановочными знаками. У меня есть Map
(outerMap
), значениями которого являются другие элементы Map
(innerMap
), значения которых составляют List
элементов.Метод вызова сбоя компиляции с вложенным шаблоном
См. Следующий класс java, который я создал, чтобы продемонстрировать это поведение. Операции импорта не включены. Игнорировать использование потоков внутри методов, это не имеет значения:
public class SSCCE {
public static void main(String[] args) {
// Setup
List<Double> doubles = Arrays.asList(1.0,2.0,3.0);
Map<Integer, List<Double>> innerMap = new HashMap<>();
innerMap.put(1, doubles);
Map<String, Map<Integer, List<Double>>> outerMap = new HashMap<>();
outerMap.put("hello", innerMap);
// Test
// This method call works fine.
Stream<Integer> streamFromInner = getStreamOfMappingToN(innerMap);
// This method call does not work - causes below compilation error.
Stream<Integer> stream = getStreamOfMergedDistinctMappingToN(outerMap);
}
private static <T, U> Stream<T> getStreamOfMappingToN(Map<T, ? extends Collection<U>> map) {
return map.entrySet().stream().map(q -> q.getKey());
}
private static <T, U> Stream<T> getStreamOfMergedDistinctMappingToN(Map<String, Map<T, ? extends Collection<U>>> map) {
return map.entrySet().stream().flatMap(
p -> getStreamOfMappingToN(p.getValue())
).distinct();
}
}
Я вижу следующее сообщение об ошибке компиляции, на втором вызове метода:
method getStreamOfMergedDistinctMappingToN in class SSCCE cannot be applied to given types;
required: Map<String,Map<T,? extends Collection<U>>>
found: Map<String,Map<Integer,List<Double>>>
reason: cannot infer type-variable(s) T,U
(argument mismatch; Map<String,Map<Integer,List<Double>>> cannot be converted to Map<String,Map<T,? extends Collection<U>>>)
where T,U are type-variables:
T extends Object declared in method <T,U>getStreamOfMergedDistinctMappingToN(Map<String,Map<T,? extends Collection<U>>>)
U extends Object declared in method <T,U>getStreamOfMergedDistinctMappingToN(Map<String,Map<T,? extends Collection<U>>>)
Может кто-нибудь предложить, почему это происходит со второй вызов метода, а не первый? Обе сигнатуры метода содержат Map<T, ? extends Collection<U>>
, но только второй не соответствует вызову. Если я заменил проблемный ? extends Collection<U>
на List<U>
, он отлично работает, потому что я фактически передаю его List
, но это кажется ленивым и не объясняет, почему я вижу эту ошибку.
Я немного поболтал об этом, некоторые люди столкнулись с подобными проблемами и объяснили их проблемы - многие отмечают, что уровень шаблона имеет значение, но без понимания того, что здесь происходит Мне трудно связать другие решения этой проблемы. Это все еще довольно запутанно. Благодаря чтению я обнаружил, что если я заменил Map<T, ? extends Collection<U>>
? extends Map<T, ? extends Collection<U>>
во втором объявлении метода, он компилируется отлично, но я не понимаю, почему, а затем почему первая сигнатура метода будет работать.
Буду признателен за ваш отзыв.
Более практичная проблема с этим кодом (даже когда вы его компилируете) заключается в том, что очень сложно понять, что происходит. – biziclop
@biziclop Конечно, это не мой фактический код, он просто демонстрирует проблему. Я использую потоки для отображения из 'Entry' в' T' на основе того, что находится в 'Collection', но я оставил много этого, поскольку я не думал, что это имеет отношение к проблеме.То же самое касается T и U, они могут быть чем угодно. –
http://bayou.io/draft/Capturing_Wildcards.html#Nested_Wildcards – ZhongYu