2017-07-20 7 views
6

Ich habe eine Sammlung, die ein Feld vom Typ Set mit einigen Werten hat. Ich muss ein neues Set erstellen, das all diese Werte sammelt.Sammeln Sie alle Werte eines Feldes Set

Ich frage mich, ob dies mit Lambda-Ausdrücke möglich ist.

Unten ist der Code Zeile:

Set<String> teacherId = batches.stream() 
           .filter(b -> !CollectionUtils.isEmpty(b.getTeacherIds())) 
           .map(b -> b.getTeacherIds()) 
           .collect(Collectors.toSet()); 

Das Problem ist Postkarten Betrieb, es enthält eine Sammlung von Satz Saiten. So sammeln Operation gibt eine Set<Set<String>> zurück, aber ich freue mich, alle Werte zu einem einzigen Satz zu aggregieren.

Antwort

7

Sie müssen flatMap verwenden statt map:

Set<String> teacherIds = 
    batches.stream() 
      .flatMap(b -> b.getTeacherIds().stream()) 
      .collect(Collectors.toSet()); 

Beachten Sie, dass Die Filterung ist für leere Sammlungen redundant - das Streaming einer leeren Sammlung führt nur zu einem leeren Stream, der das Endergebnis nicht beeinflusst. Wenn getTeacherIds()null zurückgeben könnte, müssten Sie dennoch damit umgehen. Mit filter(Objects::nonNull) würde ausreichen, und sparen Sie die Abhängigkeit von Apache Commons.

+1

Was ist, wenn die b.getTeacherIds eine Null ist? –

+1

@BiscuitCoder arg, guter Punkt - Streams behandeln Nullen nicht gut. Ich werde das bearbeiten. – Mureinik

+1

@Mureinik 'Filter (Objects :: nonNull)' wäre nicht genug. Sie würden 'stream' in' flatMap' auf einer Nullreferenz aufrufen ... – Eugene

2

Sie können flatMap verwenden, um eine flache Stream aller Werte zu erhalten, und dann sammeln zu einem Set<String>:

Set<String> teacherId = 
    batches.stream() 
      .filter(b -> !CollectionUtils.isEmpty(b.getTeacherIds())) 
      .flatMap(b -> b.getTeacherIds().stream()) 
      .collect(Collectors.toSet()); 
+2

Ich würde die Gelegenheit nutzen, um diese fragwürdige Utility-Methode loszuwerden. Wenn der Umgang mit dem Potential 'null' gewünscht wird, sollte dies explizit gemacht werden, '.filter (b -> b.getTeacherIds()! = Null)', leere Listen werden bereits von 'flatMap' behandelt. – Holger

+0

@Holger Ich habe die CollectionUtils.isEmpty in der Frage an erster Stelle eingeführt. Aber ich verstehe, dass es irrelevant ist, einen leeren Scheck zu hinterlegen, und eine bloße Nullkontrolle wäre ausreichend gewesen. –

2

Wenn Sie darauf achten, dass getTeacherIds() nicht null ist, verwenden Sie explizit über !=, dass CollectionUtils.isEmpty nur Zeug versteckt. Zumal wenn getTeacherIds() eine Empty-Collection zurückgibt - das wird von flatMap einwandfrei behandelt, so ist das für mich überhaupt nicht nötig.

Set<String> teacherIds = batches 
      .stream() 
      .filter(x -> x.getTeacherIds() != null) 
      .flatMap(x -> x.getTeacherIds().stream()) 
      .collect(Collectors.toSet()); 
1

Ich frage mich, ob diese Lambda-Ausdrücke möglich ist, verwenden.

Ich fange den letzten Fisch, :).

Set<String> teacherIds = batches.stream()//v--- the class of `x` 
           .map(XClass::getTeacherIds) 
           .filter(Objects::nonNull) 
           .flatMap(Collection::stream) 
           .collect(Collectors.toSet()); 

Hinweis: Es tut mir leid ich vergessen, Ihnen zu sagen, ob die getTeacherIds die internen IDs zu einem neuen Satz von IDs zu kopieren, über der Code ist für Sie geeignet. seit es gelesen wird die IDs von XClass einmal.

+0

Wenn man bedenkt, dass getTeacherIds null zurückgeben kann, behandelt map die NPE? –

+0

So Map-Funktion iteriert über jedes Element, sammelt, was getTeacherIds für jedes Element zurückgibt und komponiert einen Stream von getTeacherIds Ergebnissen. Von da an ist es unkompliziert.Verstehe ich das richtig ? –

+0

@BiscuitCoder ja, du hast Recht. 'map' wirft NPE nicht, NPE erscheint in' flatMap'. –

Verwandte Themen