Suppose you have structure classes like this:
public class Review{
private Integer idReview;
private String description;
private ArrayList<RelReviewImage> images;
}
public class RelReviewImage{
private Integer idRelReviewImage;
private Integer idImage;
private String name;
}
With Java 8 and Stream
s we want to do a filter for idImage
and return Review
objects.
Is it possible? One level is easy, but 2 levels we can't find any example or documentation.
Guess what you need: (Assume getters are available for Review
and RelReviewImage
)
List<Review> originalReviews = ...
List<Review> result = originalReviews.stream()
.filter(review -> review.getImages().stream() //Nested streams. Assume getImages() never null, but empty
.anyMatch(image -> image.getIdImage() == 123)) //'2 level' here
.collect(Collectors.toList());
I think you can get the most maintainable and elegant code here by not trying for a one-liner. :)
When I have these nested structures, I usually create a new method for each level. So that when I'm coding, I only have to have one level in my head at a time.
Try pulling the part that checks if there exists an image with imageId
into a Predicate
.
A Predicate
here is a Function
that takes your Review
and returns a Boolean
that can be filtered on.
public List<Review> filterReviews(){
Integer idImage = 1;
List<Review> reviews = new ArrayList<>();
...
List<Review> result = reviews.stream()
.filter(hasImage(idImage))
.collect(Collectors.toList());
return result;
}
private Predicate<Review> hasImage(final Integer idImage){
return review -> review.images.stream()
.anyMatch(image -> Objects.equals(image.idImage, idImage));
}
Protip
If the filterReviews
-method had taken the Predicate
as a parameter, you can use the same method, to filter on all different fields inside Review
, by passing different Predicates
.
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