当前位置: 首页 > 知识库问答 >
问题:

如何在流上重用filter和map的应用?

邵宏达
2023-03-14

我有一组从共享类型继承的域对象(即grouprecord extends recordrequestrecord extends record)。子类型具有特定的属性(即GroupRecord::GetCumulativeTimeRequestRecord::GetResponseTime)。

此外,作为解析日志文件的结果,我有一个包含混合子类型的记录列表。

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

为了计算日志记录上的统计信息,我想只在匹配特定子类型的记录子集上应用数学函数,即只在grouprecords上应用数学函数。因此,我希望有一个特定子类型的过滤流。我知道可以使用以下方法将筛选映射应用到子类型

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

在流上多次应用这个filter&cast(特别是在对同一子类型进行多次不同计算时)不仅很麻烦,而且会产生大量重复。

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);
    }
}
TypeFilter<GroupRecord> groupFilter = new TypeFilter(GroupRecord.class); 

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

这是可行的,但我发现这种方法对于这样一个简单的任务来说有点太多了。因此,我想知道,有没有更好的方法,或者是什么是最好的方法,以简洁和可读的方式使用流和函数来使这种行为可重用?

共有1个答案

琴正初
2023-03-14

这要看你发现什么“更简洁、更可读”。我自己认为,你已经实现的方式是好的,因为它是。

但是,确实有一种方法可以做到这一点,即使用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(...);

这种方法有明显的权衡:

  • 您会丢失管道定义中的“filter”字。这可能比原来的更让人困惑,所以可能需要一个比onlytypes更好的名称。
  • stream对象相对重量级,创建如此多的对象可能会导致性能下降。但您不应该相信我的话,在重载下对这两个变体进行配置。
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对象。这也可能是一种过度抽象的情况,但这取决于您需要代码的地方和原因。

 类似资料:
  • ,和在Python 2中完美工作。这里有一个例子: 但是在Python 3中,我收到以下输出: 如果有人能向我解释这是为什么,我将不胜感激。 为进一步清晰起见,代码截图:

  • 我有以下代码: 有可能是。 有没有一种有效的方法可以避免出现NPE?

  • 对于Java流,有没有理由使用而不是和的组合? 例如使用: 或

  • 我有一个具有不同复杂性(进程持续时间)的txntype列表。 我想从列表中找到匹配的。 我试图通过混合流的并行处理和短路过滤功能来实现它。 但我注意到它们没有混合。 我编写了下面的示例。但注意到并行和短路的混合不能正常工作。 每次运行都显示并行处理在工作,但在找到项目时没有终止!!! 通过多次运行,我发现处理没有尽快终止,并等待处理所有这些!!!! 是否存在类似的内容?

  • 我从对象和对象数组中更改了一个对象两次,这样在第一次迭代中,我过滤掉了几个对象,在第二次迭代中,我使用map更改了每个过滤后的对象。我能用减速机或更好的吗?

  • 我有一个简单的流如下: 但Intellij建议我: “filter()”和“map()”可以互换。检查信息:报告流API调用链可以简化。它允许在遍历集合时避免创建冗余的临时对象。例如 collection.stream()→collection.for每个() collection.stream()。 Intellij给出的例子很容易理解,但我不明白为什么它建议我使用。 我查看了的来源,但没有找到