Mark方法调用它总是返回非null结果

uth*_*ark 6 scala nullable compiler-warnings notnull

Scala编译器-Xcheck-null尝试检查运行时是否存在任何潜在的空指针取消引用.

这对我来说没问题,但是我得到了太多误报,即假设我定义了记录器:

private final val LOGGER: Logger = LoggerFactory.getLogger(classOf[GenericRestImpl])
Run Code Online (Sandbox Code Playgroud)

该方法getLogger永远不会返回null.我怎样才能将这些知识传递给编译器,这样它就不会抱怨?

[WARNING] TestImpl.scala:31: warning: potential null pointer dereference: LOGGER.debug
[WARNING]       LOGGER.debug("Using {} for sort", sortParam)
Run Code Online (Sandbox Code Playgroud)

当我创建新实例时,我可以用NotNull特征标记它:

return new Foo() with NotNull.
Run Code Online (Sandbox Code Playgroud)

没关系,但是如何处理从其他方法返回的对象呢?特别是如果它来自第三方图书馆?我不喜欢将我的所有变量标记为Optional,因为它会增加太多的开销.另外,我不喜欢创建隐式转换的想法(因为对于我想要标记为NotNull的每个类,它需要额外的类.

我还检查了Scala的NotNull特征的问题库支持,但它没有帮助解决我的问题.

Mor*_*mer 5

正如Jatin所提到的,NotNull它只是一个标记或标记,因此您可以使用NotNull标记任何内容.这样做的诀窍是强制转换你的基类型with NotNull.

所以你可以写这样的东西"notnull".asInstanceOf[String with NotNull].如果您确定它永远不会为空,那么这是一个安全的演员阵容.

在您的实际示例中,您可以写:

private final val LOGGER: Logger with NotNull = 
   LoggerFactory.getLogger(classOf[GenericRestImpl]).asInstanceOf[Logger with NotNull]
Run Code Online (Sandbox Code Playgroud)

虽然没有必要为此创建新类型,但如果你必须做很多事情,那就有点麻烦,所以你可以使用一些小工具来简化/澄清符号:

type NeverNull[T] = T with NotNull
def neverNull[A](a: A): NeverNull[A] = a.asInstanceOf[A with NotNull]
Run Code Online (Sandbox Code Playgroud)

NeverNull只是T标记为的任何类型的别名,NotNull并且neverNull是一个小包装器,用于将任何类型的现有值标记A为永不为null.

然后,您可以将其用作:

private final val LOGGER: NeverNull[Logger] = neverNull {
       LoggerFactory.getLogger(classOf[GenericRestImpl])
}
Run Code Online (Sandbox Code Playgroud)

如果你真的确定自己在做什么,你甚至可以将其作为隐式转换:

implicit def neverNull[A](a: A): NeverNull[A] = a.asInstanceOf[A with NotNull]

private final val LOGGER: NeverNull[Logger] = LoggerFactory.getLogger(classOf[GenericRestImpl])
Run Code Online (Sandbox Code Playgroud)

请注意,NeverNull[Logger]它仍然是一个Logger,因此您可以在其上调用该类的任何方法,或将其传递给作为参数a的函数Logger.

这种构造称为未装箱的标记类型,非常有用,请参阅此处此处的其他应用程序和讨论.