【问题标题】:Java global isEmpty() methodJava 全局 isEmpty() 方法
【发布时间】:2023-03-20 04:25:01
【问题描述】:

我有一个应用程序,它使用的代码生成各种类型的对象和数据结构,将它们作为 Object 实例返回,并且想要一种确定这些对象是否为“空”(或 null)的通用方法。

(这不是设计问题,也不是是否应该使用这种方法的问题,而是针对现有需求优化解决方案的问题。)

所以,这是一个简单的步骤:

public static boolean isEmpty(Object content)
{
    if (content == null)
    {
        return true;
    }
    else if (content instanceof CharSequence)
    {
        return (((CharSequence)content).length() == 0);
    }
    else if (content instanceof Collection<?>)
    {
        return ((Collection<?>)content).isEmpty();
    }
    else if (content instanceof Object[])
    {
        return (((Object[])content).length == 0);
    }
    else  // Use reflection (an exaggeration, for demo purposes)
    {
        try
        {
            Method isEmpty = content.getClass().
                             getDeclaredMethod("isEmpty", (Class<?>[])null);
            if (isEmpty != null)
            {
                Object result = isEmpty.invoke(content, (Object[])null);

                if (result instanceof Boolean)
                {
                    return (Boolean)result;
                }
            }
        }
        catch (Exception e)
        {
        }
    }

    return false;
}

在性能或覆盖范围方面有任何潜在改进的想法吗?

比如反射也可以用来判断对象是否有length()或size()方法,调用它看结果是否为0。(实际上反射可能太多了,但我是为了完整起见,将其包括在此处。)

是否有一个非常常用的顶级类,它具有 length() 或 size() 方法,而不是 isEmpty() 方法,以包含在上述情况中,类似于具有 isEmpty() 的 Collection?

【问题讨论】:

  • 乍一看,单独使用这种方法似乎是一个糟糕的设计决策。这将如何使用?
  • 它用于检查对象的“空性”,由产生多种不同类型数据的不可更改方法返回。
  • 为什么?如果您正在调用此方法,您可能应该已经知道要传递给它的对象,只需在对象本身上调用 isEmpty 就可以省去麻烦。
  • 这不是将对象传递给方法,而是从中获取对象。返回类型未知,它只是一个对象!
  • 真是令人沮丧。根本没有办法避免这种情况吗?就个人而言,我宁愿重写我的大部分项目也不愿接受这样的怪物。

标签: java data-structures collections is-empty


【解决方案1】:

代替丑陋的instanceofs,将方法拆分成几个同名但参数不同的方法。例如

static boolean isEmpty(Object[] array)
static boolean isEmpty(Collection collection)
static boolean isEmpty(CharSequence cs)

如果您真的想要特殊对象的自己的接口,而不是反射,请声明该接口,然后为了与上述保持一致,提供静态实用程序

static boolean isEmpty(IMayBeEmpty imbe);

【讨论】:

  • 不仅如此,您还可以包含一些常见的 lang isEmpty 方法。减少您必须编写的代码量。
  • 仍然,它闻起来很臭(并不意味着它不合理或不可避免)。但这是我能想到的最优雅的解决方案。
  • @Jim 你说得对,重载比使用 instanceof 更好,但是由于声明的返回类型是 Object,所以只会调用带有 Object 参数的 isEmpty() 方法。您提到的“commons lang”代码是指 Apache Commons 吗?
  • 我同意 PNS。在重载场景中完成虚拟方法绑定时,它是在编译时根据参数的声明类型完成的。在这种情况下,如果您传递给 isEmpty() 方法的内容被声明为 Object,那么无论实际类型如何,您都只会调用 isEmpty(Object)。但是,您可以在这里做一些反思工作。请参阅下面的答案。
  • 嗯,我想我错过了参数真正定义为对象,而不是集合,字符串 [] 等的部分......在这种情况下@Matt 是正确的,编译器不会知道的更好。您需要 instanceof 或某种双重调度。
【解决方案2】:

此方法至少可以解决您的通用 isEmpty(Object) 问题。但是,您不会获得编译时安全性,并且在没有为所请求的确切类型存在的方法的情况下调用它会产生运行时错误。请注意,“MethodUtils”类来自 apache commons-beanutils,虽然您可以轻松地直接使用反射,但为了简单起见,我在这里使用 beanutils。

“invokeExactcMethod”方法在给定类中查找具有给定名称的静态方法,该方法具有所传递对象数组的兼容参数。因此,如果对象的运行时类型是 ArrayList,它将查找 isEmpty(ArrayList) 然后 isEmpty(AbstractList) 然后 isEmpty(List)。如果可以找到该方法,则调用该方法,否则抛出 NoSuchMethodException。

public class MyUtility {
  static boolean isEmpty(Object object) {
    if (object == null) {
      return true;
    }
    else {
      try {
        return MethodUtils.invokeStaticMethod(
                  MyUtility.class, "isEmpty", new Object[]{object});
      }
      catch (NoSuchMethodException e) {
        throw new IllegalArgumentException(e);
      }
      catch (IllegalAccessException e) {
        throw new IllegalArgumentException(e);
      }
      catch (NoSuchMethodException e) {
        throw new RuntimeException(e);
      }
    }
  }
}

“invokeExactStaticMethod”更具确定性,不使用分配兼容性,而是精确的签名匹配。这意味着 isEmpty(List) 永远不会匹配任何内容,因为您无法构造该类型的任何内容。

【讨论】:

  • 很好的答案,谢谢!但是拥有 instanceof 会不会更快,尤其是当预期的数据类型是 CharSequence、Collection> 或任何类型的数组时?
  • MethodUtils 可能会缓存答案,但是是的,它可能会更快。但是,这意味着每次添加新的 isEmpty 方法时,都必须使用大 IF 子句更改该方法。使用此解决方案,您只需添加新方法。我完全支持不易出错的代码,而且我认为这不太容易出错。当您第一次尝试添加新方法并忘记 if 子句时,您会相信我。
  • 非常合理的方法。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2018-12-20
  • 1970-01-01
  • 1970-01-01
  • 2013-07-29
  • 2017-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多