I am trying to understand Lambdas in Java 8.
Say I have a Person class that looks like this:
public class Person implements {
String name;
GenderEnum gender;
int age;
List<Person> children;
}
Now what I want to do is find all persons which are female, that have children that are younger than 10 years old.
Pre java 8 I would do it like this:
List<Person> allPersons = somePeople();
List<Person> allFemaleWithChildren = new ArrayList<>();
for(Person p : allPersons) {
for(Person child : p.getChildren()) {
if(child.getAge() < 10 && p.getGender() == GenderEnum.Female) {
allFemaleWithChildren.add(p);
}
}
}
Now allFemaleWithChildren should have what I want. I have been trying to do the same using streams I think I need to use some sort of map, filter and reduce
allPersons.stream()
//filter females
.filter(p -> p.getGender == GenderEnum.Female)
//get the children
.map(c -> c.getChildren())
//filter the ones that are less than 10 years
.filter(c -> c.getAge() < 10)
//return a list with the result
.collect(Collectors.toList())
But this code does not compile. What am I missing.
Also, I don't understand what the reduce method can be used for.
The compiler says
cannot resolve method getAge()
. This is because c
is apparently a collection and not the items in the collection, which is really what I want.
Lambda expressions are much like anonymous functions. Streams are sequences or elements that support sequential or parallel operations on their items (in a very different way from classic collections). Functional programming is a paradigm that favors stateless operations and avoids modifications to the program state.
Introduced in Java 8, the Stream API is used to process collections of objects. A stream is a sequence of objects that supports various methods which can be pipelined to produce the desired result. A stream is not a data structure instead it takes input from the Collections, Arrays or I/O channels.
A lambda in Java essentially consists of three parts: a parenthesized set of parameters, an arrow, and then a body, which can either be a single expression or a block of Java code. In the case of the example shown in Listing 2, run takes no parameters and returns void , so there are no parameters and no return value.
At the moment (once you fix the compilation error) you would be returning a list of Children. Assuming that in your original code you meant to break as soon as you find a children under 10, the equivalent could look like:
allPersons.stream()
//filter females
.filter(p -> p.getGender() == GenderEnum.Female)
//only keep females with at least one child < 10
.filter(f -> f.getChildren().stream()
.anyMatch(c -> c.getAge() < 10))
//return a list with the result
.collect(Collectors.toList())
And indeed as commented below, you could use a few static imports, add helper methods and refactor the original code to make it more readable:
allPersons.stream()
.filter(this::female)
.filter(this::hasChildrenUnder10)
.collect(toList())
//...
private boolean female(Person p) { return p.getGender() == Female; }
private boolean hasChildrenUnder10(Person parent) {
return parent.getChildren().stream()
.anyMatch(c -> c.getAge() < 10));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With