简体   繁体   English

如何编写一个通用的isEmpty方法,可以检查null,为空?

[英]How to write a generic isEmpty method which can check for null, empty?

I am writing a utility method which can check for empty and null string, or collection or an object or any general types - 我正在编写一个实用程序方法,可以检查空字符串和空字符串,或集合或对象或任何常规类型 -

public static boolean isEmpty(Object obj) {
    if (obj == null)
        return true;
    if (obj instanceof Collection)
        return ((Collection<?>) obj).size() == 0;

    // is below line expensive?
    final String s = String.valueOf(obj).trim();

    return s.length() == 0 || s.equalsIgnoreCase("null");
}

How can I make my above method efficient, since above isEmpty method will be called multiple times from the application which is very performance critical? 如何使我的上述方法高效,因为上面的isEmpty方法将从应用程序中多次调用,这对性能至关重要?

I am suspecting below line will be expensive because of heavy toString methods and it will create temporary garbage as well that might cause GC and slow down the performance? 我怀疑下面的行是昂贵的,因为繁重的toString方法,它会创建临时垃圾,可能会导致GC并降低性能?

final String s = String.valueOf(obj).trim();

Update:- 更新: -

I have separated isEmpty method for each type now. 我现在为每种类型分离了isEmpty方法。 Below is what I got after simplifying the above isEmpty method. 以下是我在简化上述isEmpty方法后得到的结果。

public static boolean isEmpty(Object obj) {
    if (obj == null) {
        return true;
    }
    return false;
}

public static boolean isEmpty(Collection<?> value) {
    if (value == null || value.isEmpty()) {
        return true;
    }
    return false;
}

public static boolean isEmpty(String value) {
    if (value == null || value.isEmpty()) {
        return true;
    }
    return false;
}

Update 2:- 更新2: -

If I need to check for map null or empty, should I keep both collection isEmpty and Map isEmpty method both or Collection isEmpty method will be fine for that? 如果我需要检查map null或empty,我是否应该同时保存集合isEmpty和Map isEmpty方法,或者Collection isEmpty方法可以正常吗?

public static void main(String[] args) {

    Map<String, String> hello = new HashMap<String, String>();
    System.out.println(isEmpty(hello));

    Map<String, HashMap<Integer, String>> primary = new HashMap<String, HashMap<Integer, String>>();
    System.out.println(isEmpty(primary));

}

public static boolean isEmpty(Collection<?> value) {
    return value == null || value.isEmpty();
}

public static boolean isEmpty(Map<?, ?> value) {
    return value == null || value.isEmpty();
}

This sounds like a bad design to me. 这听起来像是一个糟糕的设计。 Null is null, empty is empty, if it's a string it's a string, and so on. Null为null,empty为空,如果是字符串,则为字符串,依此类推。 Don't try to jam everything up in one method. 不要试图用一种方法堵塞一切。 It's bad for maintainability and readability. 这对于可维护性和可读性是不利的。

if (str == null || str.isEmpty())
    ...

and

if (coll == null || coll.isEmpty())

are both perfectly fine. 都很好。

Personally however, I try to never ever equate null with an empty string or empty collection. 然而,我个人尝试永远不会将null与空字符串或空集合等同。 I think it's a bad practice. 我认为这是一个不好的做法。 A null collection is no collection at all, an empty collection is in fact still a collection. 一个null集是没有收藏可言,空集是实际上还是一个集合。 You can avoid many if (coll == null) checks by keeping a collection non-null. 通过保持集合非空,可以避免许多if (coll == null)检查。 If you're worried about memory consumption, use use Collections.emptySet et al. 如果您担心内存消耗,请使用Collections.emptySet等。


That being said, if you still want to go in this direction, I'd suggest you use plain method overloading and create one isEmpty(Collection<?> coll) and one isEmpty(String str) to avoid instanceof and casting. 话虽这么说,如果你仍然想要朝着这个方向前进,我建议你使用普通方法重载并创建一个isEmpty(Collection<?> coll)和一个isEmpty(String str)来避免instanceof和cast。


Regarding your edit: 关于你的编辑:

Don't do for instance 不要这样做

if (value == null || value.isEmpty()) {
    return true;
}
return false;

just do 做就是了

return value == null || value.isEmpty();

For collections, you'll want to use isEmpty() instead of size() . 对于集合,您将需要使用isEmpty()而不是size() For some collection types (such as LinkedList), size() is more expensive than isEmpty(). 对于某些集合类型(例如LinkedList),size()比isEmpty()更昂贵。

I like to have a utility class in a common library that handles this. 我喜欢在一个处理它的公共库中有一个实用程序类。 Note that we use the object's own isEmpty, length, or size methods (in that order) if the object has one (after determining the object isn't null). 注意,如果对象有一个(在确定对象不为null之后),我们使用对象自己的isEmpty,length或size方法(按此顺序)。 By making calls to this, one doesn't need to worry about NPEs anymore -- you make your calls to this and you are good-to-go -- if it's true, then your collection/map/etc isn't null and has something in it; 通过拨打这个电话,人们不再需要担心NPE了 - 你打电话给这个并且你很有兴趣 - 如果它是真的,那么你的集合/ map / etc不是null有一些东西; if it's false, skip over the item (it's either null or empty by it's own account). 如果它是假的,则跳过该项目(它由null或自己的帐户为空)。 The second method checks an array to see if it's null or empty, but doesn't check the contents. 第二种方法检查数组以查看它是空还是空,但不检查内容。 When you iterate over the array, you simply do a check, then iterate, and as you iterate, check each element. 迭代数组时,只需执行检查,然后迭代,并在迭代时检查每个元素。

/**
 * Provides methods to perform input validation and boundary validation.
 */
