我正在编写一个方法,用“Predicate”过滤特定的Collection,并返回一个只包含过滤元素的新Collection(Predicate返回true的那些)。
这样的事情:
public <T> Collection<T> filter(Collection<T> collection, Closure<T> predicate);
我知道,在Java中,由于类型擦除,我不能在运行时创建新的Collection()
。
我也通过将一个额外参数传递给方法来调用T.newInstance()来了解“解决方法”。
这看起来像是:
public <T> Collection<T> filter(Class<? extends Collection<T>> collectionToInstanciate, Collection<T> collection, Closure<T> predicate) {
// create the new Collection
Collection<T> container = collectionToInstanciate.newInstance();
// and then add only filtered items
Iterator<T> iter = collection.iterator();
while (iter.hasNext()) {
T obj = iter.next();
// if Predicate.invoke() returns true, then keep element, otherwise skip it
if (predicate.invoke(obj)) {
container.add(obj);
}
}
return container;
}
但是我应该如何调用我的方法?
例如,如果我只想要奇数列表的整数,我想这样做:
// instanciate ArrayList<Integer> = [1, 2, 3, 4, 5]
ArrayList<Integer> array = ...;
// return a new LinkedList<Integer> with only odd numbers
filter(LinkedList<Integer>.class, array, new Closure<Integer>() {
public Boolean invoke(Integer arg_p) {
return (arg_p % 2 == 0);
}
});
// should return [2, 4] as a LinkedList<Integer>
问题在于
LinkedList<Integer>.class
无法编译。
我应该如何声明在filter()方法中正确实例化LinkedList?
此致
答案 0 :(得分:3)
泛型是一个编译时功能,在运行时没什么意义。如果要创建LinkedList,就是这样做的。你不能让编译器根据你在运行时做的事情给你一个错误。
更简单的解决方案是传递要填充的类的实例。
List<Integer> result = filter(new LinkedList<Integer>(), array,
new Predicate<Integer>() {
public boolean invoke(Integer arg_p) {
return (arg_p % 2 == 0);
}
});
它略短,可以在编译时检查。
注意:许多这些谓词作为普通循环更简单,更快。
List<Integer> result = new LinkedList<Integer>();
for(Integer i: array)
if (i % 2 == 0)
result.add(i);
答案 1 :(得分:0)
从Peter Lawrey的回答和LuiggiMendoza的评论中,另一种方法是以这种方式使用filter()方法:
List<Integer> result = filter(
LinkedList.class, // instead of new LinkedList<Integer>()
array,
new Predicate<Integer>() {
public boolean invoke(Integer arg_p) {
return (arg_p % 2 == 0);
}
});
在filter()方法中:
public <T> Collection<T> filter(Class<? extends Collection> collectionToInstanciate, Collection<T> collection, Closure<T> predicate) {
// create the new Collection as a raw Collection, and cast it back to Collection<T>
Collection<T> container = (Collection<T>) collectionToInstanciate.newInstance();
// and then add only filtered items
Iterator<T> iter = collection.iterator();
while (iter.hasNext()) {
T obj = iter.next();
// if Predicate.invoke() returns true, then keep element, otherwise skip it
if (predicate.invoke(obj)) {
container.add(obj);
}
}
return container;
}