Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a Set from a list of objects using Java Streams

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());
like image 347
SyncMaster Avatar asked Dec 18 '22 19:12

SyncMaster


2 Answers

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>
like image 198
Eran Avatar answered Feb 22 '23 23:02

Eran


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

like image 44
ETO Avatar answered Feb 23 '23 01:02

ETO