TrailRunningReview
TrailRunningReview

Reputation: 201

java 8 nested streams

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.

Upvotes: 20

Views: 41722

Answers (4)

Sagar
Sagar

Reputation: 175

The requirement says you want to filter based on idImage which is the field in our stream of list ArrayList images
Step1:

images.stream()
    .filter(idImage->idImage.equals("I123");

Our aim will be satisfied if any match is found so

Step2:

images.stream()
        .filter(idImage->idImage.equals("I123")
        .findAny()//this will return Optional<RelReviewImage> object which will be populated if object is found also need not worry about null condition
        .isPresent()//this will check if the Optional<RelReviewImage> object was populated

But from where do we get this images stream? It is present in Review class so one can directly say Step 3

Review myReview-new Review();
            myReview.getImages.stream()
                            .filter(idImage->idImage.equals("I123")
                            .findAny()
                            .isPresent()

But we want to have all listOfReviewObjects Assuming we have ListOfReviewObjects

//Ignore below line of code if not clear,bottomLine is you get list of review objects
            List<Review> reviews = IntStream.rangeClosed(0, 10).mapToObj(e->new Review()).collect(Collectors.toList());

Step 4

reviews.stream()
            .filter("XYZ condition")
            .collect(Collectors.toList());

Our filter criteria is as per step 2 so collating each piece we have

Step 5

reviews.stream()
        .filter(review->review.getImages().stream()
                                            .filter(relReviewImage->relReviewImage.getIdImage().intValue()==imageId)
                                            .findAny()
                                            .isPresent())
        .collect(Collectors.toList());

Upvotes: -1

falin
falin

Reputation: 7

Here is some basic Idea:

public static void main(String[] args) {
    // TODO Auto-generated method stub

    List<Review> reviews = new ArrayList<>();
    for(int i = 0; i < 50; i++) {
        List<RelReviewImage> revImg = new ArrayList<>();
        for(int j = 0; j < 5; j++) {
            revImg.add(new RelReviewImage(j, j, "img_"+j));
        }
        reviews.add(new Review(i, "rev" + i, revImg));
    }

    List<Review> result = reviews.stream().filter(r -> r.getImages().stream().anyMatch(i -> i.getIdImage().intValue() < 2)).collect(Collectors.toList());

}

public class Review {
    private Integer idReview;
    private String description;
    private List<RelReviewImage> images;

    public Review(Integer id, String desc, List<RelReviewImage> img) {
        super();
        this.idReview = id;
        this.description = desc;
        this.images = img;
    }

    public Integer getIdReview() {
        return idReview;
    }

    public void setIdReview(Integer idReview) {
        this.idReview = idReview;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public List<RelReviewImage> getImages() {
        return images;
    }

    public void setImages(List<RelReviewImage> images) {
        this.images = images;
    }
}

public class RelReviewImage {
    private Integer idRelReviewImage;
    private Integer idImage;
    private String name;

    public RelReviewImage(Integer id, Integer id_img, String name) {
        super();
        this.idRelReviewImage = id;
        this.idImage = id_img;
        this.name = name;
    }

    public Integer getIdRelReviewImage() {
        return idRelReviewImage;
    }

    public void setIdRelReviewImage(Integer idRelReviewImage) {
        this.idRelReviewImage = idRelReviewImage;
    }

    public Integer getIdImage() {
        return idImage;
    }

    public void setIdImage(Integer idImage) {
        this.idImage = idImage;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Upvotes: -1

tomaj
tomaj

Reputation: 1590

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.

Upvotes: 9

卢声远 Shengyuan Lu
卢声远 Shengyuan Lu

Reputation: 32004

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());

Upvotes: 23

Related Questions