public final class ValidationUtils {
    /**
     * Check to see if Object is empty or null.
     *
     * @param object
     *            The object to check
     * @return boolean {@code true} iff the Object is null or determined to be empty (using methods that it provides --
     *         if it doesn't provide such methods, it's only empty if it's null)
     */
    public static boolean isEmpty(@Nullable final Object object) {
        if (object == null)
            return true;

        try {
            // Try to use the object class's isEmpty method to check if we're empty, now that we know we're
            // not NULL
            final Method method = object.getClass().getMethod("isEmpty");
            final Object result = method.invoke(object);

            if (result instanceof Boolean)
                return Boolean.class.cast(result).booleanValue();
        } catch (@NotNull final NoSuchMethodException | InvocationTargetException | IllegalArgumentException
                | IllegalAccessException | SecurityException ignored) {
            // We couldn't invoke... let's go to the next common method
        }

        try {
            // Try to use the object class's length method to check if we're empty, now that we know we're
            // not NULL
            final Method method = object.getClass().getMethod("length");
            final Object result = method.invoke(object);

            if (result instanceof Integer)
                return Integer.class.cast(result).intValue() <= 0;
            if (result instanceof Long)
                return Long.class.cast(result).longValue() <= 0L;
        } catch (@NotNull final NoSuchMethodException | InvocationTargetException | IllegalArgumentException
                | IllegalAccessException | SecurityException ignored) {
            // We couldn't invoke... let's go to the next common method
        }

        try {
            // Try to use the object class's size method to check if we're empty, now that we know we're
            // not NULL
            final Method method = object.getClass().getMethod("size");
            final Object result = method.invoke(object);

            if (result instanceof Integer)
                return Integer.class.cast(result).intValue() <= 0;
            if (result instanceof Long)
                return Long.class.cast(result).longValue() <= 0L;
        } catch (@NotNull final NoSuchMethodException | InvocationTargetException | IllegalArgumentException
                | IllegalAccessException | SecurityException ignored) {
            // We couldn't invoke... but we're not null... treat it like an Object
        }

        // Let's treat it like an Object... we're not null, so we're not empty
        return false;
    }

    /**
     * Check to see if the array of Objects is empty or null.
     *
     * @param obj
     *            Object Array to check
     * @return boolean true if empty
     */
    public static boolean isEmpty(@Nullable final Object... obj) {
        return ((obj == null) || (obj.length == 0));
    }
}

Example uses: 示例用途:

    final Map<String, String[]> postData = ServletActionContext.getRequest().getParameterMap();
    // We're testing if the map is null or empty... we could just do a null check here because of how we're using the map after, but...
    if (!ValidationUtils.isEmpty(postData)) {
        for (final Map.Entry<String, String[]> reqKey : postData.entrySet()) {
            // We're checking if the array is null or doesn't have any length; again, the foreach does the latter, but this is perfectly fine
            if (!ValidationUtils.isEmpty(reqKey.getValue())) {
                for (final String value : reqKey.getValue()) {
                    // Checking the value
                    if (ValidationUtils.isEmpty(value)) {
                        continue;
                    }

                    ...
                }
            }
        }
    }

As I just wrote in my answer to your other question posted 30 minutes before this one, it is wasteful to check everything every time. 正如我刚才在对这个问题发表前30分钟发出的另一个问题的答案中写的那样,每次查看所有内容都是浪费。

However, these types of functions are still useful in some situations. 但是,这些类型的函数在某些情况下仍然有用。 Instead of using an "is-valid" function, however, I would implement it as a "crash-if-bad" function. 但是,我不是使用“有效”功能,而是将其实现为“崩溃 - 如果坏”功能。 Also note that this function is for collections only. 另请注意,此功能仅适用于集合。

An example use is 一个示例用途是

CrashIfCollection.badNullLength(coll, "coll", Null.BAD, 1);

Code: 码:

   import  java.util.Arrays;
   import  java.util.Collection;

enum Null {OK, BAD};

public class CrashIfCollection  {
   public static final void main(String[] ignored)  {
      test(null);
      test(Arrays.asList(new String[] {}));
      test(Arrays.asList(new String[] {"one element"}));
   }
      private static final void test(Collection<?> to_test)  {
         System.out.println("Testing " + ((to_test == null) ? "null"
            :  Arrays.toString(to_test.toArray())));
         try  {
            CrashIfCollection.badNullLength(to_test, "to_test", Null.BAD, 1);
         }  catch(Exception x)  {
            System.out.println(x);
         }
      }
   public static final void badNullLength(Collection<?> coll, String coll_name, Null nullness, int min_len)  {
      try  {
         if(nullness == Null.OK)  {
            if(coll == null)  {
               return;
            }
            if(coll.size() < min_len)  {
               throw  new IllegalArgumentException(coll_name + ".size() (" + coll.size() + ") is less than min_len (" + min_len + ")");
            }
         }
      }  catch(NullPointerException npx)  {
         if(nullness == null)  {
            throw  new NullPointerException("nullness");
         }
         throw  npx;
      }

      //Null.BAD

      try  {
         if(coll.size() < min_len)  {
            throw  new IllegalArgumentException(coll_name + ".size() (" + coll.size() + ") is less than min_len (" + min_len + ")");
         }
      }  catch(NullPointerException npx)  {
         throw  new NullPointerException(coll_name);
      }
   }
}

Output: 输出:

Testing null
java.lang.NullPointerException: to_test
Testing []
java.lang.IllegalArgumentException: to_test.size() (0) is less than min_len (1)
Testing [one element]

You can try by doing this. 你可以尝试这样做。 If you have a size as a private integer. 如果您将大小作为私有整数。 You could do the following: 您可以执行以下操作:

public boolean isEmpty()
{
    if(size == 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

This worked for me. 这对我有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM