流中的Java 8个不同元素

时间:2018-02-01 15:11:58

标签: java java-8

我希望有最新的和不同的事件。因此,如果事件发生在一天10次产品“球”,并且是“踢”类型的事件比我只需要最新的事件,当有人踢球。

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

    @Override 
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;

        Event that = (Event) o;

        if (eventDate != null ? !eventDate.equals(that.eventDate) : that.eventDate != null)
            return false;
        if (eventType != that.eventType)
            return false;
        return productId != null ? productId.equals(that.productId) : that.productId == null;
    }

    @Override 
    public int hashCode() {
        int result = eventDate != null ? eventDate.hashCode() : 0;
        result = 31 * result + (eventType != null ? eventType.hashCode() : 0);
        result = 31 * result + (productId != null ? productId.hashCode() : 0);
        return result;
    }
}

List<Event> events = 
    actions.getEvent(requestedEvents)
           .stream()
           .map(event -> new Event(event))
           .distinct()
           .sorted(Comparator.comparing(Event::getEventDate))
           .collect(Collectors.toList());

这不起作用:(它获得了不同的事件,但它仍然返回多种事件(eventType + productId),我想每对只有最新的一个eventType和productId。

我想在没有覆盖equals和hashcode的情况下这样做,但它会更难。

3 个答案:

答案 0 :(得分:2)

您在distinct()个实例的流中使用SynchronizationEvent

stream().map(event -> new SynchronizationEvent(event)).distinct()

但是为equals()类定义了Event方法 此外,它没有具体,但即使SynchronizationEventEvent的子类,它也不起作用,因为你的equals()实现不允许比较Event的子类s:

@Override 
public boolean equals(Object o) {
    if (o == null || getClass() != o.getClass())
            return false;
   ...
}

如果SynchronizationEvent是子类,则应该使用instanceof运算符来检查当前对象是Event对象还是其任何子类的对象:

@Override 
public boolean equals(Object o) {
    if (!(o instanceof Event)
          return false;
   ...
}

答案 1 :(得分:2)

我不确定是否值得使用Streams和lambdas,但是你去了:

Collection<Event> events = allEvents.stream().collect(
    Collectors.groupingBy(e -> Arrays.asList(e.getType(), e.getProductId()),
        Collectors.collectingAndThen(
            Collectors.maxBy(Comparator.comparing(Event::getEventDate)),
            Optional::get))).values();

打破这个局面:

  • 生成的集合需要为产品和事件类型的每个组合都有一个事件,因此Collectors.groupingBy创建一个Map,其键基于Arrays.asList(e.getType(),e.​​getProductId())。
  • 如果使用单参数Collectors.groupingBy方法,Map中的每个对应值通常都是List<Event>;所以我们使用双参数形式代替那个,它接受一个应用于List<Event>的额外收集器。
  • Collectors.maxBy(Comparator.comparing(Event :: getEventDate))将List<Event>替换为该列表中的最新事件。但是,由于maxBy无法保证List非空,因此它返回Optional<Event>而不是Event实例。
  • 但我们肯定知道每个List至少会有一个元素(或者它首先不会通过groupingBy放在Map中),所以我们可以安全地将每个Optional映射到包含的值。可选的。为此,我们将Collectors.maxBy包装在Collectors.collectingAndThen中,它将maxBy的结果传递给Optional :: get。
  • 这个大型Collectors.groupingBy调用生成的地图是Map<List<Object>, Event>。此时,我们可以忽略地图的键,只返回其值。

对于它的价值,您可以使用java.util.Objects类来缩短equalshashCode方法:

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

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

答案 2 :(得分:0)

where no_cli = p_no_cli 
              and no_cli = p_no_cli

由于您不想覆盖equals和hashCode,因此可以在事件中使用eventType + productId作为键,并在eventDate排序中合并相同键的值。最后,您可以从地图中提取所有值。