这取决于您认为什么“更简洁和可读”。我本人认为您已经实施的方式就很好。
然而,确实有一种方法可以从使用它的地方稍微缩短一点,通过使用Stream.flatMap
:
static <E, T> Function<E, Stream<T>> onlyTypes(Class<T> cls) {
return el -> cls.isInstance(el) ? Stream.of((T) el) : Stream.empty();
}
它所做的是将每个原始流元素转换为Stream
一个元素(如果该元素具有预期类型),或者为空Stream
如果没有。
其用途是:
records.stream()
.flatMap(onlyTypes(GroupRecord.class))
.forEach(...);
这种方法有明显的权衡:
- 您确实从管道定义中丢失了“过滤器”一词。这可能比原来的更令人困惑,所以也许是一个比原来更好的名字
onlyTypes
是需要的。
-
Stream
对象相对重量级,创建太多对象可能会导致性能下降。但您不应该相信我在这里所说的话并在重负载下分析这两种变体。
Edit:
由于问题询问的是重用filter
and map
更笼统地说,我觉得这个答案还可以讨论更多的抽象。因此,要重用一般意义上的过滤器和映射,您需要以下内容:
static <E, R> Function<E, Stream<R>> filterAndMap(Predicate<? super E> filter, Function<? super E, R> mapper) {
return e -> filter.test(e) ? Stream.of(mapper.apply(e)) : Stream.empty();
}
和原创的onlyTypes
实施现在变成:
static <E, R> Function<E, Stream<R>> onlyTypes(Class<T> cls) {
return filterAndMap(cls::isInstance, cls::cast);
}
但是,再次需要权衡:生成的平面映射器函数现在将保存捕获的两个对象(谓词和映射器),而不是单个对象Class
上述实现中的对象。这也可能是过度抽象的情况,但这取决于您需要该代码的位置和原因。