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 Streams 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