Andrey
Andrey

Reputation: 45

Java 8 stream api key based merging

I've recently started to learn stream API. I am trying remove duplication from following piece of code. Is it possible use merge function based on Predicate or condition? (Also I was thinking about using partitioningBy or groupingBy from Collectors)

BinaryOperator<LocalDateTime> latestDate = (p, a) -> a.isAfter(p) ? a : p;
BinaryOperator<LocalDateTime> earliestDate = (p, a) -> a.isBefore(p) ? a : p;


         Map<Status,LocalDateTime> latest = history.stream()
                    .filter(isNewOrOpen.negate())
                    .collect(toMap(History::getStatus,
                            History::getChangedtetme,
                            latestDate));

        Map<Status,LocalDateTime> earliest = history.stream()
                    .filter(isNewOrOpen)
                    .collect(toMap(History::getStatus,
                            History::getChangedtetme,
                            earliestDate));

            latest.putAll(earliest);

Upvotes: 4

Views: 203

Answers (2)

Tagir Valeev
Tagir Valeev

Reputation: 100309

If I understand your problem correctly, isNewOrOpen predicate uses History.getStatus() and you want to select the history items with earliest date for new/open status and with latest date for other statuses. It's better to define the Comparator which implements this logic (it's supposed that h1 and h2 have the same status here):

Comparator<History> comparator = (h1, h2) -> isNewOrOpen.test(h1) ? 
    h2.getChangedtetme().compareTo(h1.getChangedtetme()):
    h1.getChangedtetme().compareTo(h2.getChangedtetme());

Using this comparator, it's quite easy to define the collector to solve your task:

Collector<History, ?, Map<Status, LocalDateTime>> collector
        = groupingBy(History::getStatus, 
                collectingAndThen(maxBy(comparator), 
                opt -> opt.get().getChangedtetme()));

Note the collectingAndThen usage: maxBy returns Optional<History> and we want to extract the getChangedtetme() (whatever it means).

So finally you can use this collector directly:

Map<Status, LocalDateTime> result = history.stream().collect(collector);

The latestDate and earliestDate seem to be unnecessary.

Upvotes: 2

marstran
marstran

Reputation: 28056

As you say, you can use Collectors.partitioningBy to do what you want.

BinaryOperator<LocalDateTime> latestDate = (p, a) -> a.isAfter(p) ? a : p;

Map<Boolean, Map<Status,LocalDateTime>> partitions = 
        history.stream()
               .collect(partitioningBy(isNewOrOpen,
                                       toMap(History::getStatus,
                                       History::getChangedtetme,
                                       latestDate));

Map<Status,LocalDateTime> latest = partitions.get(true);
Map<Status,LocalDateTime> earliest = partitions.get(false);

Upvotes: 2

Related Questions