将Map条目值中的List<T>转换为Set<T>

4

我有一个包含值为List<String>的条目的Map<String,Object>,我需要将List<String>的内容获取到一个Set<String>中。我正在使用以下代码:

Map<String, Object> map = SomeObj.getMap();
if (map.get("someKey") instance of List<?>) {

    Set<String> set = new HashSet<String>((List<String>) map.get("someKey"));
}

我的基于Eclipse的IDE在这一行上有几个警告:

  • 类型安全:从Object到List未经检查的强制转换

代码编译并按照预期运行。但是否有更好的方法呢?使用@SuppressWarnings("unchecked")注释该行是我最不愿意采用的选项。


为什么映射的值类型是 Object - rgettman
这是由我使用的库所决定的。getMap() 的返回类型是 Map<String,Object> - Web User
可能是重复问题,参考 如何将超类型的列表转换为子类型的列表? - Bogdan Lukiyanchuk
3个回答

8
你可以做以下事情:
Map<String, Object> map = SomeObj.getMap();
String key = "someKey";
if (map.get(key) instanceof List<?>) {
    List<?> list = (List<?>) map.get(key);
    Set<String> set = new HashSet<>();
    // Cast and add each element individually
    for (Object o : list) {
        set.add((String) o);
    }
    // Or, using streams
    Set<String> set2 = list.stream().map(o -> (String) o).collect(Collectors.toSet());
}

注意:这样做并不更安全,但不会出现警告。+1 - Peter Lawrey
1
这段代码相对更加安全,因为你会在这里发现一个元素不是对象,而不是在尝试取出该元素时才发现。 - Andy Turner
4
(请注意,另一种编写映射转换的方法是.map(String.class::cast)。) - Andy Turner
好的,我甚至没有想到 String.class::cast,即使自 Java 1.5 起,cast 就已经存在了!与使用 .toString() 相比,使用它是否有任何优势? - Web User
null.toString() 会抛出 NPE 异常,但是 (String) nullString.class.cast(null) 都不会。 - k_ssb

3

String是一种特殊的类型,所有对象都可以使用Object.toString()方法将其转换为String类型。在String类型上调用toString()方法将返回自身。

因此,如果你知道它是一个List<?>类型,你可以按照以下方式转换为Set<String>类型:

List<?> list = (List<?>) map.get("some key");
Set<?> set = list.stream().map(Object::toString).collect(Collectors.toSet());

您可能需要处理空元素。


1
关于 null,您可能想要过滤它们,或使用 .map(String::valueOf) +1 - Peter Lawrey
只有当你想要将null元素表示为"null"时,才使用@PeterLawrey;如果你想保留它们的null值,你需要使用其他方法。 - Andy Turner
我得到了相同的答案,并投票支持第一个回答。感谢两位,我能够解决错误,并过滤掉列表中的空值...我之前没有考虑到这种情况,因为API将返回从JWT令牌解析出的键值对映射。 - Web User
@WebUser 这个答案的关键在于它是无条件安全的(一旦处理了空值),因为除了将对象转换为列表的一个强制转换之外,没有其他的强制转换;而另一种方法如果列表中的任何元素不是字符串,则会在运行时失败。 - Andy Turner
如果列表中的任何元素不是字符串,另一个答案的哪个部分将失败?使用流的方法还是第一个方法?在两种情况下,似乎对象被转换为String类型。 - Web User
@WebUser 如果不是字符串,无论是流式还是非流式方法中的字符串转换都会失败。 - Andy Turner

-2

你不能将List<>强制转换为Set<>; 这些是具有不同方法的不同接口。但是,你可以做以下操作...

Set<String> set = new HashSet<String>();
set.addAll(map.get("someKey"));

这利用了addAll对Collection接口的了解。


1
类型不匹配,map.get("someKey") 是一个 Object - k_ssb
啊,我错过了他在Map中混合使用对象类型的情况。 - TCat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接