【问题标题】:Java - Cast a MapJava - 投射地图
【发布时间】:2011-12-08 22:41:51
【问题描述】:

如何以最干净的方式将Map<Object,Object> 转换为Map<String,String>

有没有办法在不遍历地图的情况下做到这一点?

谢谢

【问题讨论】:

  • 为什么Map<String, String> 首先声明为Map<Object, Object>
  • 只是一个抽象的例子,可以将 Map 转换为 Map
  • 如果后者是您的具体要求,那么您真的必须遍历它。但是,如果它实际上是一个Map<String, String>,它被错误地声明为Map<Object, Object>,那么你就可以选择(Map)(没有泛型类型参数)。
  • 您似乎对强制转换(只是告诉编译器一些已经正确的事情)和转换(对数据进行操作)感到困惑。
  • 在某些情况下对象映射是合适的,但这是例外而不是规则。

标签: java casting map


【解决方案1】:
 public  Map<String, String> castOnlyStringValues(final Map<String, Object> map) {
    return map.entrySet().stream()
              .filter(x -> String.class.isAssignableFrom(x.getValue().getClass()))
              .map(x -> (Entry<?, ?>) x).map(x -> (Entry<String, String>) x)
              .collect(toMap(Entry::getKey, Entry::getValue));
}

【讨论】:

    【解决方案2】:

    如果你想要干净的东西,你必须“深度”转换!键和值。

    使用 Java 8 流,只需几行代码:

    static public Map<String, String> toStringString(Map<? extends Object, ? extends Object> map) {
            return map
                    .entrySet()
                    .stream()
                    .collect(Collectors.toMap(
                        e -> e.getKey().toString(),
                        e -> e.getValue().toString()
                    ));
        }
    

    【讨论】:

      【解决方案3】:

      我认为解释一下为什么简单的解决方案不起作用以及为什么你永远不应该使用它是个好主意。

      假设您可以将 List&lt;Object&gt; 转换为 List&lt;String&gt;(这同样适用于 Map,只是一个更简单的界面)。您希望从以下代码中发生什么:

      List<Object> m = Something;
      m.add("Looks good.");
      m.add(42);
      List<String> s = (List<String>)m; // uhuh, no we don't want that.
      String myString = s.get(1); // huh exception here.
      

      现在您确实可以使用 Bohemians/Chris 解决方案破解它,但您基本上会破坏 Java 的类型系统。 不要那样做。您不希望List&lt;String&gt; 包含整数!以后调试愉快 - 循环遍历所有变量的附加代码将避免很多麻烦,而且几乎不是性能问题。

      如果有理由将 Map 声明为采用 Object 而不是 String,则有人可能会向其中添加任何对象 - 通常您应该能够使用更好的泛型来避免这种情况。

      【讨论】:

      • 更多现实生活中的例子。请参阅java.util.Properties extends Hashtabl&lt;Object,Object&gt;,但您想使用和Map&lt;String,String&gt; 而不是使用属性的getProperty 方法。所以你必须先转换。
      • 我真的很喜欢你的回答风格......让我想起了我如何处理许多问题;-)
      • 我讨厌工具决定我是否应该做某事。如果我需要将List&lt;String&gt; 转换为List&lt;Object&gt; 怎么办,我无法重新设计我的代码,这是两个第三方库,所以我应该将一个列表映射到另一个列表,以便以 java'sh 的方式进行?
      • @deathangel 不,你应该这样做以避免破坏类型系统。
      • 地图案例我该怎么办? stringList.stream().map(e -&gt; (Object) e).collect(toList())?如果我只是将List&lt;String&gt; 转换为List&lt;Object&gt;,我会得到什么异常?每条规则都有例外。
      【解决方案4】:

      实际答案是:

      Map<Object,Object> valueMap = ...;
      @SuppressWarnings("unchecked")
      Map<String,String> targetMap = (Map)valueMap;
      

      【讨论】:

      • 因为它不能编译。
      • 哦,哇,它没有。谢谢BalusC。好吧,我编辑了我的 sn-p 以进行一些肮脏的 hack :-)
      • 为什么 (Map)valueMap 有效但 (Map) 无效的一些解释?
      【解决方案5】:

      Chris J's answer 为基础,这是他的“hack”代码在运行,表明它有效:

      public static void main(String[] args) {
          Map<Object, Object> valueMap = new HashMap<Object, Object>();
          valueMap.put("foo", "bar");
          @SuppressWarnings("unchecked")
          Map<String, String> targetMap = (Map<String, String>) ((Object) valueMap); // hack alert!
          for (Map.Entry<String, String> entry : targetMap.entrySet()) {
              String key = entry.getKey();
              String value = entry.getValue();
              System.out.println(key + "=" + value); // prints foo=bar :)
          }
      }
      

      哇!没有运行时异常:)

      【讨论】:

      • 可怕,可怕的黑客攻击。在我看来,任何在生产代码中使用它的人都应该被取出并射击;)请注意,我假设您只提到了这一点,因为这是一个巧妙的技巧,而不是作为使用它的建议。向人们展示 Map&lt;String&gt; 如何包含整数总是很有趣..
      • 嗯......我确实说过这是一个肮脏的黑客;-)
      • 虽然我同意这通常是错误的,但在某些情况下对象映射是合适的。
      猜你喜欢
      • 1970-01-01
      • 2020-03-08
      • 1970-01-01
      • 2017-12-04
      • 2021-12-21
      • 1970-01-01
      • 1970-01-01
      • 2017-04-08
      • 1970-01-01
      相关资源
      最近更新 更多