Java:通用过滤器映射函数

我正在尝试开发一个通用函数来过滤地图.

我到目前为止的代码是:

public static Map<?, ?> filterAttrs(Map<?, ?> args, String... unless) {

    Map<?, ?> filteredAttrs = Map.class.newInstance();

    Arrays.sort(unless);
    for (Object o : args.keySet()) {
        if (Arrays.binarySearch(unless, o.toString()) < 0 ) {
            filteredAttrs.put(o, args.get(o));
        }
    }
    return filteredAttrs;
}

我在filteredAttrs.put中收到以下错误

The method put(capture#5-of ?, capture#6-of ?) in the type Map is not applicable for the arguments (Object, capture#8-of ?)

我不知道如何实例化一个通用Map(我尝试使用1Map.class.newInstance()`).

有任何想法吗?

编辑:在阅读了许多答案后,问题似乎是如何使filteredAttrs成为与args相同类型的实例. (Map)args.getClass().newInstance()似乎可以解决问题.

此代码的问题是类型系统阻止您将对象放入其键类型为?的Map中.这是因为如果键类型是?,则编译器不知道实际存储在映射中的是什么 – 它可以是Object,Integer,或List< Object> – 因此它无法确认您尝试添加到地图中的内容实际上是否为正确类型,并且不会在地图中不合适.例如,如果您有此方法:

public static void breakMyMap(Map<?, ?> m) {
    m.put(new Object(), new Object()); // Won't compile
}

然后编写如下代码:

Map<String, String> myMap = new HashMap<String, String>();
breakMyMap(myMap);

然后,如果breakMyMap中的代码要编译,它会将一对Object作为键和值放入Map< String,String>中,打破所有元素确实是字符串的不变量.

要解决这个问题,不要让这个函数在Map<?,?>上运行,而是更改函数,以便获得有关键和值的更多类型信息.例如,你可以试试这个:

public static <K, V> Map<K, V> filterAttrs(Map<K, V> args, String... unless) {

    Map<K, V> filteredAttrs = new HashMap<K, V>();

    Arrays.sort(unless);
    for (K o : args.keySet()) {
        String attr = o.toString();
        if (Arrays.binarySearch(unless, o.toString()) < 0 ) {
            filteredAttrs.put(o, args.get(o));
        }
    }
    return filteredAttrs;
}

现在编译器知道密钥类型是K,它可以验证put不会混淆map中键的类型.

我应该指出的另一件事是你所拥有的代码即使编译也不会有效.原因是这条线

Map<?, ?> filteredAttrs = Map.class.newInstance();

将在运行时导致异常,因为Map是一个接口,而不是一个类,因此尝试使用newInstance创建它的实例将无法正常工作.要解决这个问题,您可以显式指定地图的类型(正如我在上面的代码中所做的那样),或者获取参数的类:

Map<K, V> filteredAttrs = args.getClass().newInstance();

当然,这也不保证可以工作,尽管集合的一般合同是所有集合都应该有一个无参数的构造函数.

希望这可以帮助!

相关文章
相关标签/搜索