I've got the following classes:
public class Insurance {
...
}
public class Customer {
private List<Insurance> insurances;
public List<Insurance> getInsurances() {
return insurances;
}
...
}
public class CustomerRegistry {
private List<Customer> customers;
...
}
as well as this helper method, which reduces a List<Predicate<T>>
into a single Predicate<T>
:
public Predicate<T> reducePredicates(List<Predicate<T>> predicates) {
return predicates.stream()
.reduce(Predicate::and)
.orElse(p -> true);
}
What I want to do is get a list of insurances that match a list of filters, belonging to customers that match a list of filters. If this is unclear, the below code will hopefully clarify.
Method is inside CustomerRegistry
class above.
public List<Insurance> findInsurances(List<Predicate<Customer>> cusPredicates,
List<Predicate<Insurance>> insPredicates) {
List<Insurance> matches = new LinkedList<>();
customers.stream()
.filter(reducePredicates(cusPredicates)
.forEach(cus -> cus.getInsurances()
.stream()
.filter(reducePredicates(insPredicates))
.forEach(cus -> matches.add(cus)))
return matches;
}
Is there a way to do this without the matches
list? Can I perform some sort of reduction, so that the matching insurances are returned directly (i.e. not being added to a temporary collection like matches
)?
You can filter Java Collections like List, Set or Map in Java 8 by using the filter() method of the Stream class. You first need to obtain a stream from Collection by calling stream() method and then you can use the filter() method, which takes a Predicate as the only argument.
A filter stream is constructed on another stream (the underlying stream). The read method in a readable filter stream reads input from the underlying stream, filters it, and passes on the filtered data to the caller.
Java stream provides a method filter() to filter stream elements on the basis of given predicate. Suppose you want to get only even elements of your list then you can do this easily with the help of filter method. This method takes predicate as an argument and returns a stream of consisting of resulted elements.
If you have an ordered stream and perform operations which guarantee to maintain the order, it doesn't matter whether the stream is processed in parallel or sequential; the implementation will maintain the order.
Use flatMap():
customers.stream()
.filter(reducePredicates(cusPredicates))
.flatMap(cus -> cus.getInsurances().stream())
.filter(reducePredicates(insPredicates))
.collect(Collectors.toList())
Or better, to avoid reducing the predicates over and over again:
Predicate<Customer> customerPredicate = reducePredicates(cusPredicates);
Predicate<Customer> insurancePredicate = reducePredicates(insPredicates);
List<Insurance> =
customers.stream()
.filter(customerPredicate)
.flatMap(cus -> cus.getInsurances().stream())
.filter(insurancePredicate)
.collect(Collectors.toList())
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