Reputation: 63
I have a method for a filter by type, it gets as input Collection<?> collection
and Class<T> tClass
. I want to replace FluentIterable
by the Stream
.
public static <T> List<T> filterByType(final Collection<?> filerCollection, final Class<T> classType)
{
return FluentIterable.from(filerCollection).filter(classType).toList();
}
I tried with this solution:
public static <T> List<T> typeFilter(final Collection<?> filter, final Class<T> classType) {
return (List<T>) filter.stream()
.filter(Objects::nonNull)
.map(Object.class::cast)
.collect(Collectors.toList());
}
how to do that without casting the return Stream
?
Upvotes: 2
Views: 1490
Reputation: 110036
Another thing you can do (though it's probably a bit less efficient than doing it in two steps) is to define something like this:
public static <T> Function<Object, Stream<T>> instancesOf(Class<T> c) {
return o -> c.isInstance(o) ? Stream.of(c.cast(o)) : Stream.empty();
}
and then use it like this:
return filter.stream()
.flatMap(instancesOf(classType))
.collect(toList());
Upvotes: 0
Reputation: 19926
You forgot to check if your elements are even of type T
. I.e. you have to filter those elements out first:
return filter.stream()
.filter(classType::isInstance) // only keep elements of type T
.map(classType::cast) // safely cast from Object to T
.collect(Collectors.toList()); // collect into a List<T>
Class#isInstance()
also directly takes care of null
values, so you don't have to use filter(Object::nonNull)
.
Upvotes: 4
Reputation: 44368
Look carefully what FluentIterable::filter(Class<T>)
does and compare it with maps each item to the classType
with casting. Your intention is to filter those items of classType
.
Next, the classType::cast
should be used instead of Object.class::cast
since the desired class is already passed through Class<T> classType
and might be used directly as a method reference. The Object.class::cast
casts to a parent Object
which every object inherits from.
Here is what you want:
public static <T> List<T> typeFilter(final Collection<?> filter, final Class<T> classType) {
return filter.stream()
.filter(Objects::nonNull)
.filter(item -> item.getClass().equals(classType))
.map(classType::cast)
.collect(Collectors.toList());
}
Edit: As mentioned in another answer, the filter(classType::isInstance)
might be used as well.
Upvotes: 1
Reputation: 21965
You should use classType::cast
because here you're using Object.class::cast
which basically does nothing
public static <T> List<T> typeFilter(final Collection<?> filter, final Class<T> classType) {
return filter.stream()
.filter(Objects::nonNull)
.map(classType::cast)
.collect(Collectors.toList());
}
And to be even better, add a filter(classType::isInstance)
to your method chaining
Upvotes: 1