为什么lambda里面的地图没有运行?

Man*_*nvi 2 concurrency lambda java.util.concurrent java-8 concurrent.futures

我试图在java 8中学习并发和lambdas.但是我的代码没有在map中输入lambda块.

List<Book> bookList = new ArrayList<Book>();
    isbnList
    .stream()
    .map(isbn -> (CompletableFuture.supplyAsync( () -> {
        try {
            List<String> pageContents = getUrlContents(webLink + isbn);
            return new Book(
                parseBookTitle(pageContents),
                isbn,
                parseRank(pageContents)
            );
        } catch (IOException ex) {
            return null;
        }
    })).thenApply(a -> bookList.add(a))
    );
Run Code Online (Sandbox Code Playgroud)

在调试时,代码退出.map行,我得到空bookList.顺序代码给我正确的结果.

Nán*_*ete 8

流管道是懒惰的.如果没有终端操作,您的流管道甚至不会被执行.Stream.map是一个中间操作,因此它不会触发管道执行.

现在,您可以forEach使用lambda表达式添加一个步骤,cf -> cf.join()以连接您创建的CompletableFuture实例,以便执行您的管道并等待每个异步期货完成.但是这样做会破坏使用异步期货的整个目的,因为你在提交下一个之前按顺序提交它们并等待每一个完成.

更好的是,您可以将您的流转换为并行流,map直接使用您的异步lambda主体,删除CompletableFuture.supplyAsync部件并收集collect类似的效果,而不会产生额外的混乱.

List<Book> bookList = isbnList.parallelStream()
    .map(isbn -> {
        try {
            List<String> pageContents = getUrlContents(webLink + isbn);
            return new Book(
                parseBookTitle(pageContents),
                isbn,
                parseRank(pageContents)
            );
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

进一步阅读:流API javadoc中的流操作和流水线.

  • 您将异步任务提交到公共fork-join池,但您不是在等待结果.您需要确保完成任务.回到使用地图,但加入forEach中的异步期货.我会更新我的答案.我会相应地更新我的答案. (2认同)
  • 注意`Collection`s有`parallelStream()`方法,它将`stream().parallel()`步骤快捷方式. (2认同)