Вы можете использовать
public static <K, V> Map<K, V> toMap(Object... entries) {
if(entries.length % 2 == 1)
throw new IllegalArgumentException("Invalid entries");
return (Map<K, V>)IntStream.range(0, entries.length/2).map(i -> i*2)
.collect(HashMap::new, (m,i)->m.put(entries[i], entries[i+1]), Map::putAll);
}
, но это даст вам (основано) непроверенной предупреждения. Ваш метод не может сдержать обещание вернуть правильно напечатанный Map<K, V>
для массива произвольных объектов, и, что еще хуже, он не сработает с исключением, но тихо возвратит несогласованную карту, если вы передадите объекты неправильного типа.
Очиститель, обычно используется, раствор
public static <K, V> Map<K, V> toMap(
Class<K> keyType, Class<V> valueType, Object... entries) {
if(entries.length % 2 == 1)
throw new IllegalArgumentException("Invalid entries");
return IntStream.range(0, entries.length/2).map(i -> i*2)
.collect(HashMap::new,
(m,i)->m.put(keyType.cast(entries[i]), valueType.cast(entries[i+1])),
Map::putAll);
}
Это может быть собран без предупреждения, так как правильность будут проверены во время выполнения. Вызывающий код должен быть адаптировано:
Map<String, Integer> map1 = toMap(String.class, Integer.class, "k1", 1, "k2", 2);
Map<String, String> map2 = toMap(
String.class, String.class, "k1", "v1", "k2", "v2", "k3", "v3");
Помимо необходимости указать фактические типы как класс литералы, он имеет тот недостаток, что не поддерживает общий ключевой или значение типа (так как они не могут быть выражены в виде Class
) и по-прежнему не имеют безопасности во время компиляции, а только проверку времени выполнения.
Это стоит looking at Java 9. Там вы сможете сделать:
Map<String, Integer> map1 = Map.of("k1", 1, "k2", 2);
Map<String, String> map2 = Map.of("k1", "v1", "k2", "v2", "k3", "v3");
Это создаст непреложной карты неопределенного типа, а не HashMap
, но интересный момент является API.
Существует метод <K,V> Map.Entry<K,V> entry(K k, V v)
, который может быть объединен с
<K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>... entries)
создать карту переменной длины (переменные аргументы по-прежнему ограничены 255 параметров, хотя).
Вы можете реализовать подобную вещь:
public static <K,V> Map.Entry<K,V> entry(K k, V v) {
return new AbstractMap.SimpleImmutableEntry<>(k, v);
}
public static <K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>... entries) {
return Arrays.stream(entries)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
Метод удобства (ы) of
реализованы единственным способом, это может быть сделано с безопасностью типа: а перегружена метода с различным числом аргументов, как
public static <K,V> Map<K,V> of() {
return new HashMap<>();// or Collections.emptyMap() to create immutable maps
}
static <K,V> Map<K,V> of(K k1, V v1) {
return ofEntries(entry(k1, v1));
}
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2) {
return ofEntries(entry(k1, v1), entry(k2, v2));
}
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
return ofEntries(entry(k1, v1), entry(k2, v2), entry(k3, v3));
}
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
return ofEntries(entry(k1, v1), entry(k2, v2), entry(k3, v3), entry(k4, v4));
}
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
return ofEntries(entry(k1, v1), entry(k2, v2), entry(k3, v3), entry(k4, v4));
}
(Java 9 делает разрез в десяти сопоставлениях, если у вас их больше, вам необходимо использовать вариант ofEntries(entry(k1, v1), …)
).
Если вы будете следовать этому образцу, вы должны держать свой toMap
имя или использовать только map
, а не заходя в «of
», как вы не пишете интерфейс Map
.
Эти перегрузки могут выглядеть не очень элегантно, но они решают все проблемы. Вы можете написать код так же, как в своем вопросе, без указания объектов Class
, но получить безопасность типа компиляции и даже отказаться от попыток вызвать его с нечетным количеством аргументов.
Вы должны сделать разрез с определенным количеством параметров, но, как уже отмечалось, даже varargs не поддерживают неограниченные параметры. Форма ofEntries(entry(…), …)
не так плоха для больших карт.
Коллектор Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)
возвращает неопределенный тип карты, который может быть даже неизменным (хотя это HashMap
в текущей версии). Если вы хотите получить гарантию возврата экземпляра HashMap
, вместо этого вы должны использовать Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1,v2)->{throw new IllegalArgumentException("duplicate key");}, HashMap::new)
.
лучше просто использовать добрые старые 'for' loop :) – ZhongYu
Возможно, вы найдете то, что ищете: [собрать последовательные пары из потока] (http://stackoverflow.com/questions/20470010/collect-successive -пар-из-а-потока). – MikaelF
Ссылка https://stackoverflow.com/questions/31693781/convert-string-array-to-map-using-java-8-lambda-expressions –