You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 8 Stream获取最新且去重的事件实现方案问询

Solution for Getting Latest Deduplicated Events with Java 8 Stream

Alright, let's tackle this problem: we need to process a collection of Event objects, and for every combination of product ID, event type, and calendar day, we only keep the most recent event (even if there are dozens of the same event type for the same product in a single day).

Step 1: Polish the Event Class

First, let's complete the hashCode method (your original code was cut off) and add necessary getters—we'll need these to access fields in the stream:

import java.util.Date;
import java.util.Objects;

public class Event {
    private Date eventDate;
    private EventType eventType;
    private Long productId;

    // Constructor for easy object creation
    public Event(Date eventDate, EventType eventType, Long productId) {
        this.eventDate = eventDate;
        this.eventType = eventType;
        this.productId = productId;
    }

    // Getters to access private fields in stream operations
    public Date getEventDate() { return eventDate; }
    public EventType getEventType() { return eventType; }
    public Long getProductId() { return productId; }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Event that = (Event) o;
        return Objects.equals(eventDate, that.eventDate) &&
               eventType == that.eventType &&
               Objects.equals(productId, that.productId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(eventDate, eventType, productId);
    }
}

// Assume EventType is an enum (adjust values to match your use case)
enum EventType {
    KICK, PASS, CATCH
}

Step 2: Stream Implementation with Custom Grouping

The core logic is to group events by product ID + event type + calendar day, then pull the latest event from each group. Since Java 8 doesn't have a built-in triple type, we'll make a custom grouping key class for better readability:

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Collection;
import java.util.Comparator;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

public class EventProcessor {

    // Custom key to group events by product, type, and calendar day
    private static class EventGroupKey {
        private final Long productId;
        private final EventType eventType;
        private final LocalDate eventDay;

        public EventGroupKey(Long productId, EventType eventType, LocalDate eventDay) {
            this.productId = productId;
            this.eventType = eventType;
            this.eventDay = eventDay;
        }

        // Required for proper grouping: override equals and hashCode
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            EventGroupKey that = (EventGroupKey) o;
            return Objects.equals(productId, that.productId) &&
                   eventType == that.eventType &&
                   Objects.equals(eventDay, that.eventDay);
        }

        @Override
        public int hashCode() {
            return Objects.hash(productId, eventType, eventDay);
        }
    }

    public Collection<Event> getLatestUniqueEvents(Collection<Event> events) {
        return events.stream()
                // Filter out invalid events to avoid null pointer exceptions
                .filter(event -> Objects.nonNull(event.getEventDate())
                        && Objects.nonNull(event.getProductId())
                        && Objects.nonNull(event.getEventType()))
                // Group events by our custom key (product + type + day)
                .collect(Collectors.groupingBy(
                        event -> {
                            // Convert Date to LocalDate to group by calendar day (ignore time)
                            LocalDate eventDay = event.getEventDate().toInstant()
                                    .atZone(ZoneId.systemDefault()) // Use ZoneId.of("UTC") for global consistency
                                    .toLocalDate();
                            return new EventGroupKey(event.getProductId(), event.getEventType(), eventDay);
                        },
                        // For each group, grab the event with the latest timestamp
                        Collectors.maxBy(Comparator.comparing(Event::getEventDate))
                ))
                // Extract the latest event from each group (handle Optional wrapper)
                .values().stream()
                .filter(Optional::isPresent)
                .map(Optional::get)
                .collect(Collectors.toList());
    }
}

Key Details to Note

  • Filtering: We first remove events with null critical fields to prevent crashes during stream processing.
  • Grouping Logic: The EventGroupKey ensures that all events for the same product, same event type, and same day are clustered together. Converting Date to LocalDate lets us ignore hours/minutes/seconds and group strictly by calendar day.
  • Fetching the Latest Event: Collectors.maxBy uses a comparator based on eventDate to pick the most recent event in each group. Since maxBy returns an Optional, we filter out empty values and extract the actual event.
  • Timezone Adjustment: If your app uses UTC time instead of the system default, replace ZoneId.systemDefault() with ZoneId.of("UTC") to ensure consistent day grouping across different servers.

内容的提问来源于stack exchange,提问作者michealAtmi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:11:43