Basically, I'd like to use a Predicate
to filter a generic (which extends Collection), and then return an instance of the same generic Collection implementation (preferably a new instance) e.g. implement the method signature F removeNulls(F inputs)
.
I have the following examples, but there are caveats to each (removeNulls4
is probably the closest to what I'm trying to achieve):
Caveats
removeNulls1:
- the returned list may(/will) not be an instance of
F
(requires casting)
removeNulls2:
- the implementation of
F
may not have an empty constructor - use of the
forReturn
object is not thread safe (if run in parallel)
removeNulls3:
- modifies the original list
- is reinventing the wheel/not parallelisable (would prefer to use the
filter
method) Iterator.remove()
can throw anUnsupportedOperationException
removeNulls4:
- modifies the original list
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class QuickTest<I, F extends Collection<I>> {
Predicate<I> removeNullsPredicate = x -> x != null;
@SuppressWarnings("unchecked")
public F removeNulls1(F inputs) throws Exception {
return (F) inputs.stream().filter(removeNullsPredicate)
.collect(Collectors.toList());
}
@SuppressWarnings("unchecked")
public F removeNulls2(F inputs) throws Exception {
F forReturn = (F) inputs.getClass().newInstance();
inputs.stream().filter(removeNullsPredicate)
.collect(Collectors.toCollection(() -> forReturn));
return forReturn;
}
public F removeNulls3(F inputs) throws Exception {
Iterator<I> iter = inputs.iterator();
while (iter.hasNext()){
I next = iter.next();
boolean test = removeNullsPredicate.test(next);
if (!test){
iter.remove();
}
}
return inputs;
}
public F removeNulls4(F inputs) throws Exception {
List<I> forRemoval = inputs.stream().filter(removeNullsPredicate.negate())
.collect(Collectors.toList());
inputs.removeAll(forRemoval);
return inputs;
}
}