问题
Scala compiler has -Xcheck-null
which tries to check if there are any potential null pointer dereference in runtime.
It's ok for me, but I get too much false positives, i.e. suppose I define logger :
private final val LOGGER: Logger = LoggerFactory.getLogger(classOf[GenericRestImpl])
The method getLogger
never returns null
. How can I pass this knowledge to compiler so it will not complain?
[WARNING] TestImpl.scala:31: warning: potential null pointer dereference: LOGGER.debug
[WARNING] LOGGER.debug("Using {} for sort", sortParam)
When I create new instance I can mark it with NotNull
trait:
return new Foo() with NotNull.
That's ok, but what to do with objects returned from other methods? Especially if it is comming from 3rd party library? I don't like idea to mark all my variables as Optional, because it will add too much overhead. Also, I don't like idea to create implicit conversions (because it will require extra class for each class that I want to mark as NotNull.
I also checked question Library support for Scala's NotNull trait but it didn't help to solve my problem.
回答1:
As Jatin mentions, NotNull
is just a marker or tag, so you can use NotNull
to tag anything. The trick to do this is to forcing a cast your base type with NotNull
.
So you can write something like this "notnull".asInstanceOf[String with NotNull]
. It's a safe cast if you are sure it's never ever null.
In your actual example, you can therefore write:
private final val LOGGER: Logger with NotNull =
LoggerFactory.getLogger(classOf[GenericRestImpl]).asInstanceOf[Logger with NotNull]
While there is no need to create new types for this, it's a bit cumbersome if you have to do it a lot, so you could use some little utils to simplify/clarify the notation:
type NeverNull[T] = T with NotNull
def neverNull[A](a: A): NeverNull[A] = a.asInstanceOf[A with NotNull]
NeverNull
is just an alias for any type T
tagged with NotNull
and neverNull
is a little wrapper to tag any existing value of type A
as being never null.
You can then use it as:
private final val LOGGER: NeverNull[Logger] = neverNull {
LoggerFactory.getLogger(classOf[GenericRestImpl])
}
You could even make this an implicit conversion, if you are really sure of what you are doing:
implicit def neverNull[A](a: A): NeverNull[A] = a.asInstanceOf[A with NotNull]
private final val LOGGER: NeverNull[Logger] = LoggerFactory.getLogger(classOf[GenericRestImpl])
Note that NeverNull[Logger]
is still a Logger
, so you can call any method of that class on it, or pass it on to functions that take as parameter a Logger
.
This kind of construct is called an unboxed tagged type and is pretty useful, see other applications and discussion here and here.
来源:https://stackoverflow.com/questions/18494264/mark-method-call-that-it-always-returns-not-null-result