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 Fmay not have an empty constructor
- use of the forReturnobject is not thread safe (if run in parallel)
removeNulls3:
- modifies the original list
- is reinventing the wheel/not parallelisable (would prefer to use the filtermethod)
- Iterator.remove()can throw an- UnsupportedOperationException
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;
    }
}
 
     
    