考虑以下情况(这是我所拥有的简化版本。 numberOfScenarios 是这里最重要的变量:我通常使用硬编码而不是它,但我正在尝试看看是否可以计算出值):
object ScenarioHelpers {
val identifierList = (1 to Scenarios.numberOfScenarios).toArray
val concurrentIdentifierQueue = new ConcurrentLinkedQueue[Int](identifierList.toSeq)
}
abstract class AbstractScenario {
val identifier = ScenarioHelpers.concurrentIdentifierQueue.poll()
}
object Test1 extends AbstractScenario {
val scenario1 = scenario("test scenario 1").exec(/..steps../)
}
object Test2 extends AbstractScenario {
val scenario2 = scenario("test scenario 2").exec(/..steps../)
}
object Scenarios {
val scenarios = List(Test1.scenario1, Test2.scenario2)
val numberOfScenarios = scenarios.length
}
object TestPreparation {
val feeder = ScenarioHelpers.identifierList.map(n => Map("counter" -> n))
val prepScenario = scenario("test preparation")
.feed(feeder)
.exec(/..steps../)
}
不确定是否重要,但模拟从执行TestPreparation.prepScenario开始。
我看到这段代码包含一个循环依赖,这使得这种情况本身就不可能。但是我在AbstractScenario的行中得到一个NullPointerException,其中标识符正在被初始化。
我并不完全理解这一切,但我认为这与vals最初被简单声明有关,并且初始化直到稍后才会发生。因此,当初始化 identifier 时, concurrentIdentifierQueue 尚未初始化,因此为空。
我只是想了解NullPointerException背后的原因,以及是否有任何方法可以使用最少的更改来实现这一点?谢谢。
答案 0 :(得分:0)
特质初始化期间的NPE是一个非常常见的问题。 最有效的解决方法是完全避免实现继承。
如果由于某些原因无法执行,则可以标记有问题的字段lazy val
或def
而不是val
。
答案 1 :(得分:0)
你自己回答:
我看到这段代码包含一个循环依赖,这使得这种情况本身就不可能。但是我在AbstractScenario中初始化标识符的行上得到一个NullPointerException。
val feeder = ScenarioHelpers.identifierList...
调用ScenarioHelpers初始化val identifierList = (1 to Scenarios.numberOfScenarios).toArray
调用Scenarios
初始化val scenarios = List(Test1.scenario1, Test2.scenario2)
调用Test1
inicialization,包括AbstractScenario
val identifier = ScenarioHelpers.concurrentIdentifierQueue.poll()
ScenarioHelpers
仍在初始化,identifierList
为空。你必须以非循环的方式获得numberOfScenarios
。我个人会删除identifierList
并以其他方式分配标识符 - 递增计数器左右。