为什么我使用Scala Enumeration与App mix-in获得NPE?

时间:2012-06-18 14:23:04

标签: scala nullpointerexception enumeration

我有以下代码描述枚举:     

package aicore2.worker.scheduling
    object Priority extends Enumeration with App {
      type Priority = Value

      /**
       * Action is performed immediately, any running action is interrupted
       * and action queue is cleared
       */
      val ACHTUNG = Value

      /**
       * Action is performed before all LOW, NORMAL and HIGHER actions
       */
      val HIGH = Value

      /**
       * Action is performed before all NORMAL and LOW actions
       */
      val HIGHER = Value

      /**
       * Standart priority for most actions
       */
      val NORMAL = Value

      /**
       * Action is added to the end of the queue. Desired for non-critical maintenance actions
       */
      val LOW= Value


      Priority.values  foreach println
    }

和测试:

package aicore2.worker.scheduling

import org.junit.Assert._
import org.junit.Test
import aicore2.worker.scheduling.Priority._

class PriorityTypeTests {

  @Test
  def toStringTest()  {
    //Priority.values  foreach println
    //Priority.main(Array("2"))
    assertEquals(HIGH.toString(), "HIGH")
  }

  @Test
  def stringParseTest() {
     assertEquals(Priority.withName("HIGH"), HIGH)
  }

}

当我运行测试时,我得到NPE(HIGH = null)。

当我将优先级作为应用程序运行时,我得到了我想要的任何内容: ACHTUNG 高 更高 正常 LOW

在运行test之前调用Priority.main()时得到的结果相同且没有NPE。 当我从Priority标头(“with App”)中删除App trait mix-in时,所有测试都按预期传递。 我理解当我混合应用程序特征时,初始化顺序有些奇怪,但我是Scala(来自Java领域的难民)的新手,并且还没有足够的经验来解决问题。

2 个答案:

答案 0 :(得分:2)

App表示在运行main方法之前,成员不会被初始化。在REPL中尝试以下内容:

object A { val x = "foo" }
object B extends App { val x = "foo" }
A.x // = "foo"
B.x // = null

在带有App的Enumeration类中,所有成员都是null,直到您调用其main方法。因此,来自测试方法的HIGH.toString()会导致nullPointerException,因为HIGH尚未初始化。

因此,提供Enumeration App特征似乎是一个非常糟糕的主意。

答案 1 :(得分:1)

App特征扩展了DelayedInit特征,这延迟了其成员的初始化,直到明确请求它为止(在App特征的应用程序开始时)。您应该将其视为主要方法制作对象。

有关AppDelayedInit特征的更多信息,请阅读Scala 2.9.0 release notes