我正在尝试构建一种方法来合并两个 map 的内容。我在这里环顾了一段时间,看不出有什么方法可以使它通用。我想避免 @SuppressWarnings("unchecked")
注释,如果可能的话。我有一个嵌套的映射结构,其中键是字符串,值是更多内容的映射,此结构中的“叶”节点始终是集合。所以在大多数情况下,我有两张结构如下的 map :
Map<String,Map<String,Set<String>>>
我想合并两个映射,这样我最终得到两个映射的并集,这两个映射中的任何公共(public)键都在结果映射中表示,其值是两个值的合并 map 。在代码中,这是我到目前为止所拥有的:
@SuppressWarnings("unchecked")
public Map<String,Object> merge(final Map<String, Object> map1,
final Map<String, Object> map2) {
final Map<String,Object> merged = new HashMap<String,Object>(map1);
for (final Map.Entry<String,Object> entry : merged.entrySet()) {
final String key = entry.getKey();
final Object value = entry.getValue();
if (map2.containsKey(key)) {
final Object value2 = map2.get(key);
if ((value instanceof Map) && (value2 instanceof Map)) {
merged.put(key, merge((Map<String, Object>) value, (Map<String, Object>) value2));
} else if ((value instanceof Set) && (value2 instanceof Set)) {
final Set<Object> set = new HashSet<Object>((Set<Object>)value);
set.addAll((Set<Object>) value2);
merged.put(key, set);
} else {
// throw up, should only ever be a map or a set
}
}
}
for (final String key : map2.keySet()) {
if (!merged.containsKey(key)) {
merged.put(key, map2.get(key));
}
}
return merged;
}
它完成了工作,但我对它不满意,因为使用它你正在转换一大堆东西,它还对你正在使用的 Set 和 Map 实现做出假设。鉴于我知道我总是在处理字符串到某物的映射,其中某物是一组字符串或另一个字符串到某物的映射,我试图弄清楚如何使用泛型来规范它。我摆弄了类似但不完全相同的方法,显示在附近的其他答案中,例如方法签名如下:
public <T extends Map<String,T>> Map<String,T> merge(final T map1, final T map2)
但这没有成功,因为递归调用不喜欢我尝试输入 Map<String,Set<String>>
的参数。 .
我承认以前从来没有需要深入研究泛型。非常感谢任何指导。
最佳答案
重新假设 Set
和 Map
你正在使用的实现:如果你总是创建新的 map 和集合,你至少可以避免这种情况——这有一个很好的附带好处,即如果有人修改了原始集合,它不会搞砸你的合并版本。
至于您的要点,如果不进行强制转换,就无法在 Java 中执行此操作。泛型帮不了你,因为在运行时,编译器只知道
Map<String, Object> merge ( Map<String, ?> map1, Map<String, ?> map2 )
您实际上并不知道您的代码中是否有一个 Map<String, Set<String>>
, 一个 Map<String, Map<String, Set<String>>
, 或 Map<String, Object>
其中一些值为 Set<String>
和其他值是 Map<String, Set<String>>
-- 在第三种情况下它仍然有效,只要对于每个键,两个映射都具有相同的值类型。
自相矛盾的是,摆脱警告的最好方法是摆脱泛型,此时,仅使用运行时可用的信息( Map
或 Set
,我们不关心什么), 所有的转换都是安全的:
public Map<Object, Object> merge ( Map<?, ?> map1, Map<?, ?> map2 )
{
Map<Object, Object> merged = new HashMap<Object, Object>();
if ( map1 == null || map2 == null )
{
if ( map1 != null )
{
merged.putAll( map1 );
}
if ( map2 != null )
{
merged.putAll( map2 );
}
return merged;
}
Set<Object> allKeys = new HashSet<Object>();
allKeys.addAll( map1.keySet() );
allKeys.addAll( map2.keySet() );
for ( Object key : allKeys )
{
Object v1 = map1.get( key );
Object v2 = map2.get( key );
if ( v1 instanceof Set || v2 instanceof Set )
{
Set<Object> newSet = new HashSet<Object>();
if ( v1 instanceof Set )
{
newSet.addAll( (Set) v1 );
}
if ( v2 instanceof Set )
{
newSet.addAll( (Set) v2 );
}
merged.put( key, newSet );
}
else if ( v1 instanceof Map || v2 instanceof Map )
{
Map<?, ?> m1 = v1 instanceof Map ? (Map<?, ?>) v1 : null;
Map<?, ?> m2 = v2 instanceof Map ? (Map<?, ?>) v2 : null;
merged.put( key, merge( m1, m2 ) );
}
}
return merged;
}
关于java - map 与泛型的递归合并,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15959733/