public class Student {
String name;
int age;
}
I have a list of Student
objects and I need to group them according to specific logic:
So far I what I have done:
List<Student> students = List.of(
new Student("Alex", 31),
new Student("Peter", 33),
new Student("Antony", 32),
new Student("Pope", 40),
new Student("Michel", 30));
Function<Student, String> checkFunction = e -> {
if (e.getName().startsWith("A")) {
return "A-List";
} else if (e.getName().startsWith("P")) {
return "P-List";
} else if (e.getAge() >= 30) {
return "30's-List";
} else {
return "Exception-List";
}
};
Map<String, List<Student>> result = students.stream().collect(Collectors.groupingBy(checkFunction));
for (var entry : result.entrySet()) {
System.out.println(entry.getKey() + "---");
for (Student std : entry.getValue()) {
System.out.println(std.getName());
}
}
output
A-List---
Alex
Antony
P-List---
Peter
Pope
30's-List---
Michel
I understand this logic what I am following is wrong, that is why the 30's list is not populated correctly. Is it really possible with groupingBy()
?
This can be handled like in Java 8 group by String but you will have to adapt checkFunction
to actually return the groups of each Student
.
private Stream<String> mapToGroups(Student e) {
Builder<String> builder = Stream.builder();
boolean isException = false;
if (e.getName().startsWith("A")) {
builder.add("A-List");
} else if (e.getName().startsWith("P")) {
builder.add("P-List");
} else {
isException = true;
}
if (e.getAge() >= 30) {
builder.add("30's-List");
} else if (isException) {
builder.add("Exception-List");
}
return builder.build();
}
However, if we were to use this function in a flatMap()
call, we would loose the Student
in the process. So what we really want is having this method return String<Map.Entry<String, Student>>
so that we can later user the key for grouping and the value for collecting the groups:
private Stream<Entry<String, Student>> mapToGroupEntries(Student e) {
Builder<Entry<String, Student>> builder = Stream.builder();
boolean isException = false;
if (e.getName().startsWith("A")) {
builder.add(new SimpleEntry<>("A-List", e));
} else if (e.getName().startsWith("P")) {
builder.add(new SimpleEntry<>("P-List", e));
} else {
isException = true;
}
if (e.getAge() >= 30) {
builder.add(new SimpleEntry<>("30's-List", e));
} else if (isException) {
builder.add(new SimpleEntry<>("Exception-List", e));
}
return builder.build();
}
We can now use this function as part of a flatMap()
call to convert our Stream<Student>
to a Stream<Entry<String, Student>>
and then group them:
Map<String, List<Student>> result = students.stream()
.flatMap(s -> mapToGroupEntries(s))
.collect(Collectors.groupingBy(Entry::getKey,
Collectors.mapping(Entry::getValue, Collectors.toList())));