Reputation: 9966
This might be a simple Java streams question. Say, I have a List<Student>
object.
public class Student {
public String name;
public Set<String> subjects;
public Set<String> getSubjects() {
return subjects;
}
}
How can I get all the subjects taken by the list of students?
I can do this using a for each loop. How can I convert the below code to use Streams?
for (Student student : students) {
subjectsTaken.addAll(student.getSubjects());
}
Here is my attempt at using Java 8 streams. This gives me an Incompatible types
error.
Set<String> subjectsTaken = students.stream()
.map(student -> student.getSubjects())
.collect(Collectors.toSet());
Upvotes: 5
Views: 5642
Reputation: 398
A different alternative using Stream<T>#<R>collect
:
students.stream()
.map(Student::getSubjects)
.<Set<String>>collect(HashSet::new, Collection::addAll, Collection::addAll)
Upvotes: 1
Reputation: 7299
Try this:
Set<String> subjectsTaken =
students.stream()
.map(Student::getSubjects)
.flatMap(Set::stream)
.collect(Collectors.toSet());
The idea is to map the students to their subjects first, then flatten the Stream<Set<String>>
to Stream<String>
and finally collect the stream to a Set
.
I would suggest you to use method references instead of lambda expressions where it's possible (if it doesn't degrade readability).
Upvotes: 5
Reputation: 394136
Your current code produces a Set<Set<String>>
, not a Set<String>
.
You should use flatMap
, not map
:
Set<String> subjectsTaken =
students.stream() // Stream<Student>
.flatMap(student -> student.getSubjects().stream()) // Stream<String>
.collect(Collectors.toSet()); // Set<String>
Upvotes: 6