Home > OS >  How to replace iter loops by stream
How to replace iter loops by stream

Time:09-04

I am tryning to replace that code using stream.

public int countPenaltyPointsTest(Set<OffenceEntity> offences, LocalDate date) {
    int sum = 0;
    for (OffenceEntity offence : offences) {
        for (OffenceDetailsEntity offenceDetailsEntity : offence.getDetails()) {
            if (date.isAfter(offenceDetailsEntity.getStartDate())
                    && date.isBefore(offenceDetailsEntity.getEndDate())) {
                sum  =offenceDetailsEntity.getPenaltyPoints();
            }
        }
    }

I have OffenceEntity with OneToMany relationsh with OffenceDetailsEntity:

@Entity
public class OffenceEntity {
    ...
    private Set<OffenceDetailsEntity> details;
}


@Entity
public class OffenceDetailsEntity {
    ...
    private int penaltyPoints;
    private LocalDate startDate;
    private LocalDate endDate;
    @ManyToOne
    @JoinColumn(referencedColumnName = "id")
    private OffenceEntity offence;
}

and I would like to collect penalty points where date is between two dates. I know how to do it for example when I have field like penalty points in OffenceEntity. Example:

int sum = offences.stream()
            .mapToInt(OffenceEntity::getPenaltyPoints)
            .sum();

but I do not know how to "jump" to the set in OffenceEntity

CodePudding user response:

You need flatMap() operation (or its flavor flatMapToInt()) to flatten the data that corresponds to each OffenceEntity object.

public int countPenaltyPointsTest(Set<OffenceEntity> offences, LocalDate date) {
    
    return offences.stream()
        .flatMap(offence -> offence.getDetails().stream())
        .filter(ode -> date.isAfter(ode.getStartDate())
                        && date.isBefore(ode.getEndDate()))
        .mapToInt(OffenceDetailsEntity::getPenaltyPoints)
        .sum();
}

Since Java 16 we can also use mapMulty() operation for one-to-many transformations. This operation allows incorporating imperative programming features (i.e. loops and conditional statements) into the stream pipeline.

Here's how we can implement this method using mapMultyToInt():

public int countPenaltyPointsTest(Set<OffenceEntity> offences, LocalDate date) {
    
    return offences.stream()
        .mapMultiToInt((offence, consumer) -> 
            offence.getDetails().forEach(ode -> {
                if (date.isAfter(ode.getStartDate()) && date.isBefore(ode.getEndDate()))
                    consumer.accept(ode.getPenaltyPoints());
        }))
        .sum();
}

For more information on mapMulty() operation, have a look at this question.

  • Related