Java 检查流中的实例
我有以下的表达:Java 检查流中的实例,java,java-8,java-stream,instanceof,Java,Java 8,Java Stream,Instanceof,我有以下的表达: scheduleIntervalContainers.stream() .filter(sic -> ((ScheduleIntervalContainer) sic).getStartTime() != ((ScheduleIntervalContainer)sic).getEndTime()) .collect(Collectors.toList()); …其中,scheduleIntervalContainers具有元素类型Sche
scheduleIntervalContainers.stream()
.filter(sic -> ((ScheduleIntervalContainer) sic).getStartTime() != ((ScheduleIntervalContainer)sic).getEndTime())
.collect(Collectors.toList());
…其中,scheduleIntervalContainers
具有元素类型ScheduleContainer
:
final List<ScheduleContainer> scheduleIntervalContainers
最终列表scheduleIntervalContainers
是否可以在筛选之前检查类型?您可以应用另一个
筛选
,以便仅保留ScheduleIntervalContainer
实例,添加映射将保存以后的强制转换:
scheduleIntervalContainers.stream()
.filter(sc -> sc instanceof ScheduleIntervalContainer)
.map (sc -> (ScheduleIntervalContainer) sc)
.filter(sic -> sic.getStartTime() != sic.getEndTime())
.collect(Collectors.toList());
或者,正如Holger所评论的,如果您喜欢lambda表达式的样式,可以使用方法引用替换该表达式:
scheduleIntervalContainers.stream()
.filter(ScheduleIntervalContainer.class::isInstance)
.map (ScheduleIntervalContainer.class::cast)
.filter(sic -> sic.getStartTime() != sic.getEndTime())
.collect(Collectors.toList());
一个非常优雅的选择是使用类的方法引用:
scheduleIntervalContainers
.stream()
.filter( ScheduleIntervalContainer.class::isInstance )
.map( ScheduleIntervalContainer.class::cast )
.filter( sic -> sic.getStartTime() != sic.getEndTime())
.collect(Collectors.toList() );
@solution有一个小问题-在filter
和map
中键入类名容易出错-很容易忘记在这两个位置更改类名。改进的解决方案如下所示:
private static <T, R> Function<T, Stream<R>> select(Class<R> clazz) {
return e -> clazz.isInstance(e) ? Stream.of(clazz.cast(e)) : null;
}
scheduleIntervalContainers
.stream()
.flatMap(select(ScheduleIntervalContainer.class))
.filter( sic -> sic.getStartTime() != sic.getEndTime())
.collect(Collectors.toList());
private静态函数选择(类clazz){
返回e->clazz.isInstance(e)?(clazz.cast(e))流:空;
}
调度间隔容器
.stream()
.flatMap(选择(ScheduleIntervalContainer.class))
.filter(sic->sic.getStartTime()!=sic.getEndTime())
.collect(Collectors.toList());
但是,为每个匹配元素创建流
时可能会有性能损失。小心在庞大的数据集上使用它。我从@或.filter(ScheduleIntervalContainer.class::isInstance).map(ScheduleIntervalContainer.class::cast)
中学习了这个解决方案,无论您喜欢什么样式。在IDEA和Java8中,如果将上述代码段分配给列出scheduleIntervalContainers,它仍然提示我显式地将结果强制转换为列表scheduleIntervalContainers,您知道为什么吗?@K.Symbol您是否尝试分配给列表
或列表
?应该是后者。与使用instanceof和(ScheduleIntervalContainer)来强制转换相比,这种样式有什么好处?@MageWind这主要是样式问题。有些人喜欢它,因为您不必引入另一个变量名(用于lambda参数),其他人则喜欢它,因为它生成的字节码稍微少一些(虽然差异不足以真正相关)。这真是太酷了!但是为什么需要.class
?isInstance
不是对象的一部分吗?Class
是Java中的一个类吗?@PostSelf确实是,而且ScheduleIntervalContainer
不会是一个实例。在这种方法中,您必须注意NullPointerException,因为select(a.Class)
对于任何不是a
的内容都将返回null
。添加.filter(Objects::nonNull)
会有所帮助。顺便说一句:@Eran的方法是空安全的。对不起,我的错。。。flatMap的JavaDoc说“如果映射流为空,则使用空流。”。因此,即使没有null-filter,您的解决方案也是正确的。仍然(IMO)奇怪地返回null
,而您本可以返回一个空流