176

I'm usually testing this alongside a string == null, so I'm not really concerned about a null-safe test. Which should I use?

String s = /* whatever */;
...
if (s == null || "".equals(s))
{
    // handle some edge case here
}

or

if (s == null || s.isEmpty())
{
    // handle some edge case here
}

On that note - does isEmpty() even do anything other than return this.equals(""); or return this.length() == 0;?

halfer
  • 19,824
  • 17
  • 99
  • 186
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • 27
    Keep in mind that `isEmpty()` is Java 6+ only. – ColinD Jul 23 '10 at 19:14
  • 1
    You could make a helper method Util.String.hasValue(String s) which checks for null, emptiness and whitespace to handle all cases. – Cloudanger Jul 23 '10 at 19:16
  • 5
    @ColinD Probably not a problem - J2SE 5.0 completed its End of Service Life period some time ago. – Tom Hawtin - tackline Jul 23 '10 at 19:58
  • 1
    Another thing to consider is "".equals() takes Object as an argument, so you will not get a compiler error if the argument type changes from String to something else, for better or worse. – Paul Jackson Feb 10 '17 at 20:04

6 Answers6

253

The main benefit of "".equals(s) is you don't need the null check (equals will check its argument and return false if it's null), which you seem to not care about. If you're not worried about s being null (or are otherwise checking for it), I would definitely use s.isEmpty(); it shows exactly what you're checking, you care whether or not s is empty, not whether it equals the empty string

Michael Mrozek
  • 169,610
  • 28
  • 168
  • 175
  • 30
    Thank you for the explanation. Now I know why to favor "".equals(str) over str.equals("")! I was always wondering why others use this so often, but didn't take null values into account. Great :-) – Peter Wippermann Dec 02 '10 at 10:51
  • 10
    IMHO the null check is still needed in the above examples as we assume that the condition should be true for null value. s == null || "".equals(s) – mkorpela Feb 24 '14 at 11:36
  • I know this is an old thread and sorry for coming back to it, but i have a query. What is we are doing something like this: `if ("".equals(value.getValue().toString().trim()))` where, value.getValue() returns a value of object type. So the toString is necessary. So, would the .equals still take care of the null value (in case value or .getValue() return null)? – Master.Aurora Apr 18 '14 at 06:05
  • 5
    @Master.Aurora no, if `getValue()` returned null, you would get a NullPointerException when `toString()` was called – ataulm Apr 25 '14 at 13:49
  • So you're saying "".equals(s) will avoid a null reference exception, but the more natural s.equals("") won't? Sigh. – RenniePet Sep 16 '14 at 11:10
  • 12
    @RenniePet It's not like there's any magic involved. If `s` is null, you can't call methods on it -- it's null. `""` will never be null, so you can call methods on it safely, and `equals()` can handle the case where its argument is null – Michael Mrozek Sep 16 '14 at 15:47
  • 5
    A note on performance: `isEmpty()` checks the internal length of an private array whereas `equals(Object anObject)` does much more (e.g. checking `instanceof`). Perfromance-wise, `isEmpty()` is generally faster. – Turing85 Jul 21 '15 at 08:28
84

String.equals("") is actually a bit slower than just an isEmpty() call. Strings store a count variable initialized in the constructor, since Strings are immutable.

isEmpty() compares the count variable to 0, while equals will check the type, string length, and then iterate over the string for comparison if the sizes match.

So to answer your question, isEmpty() will actually do a lot less! and that's a good thing.

Jasper
  • 2,166
  • 4
  • 30
  • 50
