Überprüfen Sie die Instanz im Stream


79

Ich habe folgenden Ausdruck:

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

... wo scheduleIntervalContainershat Elementtyp ScheduleContainer:

final List<ScheduleContainer> scheduleIntervalContainers

Ist es möglich, den Typ vor dem Filter zu überprüfen?

Antworten:


128

Sie können eine andere anwenden filter, um nur die ScheduleIntervalContainerInstanzen beizubehalten. mapWenn Sie eine hinzufügen, werden die späteren Besetzungen gespeichert:

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

Wie Holger kommentierte, können Sie die Lambda-Ausdrücke durch Methodenreferenzen ersetzen, wenn Sie diesen Stil bevorzugen:

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

121
Oder .filter(ScheduleIntervalContainer.class::isInstance) .map(ScheduleIntervalContainer.class::cast)welchen Stil Sie bevorzugen.
— Holger

Wenn in IDEA und Java8 das obige Snippet List <ScheduleContainer> ScheduleIntervalContainers zugewiesen ist, werde ich dennoch aufgefordert, das Ergebnis explizit in List <ScheduleContainer> ScheduleIntervalContainers umzuwandeln. Wissen Sie warum?
— K. Symbol

@ K.Symbol Hast du versucht, einem List<ScheduleContainer>oder einem zuzuweisen List<ScheduleIntervalContainer>? Es sollte das letztere sein.
— Eran

119

Eine ziemlich elegante Option ist die Verwendung der Methodenreferenz der Klasse:

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

Welchen Vorteil hat dieser Stil im Vergleich zur Verwendung von instanceof und (ScheduleIntervalContainer) zum Casting?
— MageWind

@MageWind das ist meistens eine Frage des Stils. Einige Leute bevorzugen es, weil Sie keinen anderen Variablennamen (für den Lambda-Parameter) einführen müssen, andere, weil er etwas weniger Bytecode generiert (nicht genug Unterschied, um wirklich relevant zu sein).
— Holger

Das ist wirklich cool! Aber warum ist das .classerforderlich? ist nicht isInstanceTeil von Object? Ist Classeine Klasse in Java?
— Post Self

@ PostSelf In der Tat ist und ScheduleIntervalContainerwäre es nicht wirklich eine Instanz.
— Naman

14

Es gibt ein kleines Problem mit der @ Eran- Lösung - die Eingabe des Klassennamens in beiden filterund mapist fehleranfällig - es ist leicht zu vergessen, den Namen der Klasse an beiden Stellen zu ändern. Eine verbesserte Lösung wäre ungefähr so:

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

Es kann jedoch zu Leistungseinbußen kommen, wenn Streamfür jedes übereinstimmende Element ein erstellt wird. Seien Sie vorsichtig, wenn Sie es für große Datenmengen verwenden. Ich habe diese Lösung von @ Tagir Vailev gelernt


Bei diesem Ansatz müssen Sie kümmern sich um Nullpointerexceptions nehmen, da select(A.class)kehrt nullfür alles , was nicht ist A. Hinzufügen .filter(Objects::nonNull)würde helfen. Übrigens: @ Erans Ansatz ist nullsicher.
— Lars Gendner

Entschuldigung, mein schlechtes ... JavaDoc von flatMapsagt "Wenn ein zugeordneter Stream null ist, wird stattdessen ein leerer Stream verwendet.". Ihre Lösung war also auch ohne den Nullfilter korrekt.
— Lars Gendner

3
Trotzdem (IMO) seltsam zurückzukehren, nullwenn Sie gerade einen leeren Stream hätten zurückgeben können
— Alowaniak
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.