Java Wildcard ошибка
Как правильно написать метод?
private HashMap<?, ?> zip(List<?> k, List<?> v) {
if (ensure(k, v))
throw new IndexOutOfBoundsException();
HashMap<?, ?> map = new HashMap<>();
for (int i = 0; i < keys.size(); i++)
map.put(k.get(i), v.get(i));
return map;
}
Ответы (1 шт):
Автор решения: Nowhere Man
→ Ссылка
Имеет смысл избавиться от wildcard и сделать метод обобщённым и/или утилитарным (статическим), чтобы обеспечить контроль типов.
Также в методе zip не определена переменная keys, которая скорей всего должна быть заменена на список ключей k, и лучше, чтобы он возвращал интерфейс Map, а не конкретную реализацию HashMap:
private <K, V> Map<K, V> zip(List<K> keys, List<V> values) {
if (ensure(keys, values)) {
throw new IndexOutOfBoundsException();
}
Map<K, V> map = new HashMap<>();
for (int i = 0, n = keys.size(); i < n; i++) {
map.put(keys.get(i), values.get(i));
}
return map;
}
Вариант с использованием Stream API:
private static <K, V> Map<K, V> zipp(List<K> keys, List<V> values) {
if (keys.size() != values.size()) {
throw new IndexOutOfBoundsException();
}
return IntStream.range(0, keys.size())
.mapToObj(i -> Map.entry(keys.get(i), values.get(i)))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v2));
}
Обновление
Если требуется объединить несколько списков (чтобы одному ключу отвечало несколько значений), могут быть следующие варианты:
- создать мапу со значениями-списками
Map<K, List<?>>-- "грязный" способ
private static <K, V, E> Map<K, List<?>> zipp(List<K> keys, List<V> first, List<E> second) {
if (keys.size() != first.size() || keys.size() != second.size()) {
throw new IndexOutOfBoundsException();
}
return IntStream.range(0, keys.size())
.mapToObj(i -> Map.entry(keys.get(i), List.of(first.get(i), second.get(i))))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v2));
}
- более чистый вариант - использовать типизированный класс-контейнер типа пары
Pair<V, E>(например, при помощи типизированного кортежа record):
record Pair<V, E>(V first, E second){}
private static <K, V, E> Map<K, Pair<V, E>> zippp(List<K> keys, List<V> first, List<E> second) {
if (keys.size() != first.size() || keys.size() != second.size()) {
throw new IndexOutOfBoundsException();
}
return IntStream.range(0, keys.size())
.mapToObj(i -> Map.entry(keys.get(i), new Pair<>(first.get(i), second.get(i))))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v2));
}
Тесты:
List<Integer> k = Arrays.asList(1, 2, 3, 4, 5, 2);
List<String> v = Arrays.asList("aa", "bb", "cc", "xx", "yy", "pp");
List<Double> e = Arrays.asList(2.0, 4d, 8d, 10d, 4d, 5d);
System.out.println(zipp(k, v)); // Map<Integer, String>
System.out.println(zipp(k, v, e)); // Map<Integer, List<?>>
System.out.println(zippp(k, v, e)); // Map<Integer, Pair<String, Double>>
Результат:
{1=aa, 2=pp, 3=cc, 4=xx, 5=yy}
{1=[aa, 2.0], 2=[pp, 5.0], 3=[cc, 8.0], 4=[xx, 10.0], 5=[yy, 4.0]}
{1=Pair[first=aa, second=2.0], 2=Pair[first=pp, second=5.0], 3=Pair[first=cc, second=8.0], 4=Pair[first=xx, second=10.0], 5=Pair[first=yy, second=4.0]}
