如何检查任何值是否为空?
How can I check if Any value isEmpty?
我有以下特征和class(实际上这是一个简化,真正的代码是用Java写的,不在我的控制范围内):
trait BusinessTermValue {
def getValue: Any
}
class BusinessTermValueImpl(override val getValue: Any) extends BusinessTermValue
现在我正在尝试改进我的 API 而不触及原始代码(Pimp My Library 模式):
package object businessterms {
implicit final class BusinessTermValueSupport(val btv: BusinessTermValue) extends AnyVal {
def isDefined(): Boolean = btv != null && btv.value != null
def isEmpty(): Boolean = isDefined() && (btv.value match {
case s: String => s.isEmpty
case l: Traversable[_] => l.isEmpty
case c: java.util.Collection[_] => c.isEmpty
case _ => false
})
def getAs[T](): T = btv.value.asInstanceOf[T]
}
object BusinessTerm {
def apply(value: Any): BusinessTermValue = new BusinessTermValueImpl(value)
}
}
效果很好:
println(BusinessTerm("A String").isEmpty) // false
println(BusinessTerm(1).isEmpty) // false, Int can't be empty
println(BusinessTerm(new Integer(1)).isEmpty) // false, Integer can't be empty
println(BusinessTerm(List(1, 2, 3)).isEmpty) // false
println(BusinessTerm(List(1, 2, 3).asJava).isEmpty) // false
println(BusinessTerm("").isEmpty) // true
println(BusinessTerm(List()).isEmpty) // true
println(BusinessTerm(Seq()).isEmpty) // true
println(BusinessTerm(Map()).isEmpty) // true
println(BusinessTerm(List().asJava).isEmpty) // true
isEmpty
中的模式匹配仍然很麻烦。理想情况下,我想使用结构类型并确保实现 isEmpty
的任何类型都适用于我的 API.
很遗憾,下面的代码不起作用。变量 e
匹配任何类型,即使 value
没有定义 isEmpty
:
def isEmpty(): Boolean = isDefined() && (btv.value match {
case e: { def isEmpty(): Boolean } => e.isEmpty
case _ => false
})
有没有办法仅在底层 value
实现时才委托 isEmpty
?
由于 Java class 不在你的控制之下 returns Any
/Object
, 你没有任何 compile-time 无论如何类型安全,所以你不会通过直接使用反射丢失任何东西。
这是与 Java-reflection 一起使用的 isEmpty
实现。它是作为函数实现的,但是将它更改为包装器的方法应该很简单 class:
def isEmpty(a: Any): Boolean = {
try {
a.getClass.getMethod("isEmpty").invoke(a).asInstanceOf[Boolean]
} catch {
case e: java.lang.NoSuchMethodException => false
}
}
这里有几个例子:
println(isEmpty("hello"))
println(isEmpty(""))
println(isEmpty(List(1,2,3)))
println(isEmpty(Nil))
println(isEmpty(0 to 10))
println(isEmpty(42 until 42))
println(isEmpty(Some(42)))
println(isEmpty(None))
println(isEmpty((x: Int) => x * x))
它以交替方式打印false
/true
。如果它得到一个没有 isEmpty
方法的对象,它不会抛出任何讨厌的异常,如最后一个示例所示。
编辑
一个更健壮的版本是这样的:
def isEmpty(a: Any): Boolean = {
try {
val m = a.getClass.getMethod("isEmpty")
if (m.getParameterCount == 0) {
m.invoke(a).asInstanceOf[Boolean]
} else {
false
}
} catch {
case e: java.lang.NoSuchMethodException => false
case e: java.lang.ClassCastException => false
}
}
它防止 isEmpty
不为零且 return 不是 Boolean
的情况。但是,它仍然不是 "perfect",因为可能会发生方法 isEmpty
被重载的情况。也许 org.apache.commons.lang3.reflect
可以派上用场。
我是建议试用版的人
def isEmpty(): Boolean = isDefined && (btv.value match {
case e: { def isEmpty(): Boolean } => Try(e.isEmpty).getOrElse(false)
case _ => false
})
我还注意到捕获异常的成本很高,但我相信这种情况最不常见,因为原则上当您希望使用 isEmpty 方法时,您会使用此构造。所以我认为 trade-off 可能会付出代价,并且会认为这是一种防御性编码的情况。
我有以下特征和class(实际上这是一个简化,真正的代码是用Java写的,不在我的控制范围内):
trait BusinessTermValue {
def getValue: Any
}
class BusinessTermValueImpl(override val getValue: Any) extends BusinessTermValue
现在我正在尝试改进我的 API 而不触及原始代码(Pimp My Library 模式):
package object businessterms {
implicit final class BusinessTermValueSupport(val btv: BusinessTermValue) extends AnyVal {
def isDefined(): Boolean = btv != null && btv.value != null
def isEmpty(): Boolean = isDefined() && (btv.value match {
case s: String => s.isEmpty
case l: Traversable[_] => l.isEmpty
case c: java.util.Collection[_] => c.isEmpty
case _ => false
})
def getAs[T](): T = btv.value.asInstanceOf[T]
}
object BusinessTerm {
def apply(value: Any): BusinessTermValue = new BusinessTermValueImpl(value)
}
}
效果很好:
println(BusinessTerm("A String").isEmpty) // false
println(BusinessTerm(1).isEmpty) // false, Int can't be empty
println(BusinessTerm(new Integer(1)).isEmpty) // false, Integer can't be empty
println(BusinessTerm(List(1, 2, 3)).isEmpty) // false
println(BusinessTerm(List(1, 2, 3).asJava).isEmpty) // false
println(BusinessTerm("").isEmpty) // true
println(BusinessTerm(List()).isEmpty) // true
println(BusinessTerm(Seq()).isEmpty) // true
println(BusinessTerm(Map()).isEmpty) // true
println(BusinessTerm(List().asJava).isEmpty) // true
isEmpty
中的模式匹配仍然很麻烦。理想情况下,我想使用结构类型并确保实现 isEmpty
的任何类型都适用于我的 API.
很遗憾,下面的代码不起作用。变量 e
匹配任何类型,即使 value
没有定义 isEmpty
:
def isEmpty(): Boolean = isDefined() && (btv.value match {
case e: { def isEmpty(): Boolean } => e.isEmpty
case _ => false
})
有没有办法仅在底层 value
实现时才委托 isEmpty
?
由于 Java class 不在你的控制之下 returns Any
/Object
, 你没有任何 compile-time 无论如何类型安全,所以你不会通过直接使用反射丢失任何东西。
这是与 Java-reflection 一起使用的 isEmpty
实现。它是作为函数实现的,但是将它更改为包装器的方法应该很简单 class:
def isEmpty(a: Any): Boolean = {
try {
a.getClass.getMethod("isEmpty").invoke(a).asInstanceOf[Boolean]
} catch {
case e: java.lang.NoSuchMethodException => false
}
}
这里有几个例子:
println(isEmpty("hello"))
println(isEmpty(""))
println(isEmpty(List(1,2,3)))
println(isEmpty(Nil))
println(isEmpty(0 to 10))
println(isEmpty(42 until 42))
println(isEmpty(Some(42)))
println(isEmpty(None))
println(isEmpty((x: Int) => x * x))
它以交替方式打印false
/true
。如果它得到一个没有 isEmpty
方法的对象,它不会抛出任何讨厌的异常,如最后一个示例所示。
编辑
一个更健壮的版本是这样的:
def isEmpty(a: Any): Boolean = {
try {
val m = a.getClass.getMethod("isEmpty")
if (m.getParameterCount == 0) {
m.invoke(a).asInstanceOf[Boolean]
} else {
false
}
} catch {
case e: java.lang.NoSuchMethodException => false
case e: java.lang.ClassCastException => false
}
}
它防止 isEmpty
不为零且 return 不是 Boolean
的情况。但是,它仍然不是 "perfect",因为可能会发生方法 isEmpty
被重载的情况。也许 org.apache.commons.lang3.reflect
可以派上用场。
我是建议试用版的人
def isEmpty(): Boolean = isDefined && (btv.value match {
case e: { def isEmpty(): Boolean } => Try(e.isEmpty).getOrElse(false)
case _ => false
})
我还注意到捕获异常的成本很高,但我相信这种情况最不常见,因为原则上当您希望使用 isEmpty 方法时,您会使用此构造。所以我认为 trade-off 可能会付出代价,并且会认为这是一种防御性编码的情况。