How to reuse application of filter & map on a Stream?

Viewed 2696

I have a set of domain objects that inherit from a shared type (i.e. GroupRecord extends Record, RequestRecord extends Record). The subtypes have specific properties (i.e. GroupRecord::getCumulativeTime, RequestRecord::getResponseTime).

Further, I have a list of records with mixed subtypes as a result of parsing a logfile.

List<Record> records = parseLog(...);

In order to compute statistics on the log records, I want to apply math functions only on a subset of the records that matches a specific subtype, i.e. only on GroupRecords. Therefore I want to have a filtered stream of specific subtypes. I know that I can apply a filter and map to a subtype using

records.stream()
       .filter(GroupRecord.class::isInstance)
       .map(GroupRecord.class::cast)
       .collect(...

Apply this filter&cast on the stream multiple times (especially when doing it for the same subtype multiple times for different computations) is not only cumbersome but produces lots of duplication.

My current approach is to use a TypeFilter

class TypeFilter<T>{

    private final Class<T> type;

    public TypeFilter(final Class<T> type) {
        this.type = type;
    }

    public Stream<T> filter(Stream<?> inStream) {
        return inStream.filter(type::isInstance).map(type::cast);
    }
}

To be applied to a stream:

TypeFilter<GroupRecord> groupFilter = new TypeFilter(GroupRecord.class); 

SomeStatsResult stats1 = groupFilter.filter(records.stream())
                                      .collect(...)
SomeStatsResult stats2 = groupFilter.filter(records.stream())
                                      .collect(...)

It works, but I find this approach a bit much for such a simple task. Therefore I wonder, is there a better or what is the best way for making this behavior reusable using streams and functions in a concise and readable way?

3 Answers
Related