嵌套循环到Java流之谜

嵌套循环到Java流之谜,java,java-stream,Java,Java Stream,我不熟悉Java8中的流。我正在努力弄清楚如何使用流在列表上实现嵌套for循环。一个列表包含消息,消息中的一个字段是作者的id(遗憾的是,不是obj引用)。另一个列表是作者,作者中的一个字段是作者id。代码需要为消息列表中的每条消息在作者列表中找到匹配的作者。我的工作Java代码(不使用streams或lambdas)如下所示,我的问题是如何使用streams重写此代码?我已经尝试了一些方法,我认为需要一个平面图和一个过滤器,但我似乎无法正确使用它 public void showAuthors

我不熟悉Java8中的流。我正在努力弄清楚如何使用流在列表上实现嵌套for循环。一个列表包含消息,消息中的一个字段是作者的id(遗憾的是,不是obj引用)。另一个列表是作者,作者中的一个字段是作者id。代码需要为消息列表中的每条消息在作者列表中找到匹配的作者。我的工作Java代码(不使用streams或lambdas)如下所示,我的问题是如何使用streams重写此代码?我已经尝试了一些方法,我认为需要一个平面图和一个过滤器,但我似乎无法正确使用它

public void showAuthors(List<Message> messages, List<Authors> authors) {
    String authorName=null;
    for (Message message : messages) {
        int authorId = message.getAuthorId();
        for (Authors author : authors) {
            if (author.getId() == authorId)
                authorName = author.getFullName();
                break;
        }
        System.out.println("Message id is " + message.getId() + 
                           " author is " + authorName);
    }
}
public void showAuthors(列出消息,列出作者){
字符串authorName=null;
用于(消息:消息){
int authorId=message.getAuthorId();
for(作者:作者){
if(author.getId()==authorId)
authorName=author.getFullName();
打破
}
System.out.println(“消息id为”+Message.getId()+
“作者是”+作者姓名);
}
}
我在这里看过一些类似的问题,但我似乎不太明白

public void showAuthors(List<Message> messages, List<Authors> authors) {
    String authorName=null;
    for (Message message : messages) {
        int authorId = message.getAuthorId();
        for (Authors author : authors) {
            if (author.getId() == authorId)
                authorName = author.getFullName();
                break;
        }
        System.out.println("Message id is " + message.getId() + 
                           " author is " + authorName);
    }
}
感谢您的帮助

=============================================


更新:作者列表中的Id字段有一些空数据。这要求我在流操作中使用过滤器来创建authord,Name的映射。

因为您正在进行
mxn
比较,所以最好在
authord->author
之间创建映射,以避免
O(n)
查找作者:

Map<Integer, Author> authorMaps = authors.stream().collect(toMap(Author::getId, Function.identity()));

首先,我认为你目前的逻辑是错误的。如果第一次不满足条件,并且对于所有消息,您都会得到前一个作者或类似的无效结果,则会中断内部循环

Message id is 1 author is AuthOne
Message id is 2 author is AuthOne
Message id is 4 author is AuthOne
这是正确的

public static void showAuthors(List<Message> messages, List<Author> authors) {
    String authorName = null;
    for (Message message : messages) {
        int authorId = message.getAuthorId();
        for (Author author : authors) {
            if (author.getId() == authorId) {
                authorName = author.getFullName();
                break;
            }
        }
        System.out.println("Message id is " + message.getId() + " author is " + authorName);
    }
}

您不需要流来处理消息,这里forEach更合适。然而,流对于作者列表到映射的转换是有用的

您可以将toMap与3个参数一起使用,以避免在authors列表中可能出现的authors重复(原始代码避免了这种情况)

您可以使用Optional来避免可能缺少authos、null id等。每次。map返回null,Optional变为Optional::Empty,因此在终端操作之前跳过对它的进一步处理,而ifPresence只跳过空的Optional

Map<Integer, String> authorNames=authors.stream()
    .collect(Collectors.toMap(
        Author::getId,
        Author::getFullName,
        (oldValue, newValue) -> oldValue));

