有两个类和两个对应的列表:

class Click {
   long campaignId;
   Date date;
}

class Campaign {
   long campaignId;
   Date start;
   Date end;
   String type;
}

List<Click> clicks = ..;
List<Campaign> campaigns = ..;

并希望找到Click中的所有clicks:
  • Campaign列表中具有对应的campaigns,即具有相同Campaign
  • campaignId
  • Campaign具有type =“prospective” AND
  • Campaigns.start <click.date <Campaigns.end

  • 到目前为止,我有以下实现(对我来说似乎很困惑和复杂):
    clicks.
            stream().
            filter(click -> campaigns.stream().anyMatch(
                    campaign -> campaign.getCampaignType().equals("prospecting") &&
                            campaign.getCampaignId().equals(click.getCampaignId()) &&
                            campaign.getStart().after(click.getDate()) &&
                            campaign.getEnd().before(click.getDate()))).
            collect(toList());
    

    我想知道是否有更简单的解决方案。

    最佳答案

    突出的一件事是您的第二个要求与匹配无关,这仅是campaigns的条件。您必须测试这是否对您更好:

    clicks.stream()
        .filter(click -> campaigns.stream()
            .filter(camp -> "prospecting".equals(camp.type))
            .anyMatch(camp ->
                camp.campaignId == click.campaignId &&
                camp.end.after(click.date) &&
                camp.start.before(click.date)
            )
        )
        .collect(Collectors.toList());
    

    否则,我从来没有见过不涉及在第一个谓词内部流式传输第二个集合的流解决方案,因此您做不到的事情不会比您做的更好。在可读性方面,如果您感到困惑,则创建一个测试 boolean 条件的方法并调用它:
    clicks.stream()
        .filter(click -> campaigns.stream()
            .filter(camp -> "pre".equals(camp.type))
            .anyMatch(camp -> accept(camp, click))
        )
        .collect(Collectors.toList());
    
    static boolean accept(Campaign camp, Click click) {
        return camp.campaignId == click.campaignId &&
                camp.end.after(click.date) &&
                camp.start.before(click.date);
    }
    

    最后,有2条无关的建议:
  • 不要使用旧的Date类,而要使用新的java.time APILocalDate
  • 如果Campaigntype仅具有一些预定义的值(例如“submitted”,“prospecting”,“accepted” ...),则enum比一般的String更好。
  • 07-24 19:39