问题描述
我正在为removeAll
写一个方法ArrayList
。通过该接口,removeAll
取一个Collection<?>
,但是,出于任何原因,我都希望Collection
只能是String
个。有没有办法一次针对整个Collection
执行此操作?
(我并不是说要单独遍历每个元素,就像这样:
for (Object el : c) {
if (!(el instanceof String)) {
throw new ClassCastException(String.format("Object %s is not of type String.",el.toString()));
}
}
这是我的备份,但我希望一次检查整个Collection
。)
我确实尝试过:
public boolean removeAll(Collection<?> c) {
return subMethod((Collection<? extends String>) c,true); //true is unimportant here
}
但这只是将任何Collection<Wrapper of Primitive>
转换为Collection<String>
。
编辑:明确地说,我想采用其他方法来确保Collection
仅包含String
。
解决方法
不,没有办法。
Java通过擦除实现泛型,因此Collection<>
本身不知道其创建时的类型参数是什么。
仅当编译代码时,才会存在Collection上的泛型类型的概念,并且通过实现List.removeAll()
,您将被该方法提供的特定签名所束缚,其中不包括{{1 }}规范,例如? extends E
之类的某些方法。
此外,addAll()
的界面documentation明确表示(添加了强调):
投掷:
ClassCastException-如果此列表的元素的类与指定的集合不兼容(可选)
因此,为了履行此接口的约定,仅当您自己的列表中的元素与您的特定集合类型不兼容时,才应引发异常:您不应仅引发异常因为传入的参数中的项目不兼容。这就是为什么方法签名首先不包含List.removeAll()
的原因:您应该允许在集合中提供其他类型,而忽略它们,因为它们显然将不匹配任何值。您的列表。
如果您要确保给定的集合仅包含字符串,则一种选择是不实现<? extends E>
接口。这有明显的缺点,但是如果您的实现是特殊的,则实现的使用者可能值得承认他们正在使用具有特殊要求的特殊类,并且不能将其交给仅知道什么的方法与广义List
有关。如果这样做的话,您将拥有更大的灵活性,包括将List
声明为采用removeAll()
或什至可以保证仅包含String的更具体,专门,非通用的集合类型。它。
可能类似于:
boolean b = c.stream().allMatch(String.class::isInstance);
if(b){
//
}