【问题标题】:Java - convert unmodifiable sets in a map(key, set) to modifaibleJava - 将 map(key, set) 中的不可修改集转换为可修改集
【发布时间】:2020-09-05 16:54:18
【问题描述】:

我实现了一个返回 Map<key,Set<objects>> 的函数,当我调用这个函数时,它返回类型为 Unmodifiable 的集合。

我需要对这个集合做一些操作,在最佳实践中如何将它们转换为可修改集合?否则我得到了

Exception in thread "main" java.lang.UnsupportedOperationException

提前致谢。

【问题讨论】:

    标签: java collections set guava unmodifiable


    【解决方案1】:

    假设Map 本身是可变的,您可以使用类似

    map.replaceAll((key, set) -> new HashSet<>(set));
    

    例子:

    Map<Integer,Set<Object>> map = new HashMap<>();
    map.put(5, Collections.emptySet());
    map.put(10, Collections.singleton("foo"));
    
    map.replaceAll((key, set) -> new HashSet<>(set));
    
    map.get(5).add(42);
    map.get(10).add("bar");
    
    map.entrySet().forEach(System.out::println);
    
    5=[42]
    10=[bar, foo]
    

    当然,您也可以按照复制构造函数约定将new HashSet&lt;&gt;(set) 替换为new TreeSet&lt;&gt;(set) 或通常每个Set 实现类型。当你不能使用复制构造函数时,你必须求助于addAll,例如

    map.replaceAll((key, set) -> {
        TreeSet<Object> newSet = new TreeSet<>(Comparator.comparing(Object::toString));
        newSet.addAll(set);
        return newSet;
    });
    

    还有另一种选择。无需转换地图的所有值,而是仅按需转换集合,即当您真正想要修改它们并且结果它们没有预期的类型时:

    Map<Integer,Set<Object>> map = new HashMap<>();
    map.put(5, Collections.emptySet());
    map.put(10, Collections.singleton("foo"));
    
    map.computeIfPresent(5, (key,set)->set instanceof HashSet? set: new HashSet<>()).add(42);
    map.computeIfPresent(10, (key,set)->set instanceof HashSet?set:new HashSet<>()).add("bar");
    
    map.entrySet().forEach(System.out::println);
    

    【讨论】:

      【解决方案2】:

      您可以复制original set to another one that can be modified

      类似这样的:

      Set<YourType> newSet = unmodifiableSet
                              .stream()
                              .collect(Collectors.toSet());
      // Or maybe...
      Set<YourTYpe> otherSet = new HashSet<>();
      otherSet.addAll(unmodifiableSet);
      
      

      然后,您可以毫无问题地修改新列表,并将其重新分配到地图中。

      【讨论】:

      • 是的,这正是我所做的,但我正在寻找比循环遍历所有地图以逐组转移更实用的东西。另外我不明白为什么它变成不可修改的,你知道吗?
      • 要知道为什么它变成不可修改,请发布返回地图的代码
      • 你能告诉我你是如何从你的函数中返回地图的吗?也许我们可以弄清楚为什么会这样。
      【解决方案3】:

      只需使用复制构造函数

      对于HashSet

      Set<Type> modifiable = new HashSet<>(unmodifiable);
      

      对于TreeSet

      SortedSet<Type> modifiable = new TreeSet<>(unmodifiable);
      

      对于LinkedHashSet

      Set<Type> modifiable = new LinkedHashSet<>(unmodifiable);
      

      如果你在没有这样的构造函数的情况下使用花哨的 Set 实现:

      Set<Type> modifiable = new MyFancySet<>();
      modifiable.addAll(unmodifiable);
      

      【讨论】:

      • 我使用 HashSet,这就是我为地图中的每个集合所做的。但是,与其在地图中逐个键地遍历并将集合复制到新地图中,还有更好的解决方案吗?
      • @AlaaKhalil 您绝对应该添加代码来显示您如何创建和填充地图。
      【解决方案4】:

      您可以通过Streams 单行执行此操作:

      map 是您的原始地图(例如 Map&lt;Integer, ImmutableSet&lt;Object&gt;&gt; map;

      Map<Integer, Set<Object>> mutableMap = map.entrySet()
                      .stream()
                      .collect(Collectors.toMap(Map.Entry::getKey, Sets::newHashSet));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-10-15
        • 1970-01-01
        • 2012-02-12
        • 1970-01-01
        • 2014-10-11
        • 2013-11-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多