代码之家  ›  专栏  ›  技术社区  ›  Anthony Accioly

如何检查任何值是否为空?

  •  2
  • Anthony Accioly  · 技术社区  · 6 年前

    我有以下特点和类(实际上这是一种简化,真正的代码是用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 很麻烦。理想情况下,我希望使用结构类型,并确保实现 栈空 使用我的API。

    不幸的是,下面的代码不起作用。变量 e 匹配任何类型,即使在 value 不定义 栈空 :

    def isEmpty(): Boolean = isDefined() && (btv.value match {
      case e: { def isEmpty(): Boolean } => e.isEmpty
      case _ => false
    })
    

    有没有授权的方法 栈空 仅当基础 价值 实施它?

    2 回复  |  直到 6 年前
        1
  •  3
  •   Andrey Tyukin    6 年前

    我是建议尝试版本的人

    def isEmpty(): Boolean = isDefined && (btv.value match {
      case e: { def isEmpty(): Boolean } => Try(e.isEmpty).getOrElse(false)
      case _ => false
    })
    

    我还注意到捕获异常的代价很高,但我认为这种情况最不常见,因为原则上,当您希望有一个isEmpty方法时,您将使用这种构造。因此,我认为这种权衡可能会得到回报,并认为这是一种防御性编码。

        2
  •  1
  •   Andrey Tyukin    6 年前

    因为不受您控制的Java类返回 Any / Object ,您没有任何编译时类型安全性,因此直接使用反射不会丢失任何东西。

    这是一个 isEmpty 使用Java反射的实现。它是作为函数实现的,但将其更改为包装器类的方法应该很简单:

    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 以交替的方式。如果它得到的对象没有 栈空 方法,如最后一个示例所示。


    编辑

    更可靠的版本是:

    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
      }
    }
    

    它可以防止 栈空 不是null,并且它不会返回 Boolean 。然而,它仍然不是“完美的”,因为这种方法可能会发生 栈空 过载。大概 org.apache.commons.lang3.reflect 可以派上用场。

    推荐文章