Ü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.