Scala NullPointerException во время инициализации - PullRequest
0 голосов
/ 26 апреля 2018

Рассмотрим следующий случай (это упрощенная версия того, что у меня есть. 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.

Я вижу, что этот код содержит циклическую зависимость, которая делает этот случай невозможным сам по себе. Но я получаю исключение NullPointerException в строке в AbstractScenario, где идентификатор инициализируется.

Я не до конца понимаю все это, но я думаю, что это как-то связано с тем, что сначала просто объявляются значения val, а инициализация не происходит позже. Поэтому, когда идентификатор инициализируется, concurrentIdentifierQueue еще не инициализирован и, следовательно, имеет значение null.

Я просто пытаюсь понять причины, лежащие в основе исключения NullPointerException, а также есть ли способ заставить это работать с минимальными изменениями? Спасибо.

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Вы сами ответили:

Я вижу, что этот код содержит циклическую зависимость, которая делает этот случай невозможным сам по себе.Но я получаю исключение NullPointerException в строке в AbstractScenario, где инициализируется идентификатор.

  • val feeder = ScenarioHelpers.identifierList... вызывает инициализацию ScenarioHelpers
  • val identifierList = (1 to Scenarios.numberOfScenarios).toArray вызывает Scenarios инициализацию
  • val scenarios = List(Test1.scenario1, Test2.scenario2) вызывает Test1 инициализацию, включая AbstractScenario
  • Здесь val identifier = ScenarioHelpers.concurrentIdentifierQueue.poll() ScenarioHelpers все еще инициализируется, а identifierList равно нулю.

У вас естьполучить numberOfScenarios нециклическим способом.Лично я бы удалил identifierList и присвоил бы идентификатор другим способом - увеличивая счетчик или около того.

0 голосов
/ 26 апреля 2018

NPE во время инициализации черты - очень распространенная проблема. Самый надежный способ решить эту проблему - вообще избежать наследования реализации.

если по каким-либо причинам это невозможно, вы можете пометить проблемные поля lazy val или def вместо val.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...