[java] 스트림에서 instanceof 확인

다음식이 있습니다.

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

scheduleIntervalContainers요소 유형이 있는 위치 ScheduleContainer:

final List<ScheduleContainer> scheduleIntervalContainers

필터 전에 타입을 확인할 수 있습니까?



답변

인스턴스 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());


답변

매우 우아한 옵션은 클래스의 메서드 참조를 사용하는 것입니다.

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


답변

@ 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 에서이 솔루션을 배웠습니다.


답변