java 8 stream的Collector接口问题

时间:2015-03-02 15:24:00

标签: java-8 java-stream

我有以下JPA实体:

@Entity
public class Message {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    private Member sender;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    private Member recipient;

从一组邮件(Collection<Message> messages)中,我试图通过在收件人或发件人字段上进行分组来获取Map<Member, List<Message>> messageMap

为了进一步定义我的用例,连接成员(currentMember)有许多附加到其实例的已发送和已接收消息。我想检索并将消息添加到一个集合中,该集合将包含所有已连接的成员消息(已发送或已接收),如下所示:

Collection<Message> messages = new ArrayList<Message>();
messages.addAll(currentMember.getSentMessages());
messages.addAll(currentMember.getReceivedMessages());

对于当前成员至少交换过一条消息的每个其他/对方成员,我想获得所有已交换消息的列表。

然后,我将能够构建上述Map<Member, List<Message>> messageMap

是否可以使用流api开箱即用,还是需要实现自己的收集器?

1 个答案:

答案 0 :(得分:2)

如果我正确理解您的问题,您希望通过将接收方用作已发送邮件的密钥并使用发件人作为已接收邮件的密钥来统一处理邮件。您可以通过在collect操作中使用条件来执行此操作:

Map<Member, List<Message>> map = Stream.concat(
  currentMember.getSentMessages().stream(), currentMember.getReceivedMessages().stream())
.collect(Collectors.groupingBy(msg ->
                   msg.getSender()==currentMember? msg.getRecipient(): msg.getSender()));

根据与currentMember的比较结果,使用发送方或接收方作为密钥,因此密钥始终是“另一方”。它可能不是最有效的解决方案,因为它评估事先已知的信息,但它很简单。

如果您想避免重新生成已知信息,则必须通过流传输。如果没有标准Pair类型,您可以使用Map.Entry个实例来封装“所需密钥”和Message实例对:

Map<Member, List<Message>> map =
  Stream.concat(
      currentMember.getSentMessages().stream().map(msg ->
          new AbstractMap.SimpleImmutableEntry<>(msg.getRecipient(), msg)),
      currentMember.getReceivedMessages().stream().map(msg ->
          new AbstractMap.SimpleImmutableEntry<>(msg.getSender(), msg)))
  .collect(Collectors.groupingBy(e -> e.getKey(),
               Collectors.mapping(e->e.getValue(), Collectors.toList())));

在这里,不仅包装成对使代码变得复杂,由于所需的展开,收集操作的代码也变得更加复杂。

决定走向哪个方向取决于你...