Search code examples
javafilterjava-streamdistinctinstanceof

How to filter out Distinct objects of a Particular subtype from a List of super type with Streams


I would like to create a Java stream that will collect only elements that are instanceof class A and at the same time are distinct by x.

I am using Java 8.

What I have in the beginning is a List of instances of class C.

Class A extends B{
   int x;
}

Class B extends C{

}

Class C(){

}

but other classes also extend class C.

What I did so far:

List<C> input = ...; 
List<C> result = input.stream()
    .filter(r -> r instanceof A)
    .collect(Collectors.toList());

And this works fine however for the first part.

However, I would like to compare all elements and get a List of distinct objects (compare by value of int x).


Solution

  • You can define a method that would expect an instance of target class Class<T> in order to filter out any subtype of C from the source list.

    Note that would work only if equals/hashCode contract was properly implemented by each subclass.

    public static <T extends C> List<T> getItemsOfType(List<C> source,
                                                       Class<T> itemClass) {
        return source.stream()
            .filter(item -> itemClass.isAssignableFrom(item.getClass())) // ensures that this element can be safely casted to the target type
            .map(itemClass::cast) // casting to the type T
            .distinct()           // ensures uniqueness of elements according to `equals/hashCode` implementation of the type T
            .collect(Collectors.toList());
    }
    
    public static void main(String[] args) {
        List<C> input = List.of(new A(1), new D(), new A(3));
        List<A> result = getItemsOfType(input, A.class);
    
        System.out.println(result);
    }
    

    Output:

    [A{x=1}, A{x=3}]