gpt4 book ai didi

java - 如何使用 Java 8 Stream 将 Array 转换为 HashMap

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:13:52 25 4
gpt4 key购买 nike

我正在编写一个使用 Java 8 Stream 将数组转换为 Map 的函数。

这是我想要的

public static <K, V> Map<K, V> toMap(Object... entries) {
// Requirements:
// entries must be K1, V1, K2, V2, .... ( even length )
if (entries.length % 2 == 1) {
throw new IllegalArgumentException("Invalid entries");
}

// TODO
Arrays.stream(entries).????
}

有效用法

Map<String, Integer> map1 = toMap("k1", 1, "k2", 2);

Map<String, String> map2 = toMap("k1", "v1", "k2", "v2", "k3", "v3");

无效用法

Map<String, Integer> map1 = toMap("k1", 1, "k2", 2, "k3");

有什么帮助吗?

谢谢!

最佳答案

你可以使用

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);
}

但它会给您一个(有根据的)未检查 警告。您的方法无法 promise 返回正确输入的 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对象,但获得编译时类型安全性,甚至拒绝使用奇数个参数调用它的尝试。

您必须在一定数量的参数处进行切割,但是,如前所述,即使是可变参数也不支持无限参数。和 ofEntries(entry(…), …)对于较大的 map ,形式并不是那么糟糕。


Collection 家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)相反。

关于java - 如何使用 Java 8 Stream 将 Array 转换为 HashMap,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41946327/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com