2014-12-01 15 views
11

Supponiamo di avere classi di struttura come questa:Java 8 flussi di nidificate

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; 
} 

con Java 8 e Stream s vogliamo fare un filtro per idImage e tornare Review oggetti.
È possibile? Un livello è facile, ma su 2 livelli non possiamo trovare esempi o documentazione.

+1

La tua domanda non è chiara - si può mostrare un esempio di codice con un ingresso e l'uscita prevista? – assylias

risposta

12

Indovinate che cosa avete bisogno: (Assumiamo getter sono disponibili per Review e 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()); 
2

penso che si può ottenere il codice più mantenibile ed elegante qui da non provare per un one-liner. :)

Quando ho queste strutture nidificate, di solito io, , creo un nuovo metodo per ogni livello. In modo che quando sto codificando, devo solo avere un livello nella mia testa alla volta.

Provare a tirare la parte che controlla se esiste un'immagine con imageId in un Predicate.

Un Predicate ecco un Function che toglie il Review e restituisce un Boolean che può essere filtrata su.

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

Se il -Metodo filterReviews aveva preso la Predicate come parametro, è possibile utilizzare lo stesso metodo, a filtrare su tutti i campi diversi all'interno Review, passando diversi Predicates.

+0

Secondo me è molto meglio aggiungere un metodo 'hasImage' alla classe' Review' che restituisce semplicemente il vecchio 'boolean'. Quindi puoi '.filter (Review :: hasImage)'. Ciò incapsulerebbe anche l'archiviazione 'images'. Supponiamo che in seguito cambierai 'Lista images' in' Map id2image'. Quindi 'hasImage' sarà ridotto a' return id2image.containsKey (idImage); ' –

1

Ecco qualche idea di base:

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; 
    } 
} 
+0

Sebbene questo codice possa rispondere alla domanda, fornire un contesto aggiuntivo su come e/o perché risolve il problema migliorerebbe il valore a lungo termine della risposta. –

Problemi correlati