初始化期间Scala NullPointerException

时间:2018-04-26 09:29:38

标签: scala gatling

考虑以下情况(这是我所拥有的简化版本。 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背后的原因,以及是否有任何方法可以使用最少的更改来实现这一点?谢谢。

2 个答案:

答案 0 :(得分:0)

特质初始化期间的NPE是一个非常常见的问题。 最有效的解决方法是完全避免实现继承。

如果由于某些原因无法执行,则可以标记有问题的字段lazy valdef而不是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并以其他方式分配标识符 - 递增计数器左右。