web-dev-qa-db-ja.com

ストリーム内のinstanceofを確認します

私は次の式を持っています:

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

...ここで、scheduleIntervalContainersの要素タイプはScheduleContainerです。

final List<ScheduleContainer> scheduleIntervalContainers

フィルターの前にタイプを確認することはできますか?

58
quma

filterインスタンスのみを保持するために別のScheduleIntervalContainerを適用できます。mapを追加すると、後のキャストが保存されます。

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

または、Holgerがコメントしたように、そのスタイルが必要な場合は、ラムダ式をメソッド参照に置き換えることができます。

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

非常にエレガントなオプションは、クラスのメソッド参照を使用することです:

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

@ Eran ソリューションに小さな問題があります-filtermapの両方にクラス名を入力するとエラーが発生しやすくなります-クラスの名前を変更するのを忘れがちです両方の場所で。改善されたソリューションは、次のようなものになります。

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 から学びました

12
Andrey