messages.forEach(
    m -> Optional.of(m)
        .map(Message::getAuthorId)
        .map(authorNames::get)
        .map(name -> "Message id is " + m.getId() + " author is " + name)
        .ifPresent(System.out::println)
);
Map authorNames=authors.stream()
.collect(collector.toMap)(
作者:getId,
作者::getFullName,
(oldValue,newValue)->oldValue);
messages.forEach(
m->可选。of(m)
.map(消息::getAuthorId)
.map(authorNames::get)
.map(名称->消息id为“+m.getId()+”作者为“+name”)
.ifPresent(System.out::println)
);

在尝试了上面的一些建议之后,我很快意识到authors数据中的一些对象没有Id,只有名称(显然它们有双重用途……这不是我的设计!)

因此,我根据以上答案中的帮助/提示写了以下内容:

public void showAuthors(List<Message> messages, List<Reference> authors) {
Map<Integer, String> authorsById = authors.stream()
    .filter(author -> !(author.getId() == null))
    .filter(name -> !(name.getFullName() == null))
    .collect(Collectors.toMap(Reference::getId, Reference::getFullName));

messages.forEach(
    message -> System.out.println("Message id is " + message.getId() + 
              " Author is " + authorsById.get(message.getSenderId())));
public void showAuthors(列出消息,列出作者){
Map authorsById=authors.stream()
.filter(author->!(author.getId()==null))
.filter(name->!(name.getFullName()==null))
.collect(Collectors.toMap(Reference::getId,Reference::getFullName));
messages.forEach(
message->System.out.println(“消息id为”+message.getId()+
“Author是”+authorsById.get(message.getSenderId());
这个解决方案有什么问题吗

另外,我是stackoverflow的新手(我相信你可以告诉我)…有没有办法让所有3个响应者都能得到帮助?这就是投票的目的吗


Meg在逻辑上完全正确,忘记了if语句上的大括号。粗心。感谢您的帮助。没有理由对不应该是可选的东西使用
可选的
。这只是使整个代码复杂化。与
messages.forEach(m->Optional.of(authorNames.get(m.getAuthorId())相比IFONE(No.> Soal.Out.PrtLn(“消息ID是”+M .GeTiDe+)+“作者为+Name”);进一步,如果IDS不是唯一的,我们应该认为它是一个错误,因此,您不应该提供像<代码>(OLD值,NeWalk)这样的合并函数。->oldValue
在出现此类错误时会自动丢弃项目。如果没有作者,您的可选.of将简单地抛出NPE。在这种情况下,旧代码跳过了消息-除非您有直接问题来修复它,否则新代码也应该这样做(M Watson不会表达)另外,旧代码只适用于重复的ID,这又是一个正确规范的问题。是的,它应该是可选的。不可用的,否则我没有使用可选的,这是我评论的实际要点。对于非可选的东西,不要用可选的使代码复杂化f“新代码也应该这样做”,旧代码将匹配
null
id,而使用
Optional
会导致将
null
id视为从不匹配。对于重复项,旧代码不会处理它们,只是由于短路而忽略它们。这与显式使用重复项删除合并函数不同。有什么原因吗不要使用这样的东西:将作者的
放入
映射
(过滤掉空ID),然后是
消息。forEach
要打印消息ID和作者?@Holger Old code将在“int authorId=”中抛出NPE行,因此它将无法保留空作者id,因此将跳过消息中的空id,但永远不会正确匹配它们。通常,单独行中的直接函数引用序列比包装在可选构造函数中的直接计算组合可读性更高。编译器优化器可以
public void showAuthors(List<Message> messages, List<Reference> authors) {
Map<Integer, String> authorsById = authors.stream()
    .filter(author -> !(author.getId() == null))
    .filter(name -> !(name.getFullName() == null))
    .collect(Collectors.toMap(Reference::getId, Reference::getFullName));

messages.forEach(
    message -> System.out.println("Message id is " + message.getId() + 
              " Author is " + authorsById.get(message.getSenderId())));