HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaModerate

Writing a generic performance efficient isEmpty method which can check for null or emptiness

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
emptinessgenericcanmethodnullwritingefficientisemptyperformancefor

Problem

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?

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?

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


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?

public static void main(String[] args) {

    Map hello = new HashMap();
    System.out.println(isEmpty(hello));

    Map> primary = new HashMap>();
    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();
}

Solution

Method overloading can make your implementations more efficient and cleaner:

public static boolean isEmpty(Collection obj) {
    return obj == null || obj.isEmpty();
}

public static boolean isEmpty(String string) {
    return string == null || string.trim().isEmpty();
}

public static boolean isEmpty(Object obj) {
    return obj == null || obj.toString().trim().isEmpty();
}


The Collection version is as efficient as possible.

The String version would be more efficient without the trimming. It would be best to trim your strings as soon you see them, long before they reach this call. If you can review the callers and make sure that the strings are always trimmed at their origins, then you can remove .trim() for best performance.

The Object version can be inefficient, depending on the toString implementation of the objects that will be passed to it, and because of the trimming.

I removed the comparison with null from there, because it seems pointless to me. I mean, a class whose toString method says "null" would seem very very odd.

In any case, you don't really want the Object version to be called, at all. Most importantly because it probably won't even work. Take for example an empty Map. Its toString method returns the string {}, which won't match your conditions of emptiness. (For this type you should definitely add isEmpty(Map map) to benefit from its isEmpty method.)

If performance is so critical, then add more overloaded implementations for all other types that you care about, for example:

public static boolean isEmpty(Something obj) {
    return obj == null || obj.isEmpty();
}


Finally, especially when something is so important, you definitely want to unit test it, for example:

@Test
public void testEmptyObject() {
    assertTrue(isEmpty((Object) null));
    assertFalse(isEmpty(new Object()));
}

@Test
public void testEmptyString() {
    assertFalse(isEmpty("hello"));
    assertTrue(isEmpty(""));
    assertTrue(isEmpty(" "));
    assertTrue(isEmpty((Object) null));
}

@Test
public void testEmptySet() {
    assertFalse(isEmpty(new HashSet(Arrays.asList("hello"))));
    assertTrue(isEmpty(new HashSet()));
}

@Test
public void testEmptyMap() {
    Map map = new HashMap();
    assertTrue(isEmpty(map));
    map.put("hello", "hi");
    assertFalse(isEmpty(map));
}

Code Snippets

public static boolean isEmpty(Collection obj) {
    return obj == null || obj.isEmpty();
}

public static boolean isEmpty(String string) {
    return string == null || string.trim().isEmpty();
}

public static boolean isEmpty(Object obj) {
    return obj == null || obj.toString().trim().isEmpty();
}
public static boolean isEmpty(Something obj) {
    return obj == null || obj.isEmpty();
}
@Test
public void testEmptyObject() {
    assertTrue(isEmpty((Object) null));
    assertFalse(isEmpty(new Object()));
}

@Test
public void testEmptyString() {
    assertFalse(isEmpty("hello"));
    assertTrue(isEmpty(""));
    assertTrue(isEmpty(" "));
    assertTrue(isEmpty((Object) null));
}

@Test
public void testEmptySet() {
    assertFalse(isEmpty(new HashSet<String>(Arrays.asList("hello"))));
    assertTrue(isEmpty(new HashSet<String>()));
}

@Test
public void testEmptyMap() {
    Map<String, String> map = new HashMap<String, String>();
    assertTrue(isEmpty(map));
    map.put("hello", "hi");
    assertFalse(isEmpty(map));
}

Context

StackExchange Code Review Q#56236, answer score: 13

Revisions (0)

No revisions yet.