检查流中的instanceof


79

我有以下表达:

scheduleIntervalContainers.stream()
        .filter(sic -> ((ScheduleIntervalContainer) sic).getStartTime() != ((ScheduleIntervalContainer)sic).getEndTime())
        .collect(Collectors.toList());

...其中scheduleIntervalContainers元素类型为ScheduleContainer

final List<ScheduleContainer> scheduleIntervalContainers

是否可以在过滤器之前检查类型?

Answers:


128

您可以应用另一个filter命令以仅保留ScheduleIntervalContainer实例,添加amap将为您节省以后的转换:

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());

121
或者.filter(ScheduleIntervalContainer.class::isInstance) .map(ScheduleIntervalContainer.class::cast),无论您喜欢哪种样式。
霍尔格

在IDEA和Java8中,如果将以上代码段分配给List <ScheduleContainer> scheduleIntervalContainers,它仍然提示我将结果显式转换为List <ScheduleContainer> scheduleIntervalContainers,您知道为什么吗?
K. Symbol

@ K.Symbol您是否尝试分配给aList<ScheduleContainer>或a List<ScheduleIntervalContainer>?应该是后者。
伊兰

119

一个不错的选择是使用类的方法引用:

scheduleIntervalContainers
  .stream()
  .filter( ScheduleIntervalContainer.class::isInstance )
  .map( ScheduleIntervalContainer.class::cast )
  .filter( sic -> sic.getStartTime() != sic.getEndTime())
  .collect(Collectors.toList() );

与使用instanceof和(ScheduleIntervalContainer)进行铸造相比,此样式有什么好处?
MageWind

@MageWind主要是风格问题。有些人喜欢它,因为您不必引入另一个变量名(用于lambda参数),而另一些人则喜欢,因为它生成的字节码略少(尽管差别不大,但实际上没有关系)。
Holger

这真是太酷了!但是为什么.class需要?不是isInstance的一部分Object?是ClassJava类吗?
发布自我

@PostSelf确实,它确实是,ScheduleIntervalContainer也不会真的是一个实例。
纳曼

14

@ Eran解决方案存在一个小问题-在两个位置都输入类名,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());   

但是,Stream为每个匹配的元素创建一个可能会降低性能。小心在庞大的数据集上使用它。我已经从@ Tagir Vailev学习了此解决方案


在这种方法中,您必须注意NullPointerExceptions,因为select(A.class)它将返回非null的任何内容A。添加.filter(Objects::nonNull)会有所帮助。顺便说一句:@Eran的方法是空安全的。
拉尔斯·根德纳

抱歉,我的问题……JavaDoc flatMap说:“如果映射流为null,则使用空流。” 因此,即使没有null过滤器,您的解决方案也是正确的。
拉尔斯·根德纳

3
null当您刚返回空流时,IMO(IMO)仍然很奇怪地返回
Alowaniak
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.