繁体   English   中英

Java 8流高级用法的问题

[英]Issue with advanced java 8 stream usage

我试图使用Java 8流,以便对MessageMember列表执行操作。

Message是我的域模型中的实体。 Message具有类型为Membersender字段和receiver字段。

Member是我的域模型中的第二个实体。 Member具有已发送消息的集合和已接收消息的集合。

会员JPA实体

@Entity
public class Member implements UserDetails {

    private static final long serialVersionUID = 1L;

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

    ...    

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "sender")
    private Collection<Message> sentMessages;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "recipient")
    private Collection<Message> receivedMessages;

    @Version
    private Integer version;

消息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;

    @NotNull
    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(pattern = "dd/MM/yyyy HH:mm:ss")
    private Date sendDate;

    private boolean messageRead;

    @NotNull
    @Size(min = 5, max = 500)
    @Column(length = 500)
    private String text;

    @Version
    private Integer version;

我想从Collection<Message> (来自给定成员的已发送和已接收消息的组合列表)中获取SortedMap<Message, Member> ,其中包含来自另一个成员的最新发送或接收消息作为键,而另一个成员为价值。

任何人都可以请教如何使用Java 8流的指针或想法,以实现此目标?

编辑1 :这是请求的示例输入/输出:

输入( message表的内容):

在此处输入图片说明

#2成员的输出应该是#5和#4的消息

说明:最新的发送或涉及部件#2构件#1接收到的消息是消息#4和涉及部件#2构件#6的最新消息是消息#5。

成员#2和成员#1之间的其他消息较旧,因此未考虑在内。

最终目标是实现一个消息框,例如whatsapp / hangout或fb,通过该消息框,我可以显示当前登录的用户与其他每个用户之间最后发送或接收的消息。

如果我很好理解,这(不是单线的)是可能的实现:

SortedMap<Message, Member> sortedMap = new TreeMap<>(Comparator.comparing(Message::getSendDate).reversed());
myCombinedCollection.forEach(m -> sortedMap.put(m, m.getRecipient()));

如果您真的想要单线,则应该这样做:

SortedMap<Message, Member> sort = myCombinedCollection.stream()
                                                      .collect(Collectors.toMap(m -> m,
                                                                                Message::getRecipient, 
                                                                                (m1, m2) -> m2,
                                                                                () -> new TreeMap<>(Comparator.comparing(Message::getSendDate).reversed())));

toMap收集器可以按以下方式分解:

  • 对于流中的每个Message
  • 构造一个新条目,将消息作为关键字,并将接收者成员作为值
  • 您将其放置在TreeMap中,该MapMap将消息作为发送日期进行比较
  • 如果两条消息的发送日期相同,则仅保留一条


自进行编辑以来,映射实际上更加复杂,因为实际上您必须考虑消息的发送日期以及发送者和接收者之间的映射。 因此,您必须创建一个返回唯一映射的函数(警告:您需要1->2必须与具有2->1映射相同)。

这是我使用的映射方法(您可能想实现自己的映射;仅用于示例):

  Map<String, Optional<Message>> map = myCombinedCollection.stream()
                         .collect(groupingBy(Message::mapping, maxBy(Comparator.comparing(Message::getSendDate))));

完成后,将消息放入地图中,并使用下游收集器获取最新消息:

6->2 => Optional[5-Thu Apr 01 00:00:00 CEST 3915:Hi there dude]
2->1 => Optional[4-Fri Apr 02 09:45:00 CEST 3915:Je suis disponible]

结果是:

List<Message> messages = map.entrySet().stream()
                                       .filter(e -> e.getValue().isPresent())
                                       .map(e -> e.getValue().get())
                                       .collect(toList());

该键在这里并不重要,因为您仅对消息感兴趣。 您可以做的是从此映射中获取List<Message> ,首先过滤为空的值:

[5-Thu Apr 01 00:00:00 CEST 3915:Hi there dude, 4-Fri Apr 02 09:45:00 CEST 3915:Je suis disponible]

最终输出:

 [5-Thu Apr 01 00:00:00 CEST 3915:Hi there dude, 4-Fri Apr 02 09:45:00 CEST 3915:Je suis disponible] 

如果您想看到一个小的实现,我就创建了这个小要点


我不知道这些收藏品是怎么装的。 但是也许值得为每个成员实现一个缓存映射,以便在发送/接收新消息时,您可以更新该映射。 这比获取所有合并的消息更有效。

希望能帮助到你! :)

您可以按收件人对发送的邮件进行分组,然后查找每个收件人的最新邮件(未经测试,可能有错字):

Map<Member,Message>
  memberMessages = 
      sentMessages.stream()
                  .collect(Collectors.groupingBy(Message::getRecipient, 
                                                 Collectors.maxBy(Comparator.comparingLong(m -> m.getSendDate().getTime())))));

这为您提供了与您想要的相反的键和值,但这应该可以帮助您入门。 例如,您可以通过创建此映射条目的Stream,然后使用toMap收集它,在过程中反转键和值,从而创建反向映射。

我不确定整个过程是否可以在单个Stream管道中完成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM