首页 > 解决方案 > 如果在并行流上运行,收集是否返回列表快照?

问题描述

我有一个仅在 Circle CI 上开始失败的单元测试。它在此(Kotlin)示例的最后一行失败:

generator.generateNames(50) // returns List<String>
.parallelStream()
.map { name ->
    val playerId = "${name.firstName.toLowerCase()}"
    Player(playerId = playerId)
}.collect(Collectors.toList()).last()

投掷:Caused by: java.util.NoSuchElementException

如果我不使用并行流,它总是在我的本地机器或 Circle CI 上工作。我的理论是collect调用返回一个 List 快照(它实际上在 List 完全填满之前不会阻塞)并且 CI 没有足够的 CPU 来收集其他线程中的单个元素?

但是,我的流是有序的,收集器也是对的吗?这甚至是并行收集吗?

标签: kotlinjava-8java-stream

解决方案


您收到的异常可能包含一条消息,而不仅仅是异常的名称。该消息可能会告诉您错误。例如,代码的最后一部分调用 Kotlin 扩展函数last(),在实现中:

public fun <T> List<T>.last(): T {
    if (isEmpty())
        throw NoSuchElementException("List is empty.")
    return this[lastIndex]
}

因此,如果您在堆栈跟踪中看到“列表为空”消息,java.util.NoSuchElementException那么这就是原因。

此外,如果您共享堆栈跟踪,您实际上可以看到引发异常的原因。但是看看你的代码,这是唯一可能的候选人。

那么问题是,“为什么最后的列表是空的?!” ...generateNames(50)在这种环境下工作方式不同吗?问题不collect(Collectors.toList())在于提供同步结果。


推荐阅读