Java:通用过滤器映射函数

Java:通用过滤器映射函数,java,filter,map,clone,Java,Filter,Map,Clone,我正在尝试开发一个通用函数来过滤地图 到目前为止,我掌握的代码是: public static Map<?, ?> filterAttrs(Map<?, ?> args, String... unless) { Map<?, ?> filteredAttrs = Map.class.newInstance(); Arrays.sort(unless); for (Object o : args.keySet()) {

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

到目前为止,我掌握的代码是:

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;
}
公共静态映射筛选器(映射参数、字符串…除非){
Map filteradattrs=Map.class.newInstance();
数组。排序(除非);
对于(对象o:args.keySet()){
if(Arrays.binarySearch(除非,o.toString())<0){
filteredAttrs.put(o,args.get(o));
}
}
返回过滤器REDATTRS;
}
我在filteredAttrs.put中得到以下错误

类型映射中的方法put(capture#5-of?,capture#6-of?)不适用于参数(Object,capture#8-of?)

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

有什么想法吗


编辑:在阅读了许多答案之后,问题似乎是如何使
filteradattrs
成为与
args
相同类型的实例
(Map)args.getClass().newInstance()
似乎起到了作用。

此代码的问题在于类型系统阻止您将对象放入键类型为
Map
中。这是因为如果键类型是
,编译器不知道映射中实际存储的是什么-它可能是
对象
,或
整数
,或
列表
,因此它无法确认您试图添加到映射中的内容实际上是正确的类型,并且不会在
映射中不合适。例如,如果您有此方法:

public static void breakMyMap(Map<?, ?> m) {
    m.put(new Object(), new Object()); // Won't compile
}
既然编译器知道键类型是
K
,它就可以验证
put
不会混淆映射中键的类型

我应该指出的另一件事是,即使编译了,您的代码也永远不会工作。原因是这条线

Map<?, ?> filteredAttrs = Map.class.newInstance();
当然,这也不能保证有效,尽管集合的一般约定是所有集合都应该有一个无参数构造函数

希望这有帮助

这条线

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

应该抛出实例化异常-因为
Map
是一个接口-除非您实现了自己的名为
Map

的类,否则无法实例化Map,因为它是一个接口。不要使用
,因为它一开始会造成混乱

public static <T, K> Map<T, K> filterAttrs(Map<T, K> args, T... unless) {
    Map<T, K> filteredAttrs;

    filteredAttrs = new HashMap<T, K>();
    Arrays.sort(unless);
    for (T o : args.keySet()) {
        if (Arrays.binarySearch(unless, o) < 0) {
            filteredAttrs.put(o, args.get(o));
        }
    }

    return filteredAttrs;
}

您不能将任何内容放入
映射
,因为编译器不知道它是什么类型的映射。行中:

filteredAttrs.put(o, args.get(o));
您假装
映射
映射
,但事实并非如此。Angelika Langer的Java泛型常见问题解答更详细地解释了这一点

应该向方法中添加类型参数;然后,也不必通过反射创建新贴图:

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()) {
        if (Arrays.binarySearch(unless, o.toString()) < 0) {
            filteredAttrs.put(o, args.get(o));
        }
    }
    return filteredAttrs;
}
公共静态映射筛选器(映射参数、字符串…除非){
Map filteradattrs=new HashMap();
数组。排序(除非);
对于(ko:args.keySet()){
if(Arrays.binarySearch(除非,o.toString())<0){
filteredAttrs.put(o,args.get(o));
}
}
返回过滤器REDATTRS;
}

我认为如果人们在重新发明车轮(而不是做得更好),那就不好了。 用一个建议来解决你所有的问题:你能试试吗

例如,您可以使用:

  • 地图过滤
  • 地图过滤键
  • Maps.filterValues

或者至少写一个以谓词为参数的过滤器。

回答得好!我开始尝试使用泛型,但找不到实例化泛型映射的方法。(Map)args.getClass().newInstance()似乎做了我理解正确的事情,这段代码在运行时确定如何实例化filteredAttrs,然后将其转换为映射。编译器有足够的信息在编译时知道filteradattrs类型(即,与args相同的类型),没有办法告诉它吗?@opensas-你是对的,不需要强制转换。我刚把它取下来。自从1.5之前,我就没有使用过
newInstance
,所以我不知道它在运行时是否有正确的类型信息。谢谢你指出这一点!是的,有了这个cropded down示例,行是无用的,我将从问题中删除它,谢谢…我希望filteredAttrs与args的类型相同(HaspMap、LinkedHashMap,无论什么),只实例化一个新的HashMap可以吗???我如何告诉编译器这样做?
public static <T, K> Map<T, K> filterAttrs(Map<T, K> args, T... unless) {
    Map<T, K> filteredAttrs;

    filteredAttrs = new HashMap<T, K>();
    Arrays.sort(unless);
    for (T o : args.keySet()) {
        if (Arrays.binarySearch(unless, o) < 0) {
            filteredAttrs.put(o, args.get(o));
        }
    }

    return filteredAttrs;
}
String attr = o.toString();
filteredAttrs.put(o, args.get(o));
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()) {
        if (Arrays.binarySearch(unless, o.toString()) < 0) {
            filteredAttrs.put(o, args.get(o));
        }
    }
    return filteredAttrs;
}