Collections removeAll method
I would like to know if something lik开发者_JAVA百科e below is possible,
list.removeAll(namesToRemove)
I hope the context is understandable.
The list
is of type ArrayList<MyObject>
where MyObject
has a getName
method.
The namesToRemove
is an ArrayList<String>
containing names of the objects to be removed.
I know this can be achieved by overriding equals method in MyObject
class. I would like to know if any other choice is present.
You can do something like this using Google Collections Collections2.filter()
:
final List<String> namesToKeep = getNamesToFilter();
List<MyObject> filtered = Collections2.filter(originalList, new Predicate<MyObject>() {
@Override
public boolean apply(MyObject o) {
return namesToKeep.contains(o.getName());
}
});
Java 8:
list.removeIf(obj -> namesToRemove.contains(obj.getName()));
Java 7 and older:
Iterator<MyObject> iter = list.iterator();
while (iter.hasNext())
if (namesToRemove.contains(iter.next().getName()))
iter.remove();
Note that both alternatives have quadratic complexity. You can make it linear by doing
Set<String> namesToRemoveSet = new HashSet<>(namesToRemove);
before the snippets, and use namesToRemoveSet
instead of namesToRemove
.
You don't want to override anything in the Object class. You need to use either a filter utility or a collection that uses your own semantics instead of equals, maybe a ForwardingCollection wrapped around your own implementation of equivalence.
All this can be achieved with google guava without breaking any standards
Another approach: Subclass ArrayList
and implement a custom method like:
public class MyArrayList<E> extends ArrayList<E> {
// all needed constructors
public void removeAllWithNames(Collection<String> names) {
// following code is based on aioobe's answer
Iterator<E> iter = iterator();
while (iter.hasNext())
if (names.contains(iter.next().toString()))
iter.remove();
}
}
EDIT
changed the code - the comment was good, now the custom list is a 'List' again, but now we use the toString()
method (for simplicity) for filtering. (using a getName()
method is possible but requires more lines of code)
Collection<MyObject> list = Collections2.filter(list, mo -> !namesToRemove.contains(mo.getName()));
精彩评论