David Young
  • 4,643
  • 2
  • 21
  • 18
  • 3
    I think in this case the difference doesn't apply; there will never be an iteration over the strings for comparison, because the sizes won't match (unless the string actually is empty, and then there's no characters to iterate over) – Michael Mrozek Jul 23 '10 at 19:25
  • 2
    True but with equals you incur a reference check first to see if they are the same object, then an instanceof, then a cast to String, a length check, and then finally the iteration. If both Strings were empty then it would be just a simple reference check though. – David Young Jul 23 '10 at 19:29
  • source code to the String class is available http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/lang/java/lang/String.java.htm – David Young Jul 24 '10 at 05:22
  • 1
    @David dead link; here's a live one http://www.docjar.com/html/api/java/lang/String.java.html#1011 – Matt Ball Apr 08 '12 at 14:31
17

One thing you might want to consider besides the other issues mentioned is that isEmpty() was introduced in 1.6, so if you use it you won't be able to run the code on Java 1.5 or below.

Fabian Steeg
  • 44,988
  • 7
  • 85
  • 112
  • 4
    That's definitely not a concern for me. – Matt Ball Jul 23 '10 at 19:37
  • 1
    Also, this answer is now 6 years ago. I would hope no one has to use anything ancient like Java 1.5 anymore. – Misha Nasledov Sep 27 '16 at 23:23
  • 1
    There are in fact many things that can break when upgrading a java version. It's less critical for a back-end application which runs on a big server, but it does matter for client applications. The graphical libraries and garbage collection strategies are impacted often by major and minor java upgrades. On top of that, client software can run on various operating systems and sometimes with limited memory, which means you often won't have the budget/resources to test everything. - Yes, I have customers that still stick with Java 5 in 2017. – bvdb Apr 26 '17 at 08:07
15

You can use apache commons StringUtils isEmpty() or isNotEmpty().

Android Killer
  • 18,174
  • 13
  • 67
  • 90
CoolBeans
  • 20,654
  • 10
  • 86
  • 101
3

I wrote a Tester class which can test the performance:

public class Tester
{
    public static void main(String[] args)
    {
        String text = "";

        int loopCount = 10000000;
        long startTime, endTime, duration1, duration2;

        startTime = System.nanoTime();
        for (int i = 0; i < loopCount; i++) {
            text.equals("");
        }
        endTime = System.nanoTime();
        duration1 = endTime - startTime;
        System.out.println(".equals(\"\") duration " +": \t" + duration1);

        startTime = System.nanoTime();
        for (int i = 0; i < loopCount; i++) {
            text.isEmpty();
        }
        endTime = System.nanoTime();
        duration2 = endTime - startTime;
        System.out.println(".isEmpty() duration "+": \t\t" + duration2);

        System.out.println("isEmpty() to equals(\"\") ratio: " + ((float)duration2 / (float)duration1));
    }
}

I found that using .isEmpty() took around half the time of .equals("").

Wolfson
  • 1,187
  • 17
  • 22
bonapart3
  • 469
  • 7
  • 20
  • This isn't a valid microbenchmark. I would strongly recommend using [Caliper](https://github.com/google/caliper) or similar purpose-built benchmarking tool. http://stackoverflow.com/q/504103/139010 – Matt Ball Jan 31 '17 at 19:20
  • Thanks for the tip! When I get some free time I will experiment with some micro benchmarking and update my answer. – bonapart3 Feb 01 '17 at 15:31
2

It doesn't really matter. "".equals(str) is more clear in my opinion.

isEmpty() returns count == 0;

Jasper
  • 2,166
  • 4
  • 30
  • 50
Kylar
  • 8,876
  • 8
  • 41
  • 75
  • 48
    I'd say `str.isEmpty()` is much more clear than `"".equals(str)`. It reads as what you're checking. Matter of opinion though, I guess. – ColinD Jul 23 '10 at 19:14
  • 7
    I think some people prefer to do "".equals(str) to avoid NPE. I personally do not like it because I would rather check for the string to be not null first. – CoolBeans Jul 23 '10 at 20:42
  • @CoolBeans Yep. Having said that the questions says: _so I'm not really concerned about a null-safe test_. – Valerio Bozz Nov 09 '20 at 14:15