【问题标题】:Warning for generic varargs泛型可变参数警告
【发布时间】:2011-05-14 13:26:51
【问题描述】:

我已经声明了以下方法:

private void mockInvokeDBHandler(Map<String, Object>... rows) {
    List<Map<String, Object>> allRows = Arrays.asList(rows));
    // rest of method omitted
}

它由客户端使用类似的东西调用

Map<String, Object> row1 = new HashMap<String, Object>();
Map<String, Object> row2 = new HashMap<String, Object>();

mockInvokeDBHandler(row1, row2);

但是,上面显示的最后一行会产生警告

类型安全:为可变参数创建 Map 的通用数组

我不完全理解这一点,但我想这是因为 varargs 参数被转换为数组,并且拥有一个类型为泛型类的数组是个坏主意(因为泛型是不变的,而数组不是) .

我可以通过将方法重新定义为来解决这个问题

private void mockInvokeDBHandler(List<Map<String, Object>> rows) {
}

但这会增加将行对象放入客户端 List 的负担,我宁愿避免这种情况。有没有更好的解决方案?

【问题讨论】:

  • 恕我直言,您可以忽略警告。
  • 我确定您的实际代码可以编译,但似乎您在这里有一个发布错误:ListMap&lt;String, Object&gt; allRows,应该是List&lt;Map&lt;String, Object&gt;&gt; allRows
  • @Mark E - 谢谢,代码很好,只是在我的帖子中打错了

标签: java generics variadic-functions


【解决方案1】:

为了将参数传递给可变参数方法,编译器会将参数放入数组中。

警告是让您知道编译器无法保证数组中的每个元素(可变参数方法的每个参数)都是真正的Map&lt;String, Object&gt;

这是一个令人讨厌的警告,因为除了重新定义方法签名以不使用可变参数之外,您无法解决此问题。只要您非常确定这些参数的实际运行时类型(在这种情况下,您就是),IMO 就可以安全地忽略它。

【讨论】:

    【解决方案2】:

    没有办法避免这个警告,除了在方法中添加@SuppresWarning("unchecked") :)

    由于您说它是私有方法,因此在这种情况下没有“客户端”,并且您可以控制该方法,因此忽略警告似乎是合理的。

    当我创建将参数化类型作为可变参数的方法时,我创建了一些重载:

    void mockInvokeDBHandler(Map<String, Object> map1)
    void mockInvokeDBHandler(Map<String, Object> map1, Map<String, Object> map2)
    void mockInvokeDBHandler(Map<String, Object> map1, Map<String, Object> map2, Map<String, Object>... othermaps)
    

    这可以避免一些警告,具体取决于提供的参数数量。

    【讨论】:

    • 避免这种重载正是我想使用可变参数的原因
    【解决方案3】:

    对于任何登陆这里的人来说,答案都有些陈旧。 Java 7 引入了@Safevarargs 注释来解决这个问题:

    @SafeVarargs
    private void mockInvokeDBHandler(Map<String, Object>... rows) {
    

    来自 javadoc:

    程序员断言带注释的方法的主体或 构造函数不会对其执行潜在的不安全操作 可变参数。将此注释应用于方法或 构造函数抑制关于 a 的未经检查的警告 non-reifiable 变量 arity (vararg) 类型并抑制 关于调用时参数化数组创建的未经检查的警告 网站。

    【讨论】:

    • 并且方法必须是有效的final
    【解决方案4】:

    您可以通过使用一些构建器接口(例如the one I'm using)来减轻使用列表而不是可变参数的负担。使用这个 CollectionBuilder,它会变成这样:

    mockInvokeDBHandler(CollectionBuilder.<Map<String, Object>>list().add(map1).add(map2).get());
    

    虽然没有通用参数,但它更漂亮:

    import static at.molindo.utils.collections.CollectionBuilder.list
    
    List<String> list = list(String.class).add("foo").addAll(set).get();
    

    它肯定比可变参数解决方案更长,但有时还是很方便的。

    【讨论】:

      猜你喜欢
      • 2012-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多