【发布时间】:2017-05-29 12:07:01
【问题描述】:
我有一组继承自共享类型(即GroupRecord extends Record、RequestRecord extends Record)的域对象。子类型具有特定属性(即GroupRecord::getCumulativeTime、RequestRecord::getResponseTime)。
此外,由于解析日志文件,我有一个包含混合子类型的记录列表。
List<Record> records = parseLog(...);
为了计算日志记录的统计信息,我想仅对匹配特定子类型的记录子集应用数学函数,即仅在 GroupRecords 上。因此,我想要过滤特定子类型的流。我知道我可以将filter 和map 应用于子类型
records.stream()
.filter(GroupRecord.class::isInstance)
.map(GroupRecord.class::cast)
.collect(...
多次在流上应用此过滤器和强制转换(尤其是在为不同的计算多次为同一子类型执行此操作时)不仅麻烦而且会产生大量重复。
我目前的方法是使用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);
}
}
应用于流:
TypeFilter<GroupRecord> groupFilter = new TypeFilter(GroupRecord.class);
SomeStatsResult stats1 = groupFilter.filter(records.stream())
.collect(...)
SomeStatsResult stats2 = groupFilter.filter(records.stream())
.collect(...)
它有效,但我发现这种方法对于这样一个简单的任务来说有点过分。因此,我想知道,是否有更好的或最好的方法来以简洁易读的方式使用流和函数使这种行为可重用?
【问题讨论】:
-
你能对这些条目进行分组吗?
records.stream().collect(Collectors.groupingBy(Record::getClass));然后简单地为您感兴趣的课程做一个 get ? -
@Eugene,如果目标不是多次迭代记录,那么将过滤后的对象收集到中间列表中然后处理两次确实比将所有内容收集到地图中并仅使用其中一个要好得多条目。此外,按类分组并不能保证类型安全,您仍然需要手动转换。
-
所以你正在过滤然后在整个数据集上投射许多类型以计算不同的统计数据。我不认为这是最好的方法。相反,您应该能够一次计算所有统计数据。此外,如果您还需要计算
Record的其他子类型的多个(其他)统计信息,您应该仍然可以一次完成所有操作。唯一不同的是,每组统计数据都需要在整个数据集的不同子集上进行计算。无论您的具体用例是什么,我认为您都需要一个自定义收集器。
标签: java java-8 java-stream