41

I have a question about comparing a string with the empty string in Java. Is there a difference, if I compare a string with the empty string with == or equals? For example:

String s1 = "hi";

if (s1 == "")

or

if (s1.equals("")) 

I know that one should compare strings (and objects in general) with equals, and not ==, but I am wondering whether it matters for the empty string.

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
user42155
  • 48,965
  • 27
  • 59
  • 60
  • Isn't comparing the length better way?? I feel length comparision is more optimized than string comparision – Ravisha Jun 07 '11 at 09:27
  • @Ravisha Internally, [`String.java`'s](http://www.docjar.com/html/api/java/lang/String.java.html) `equals` method has several optimizations: **1:** Reference `==` comparison, **2:** `instanceof String` check before casting, and **3:** length value comparison before finally comparing the strings charachter by character. So to answer your question, yes, length comparison is efficient, but your code should rely on String.equals and not reinvent any of its wheels. – Patrick M Dec 11 '14 at 19:44
  • @Patrick M . If the intention here is to check for the empty string , i prefer to compare the length . Rather than comparison. – Ravisha Feb 02 '15 at 06:20
  • @Ravisha I take your point. The question and its answers ended up focusing on the canonical form of string comparison, which has a particular 'right' way when one of the strings may be null. But from the broader perspective of detecting if a string is empty, there is the specifically defined [`.isEmpty()`](http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#isEmpty()) method which "Returns true if, and only if, `length()` is 0." But then you still have to do a null check, which is why I really prefer C#'s `public static bool IsNullOrEmpty`. – Patrick M Feb 02 '15 at 17:06

9 Answers9

81
s1 == ""

is not reliable as it tests reference equality not object equality (and String isn't strictly canonical).

s1.equals("")

is better but can suffer from null pointer exceptions. Better yet is:

"".equals(s1)

No null pointer exceptions.

EDIT: Ok, the point was asked about canonical form. This article defines it as:

Suppose we have some set S of objects, with an equivalence relation. A canonical form is given by designating some objects of S to be "in canonical form", such that every object under consideration is equivalent to exactly one object in canonical form.

To give you a practical example: take the set of rational numbers (or "fractions" are they're commonly called). A rational number consists of a numerator and a denomoinator (divisor), both of which are integers. These rational numbers are equivalent:

3/2, 6/4, 24/16

Rational nubmers are typically written such that the gcd (greatest common divisor) is 1. So all of them will be simplified to 3/2. 3/2 can be viewed as the canonical form of this set of rational numbers.

So what does it mean in programming when the term "canonical form" is used? It can mean a couple of things. Take for example this imaginary class:

public class MyInt {
  private final int number;

  public MyInt(int number) { this.number = number; }
  public int hashCode() { return number; }
}

The hash code of the class MyInt is a canonical form of that class because for the set of all instances of MyInt, you can take any two elements m1 and m2 and they will obey the following relation:

m1.equals(m2) == (m1.hashCode() == m2.hashCode())

That relation is the essence of canonical form. A more common way this crops up is when you use factory methods on classes such as:

public class MyClass {
  private MyClass() { }

  public MyClass getInstance(...) { ... }
}

Instances cannot be directly instantiated because the constructor is private. This is just a factory method. What a factory method allows you to do is things like:

  • Always return the same instance (abstracted singleton);
  • Just create a new intsance with every call;
  • Return objects in canonical form (more on this in a second); or
  • whatever you like.

Basically the factory method abstracts object creation and personally I think it would be an interesting language feature to force all constructors to be private to enforce the use of this pattern but I digress.

What you can do with this factory method is cache your instances that you create such that for any two instances s1 and s2 they obey the following test:

(s1 == s2) == s1.equals(s2)

So when I say String isn't strictly canonical it means that:

String s1 = "blah";
String s2 = "blah";
System.out.println(s1 == s2); // true

But as others have poitned out you can change this by using:

String s3 = new String("blah");

and possibly:

String s4 = String.intern("blah");

So you can't rely on reference equality completely so you shouldn't rely on it at all.

As a caveat to the above pattern, I should point out that controlling object creation with private constructors and factory methods doesn't guarantee reference equality means object equality because of serialization. Serialization bypasses the normal object creation mechanism. Josh Bloch covers this topic in Effective Java (originally in the first edition when he talked about the typesafe enum pattern which later became a language feature in Java 5) and you can get around it by overloading the (private) readResolve() method. But it's tricky. Class loaders will affect the issue too.

Anyway, that's canonical form.

cletus
  • 616,129
  • 168
  • 910
  • 942
  • 1
    +1 for a great explanation. But you may want to explain what "canonical" means in this context -- that the JVM holds a table of created strings so it doesn't need to create the same string repeatedly. One of the few places Java has a clear performance advantage over C and C++. – rtperson Feb 10 '09 at 18:48
  • For C/C++, GCC at least has a compile-time option to reuse string constants. It's smart enough to support substrings where possible, too. It doesn't do this at runtime, though (unless you have a library which does this, e.g. using implicit sharing like Qt). – strager Feb 11 '09 at 01:56
  • 1
    +1 for "".equals(str) ... can't believe this never occurred to me. – Tom Mar 13 '12 at 22:38
  • Please, I want to see your "clear performance advantage". http://raid6.com.au/~onlyjob/posts/arena/ – ActiveTrayPrntrTagDataStrDrvr Nov 20 '13 at 13:17
  • 1
    Just to have that said: Testing against `"".equals(s1)` returns also `TRUE` if `s1` is `NULL`. You have to test that separately if you want to use `s1` as a string-object. – SimonSimCity Sep 18 '14 at 06:20
  • @SimonSimCity Actually, `"".equals(null)` returns `false`. Did you mean that `!"".equals(null)` returns `true`? – LoPoBo Sep 12 '19 at 11:13
  • @cletus Good explanation but I think you forgot to implement `equals` in your class `MyInt`. – LoPoBo Sep 12 '19 at 11:16
29

It's going to depend on if the string is a literal or not. If you create the string with

new String("")

Then it will never match "" with the equals operator, as shown below:

    String one = "";
    String two = new String("");
    System.out.println("one == \"\": " + (one == ""));
    System.out.println("one.equals(\"\"): " + one.equals(""));
    System.out.println("two == \"\": " + (two == ""));
    System.out.println("two.equals(\"\"): " + two.equals(""));

--

one == "": true
one.equals(""): true
two == "": false
two.equals(""): true

Basically, you want to always use equals()

tddmonkey
  • 20,798
  • 10
  • 58
  • 67
14

Short answer

s1 == ""         // No!
s1.equals("")    // Ok
s1.isEmpty()     // Ok: fast (from Java 1.6) 
"".equals(s1)    // Ok: null safe

I would assure s1 is not null and use isEmpty().

Note: empty string "" is not a special String, but counts as any other "value".

A little longer answer

References to String objects depend on the way they are created:

String objects created using the operator new always refer to separate objects, even if they store the same sequence of characters so:

String s1 = new String("");
String s2 = new String("");
s1 == s2 // false

String objects created using the operator = followed by a value enclosed whitin double quotes (= "value") are stored in a pool of String objects: before creating a new object in the pool, an object with the same value is searched in the pool and referenced if found.

String s1 = ""; // "" added to the pool
String s2 = ""; // found "" in the pool, s2 will reference the same object of s1
s1 == s2        // true

The same is true for strings created enclosing a value whitin double quotes ("value"), so:

String s1 = "";  
s1 == "";        //true

String equals method checks for both, that's why it is safe to write:

s1.equals("");

This expression may throw a NullPointerException if s1 == null, so, if you don't check for null before, it is safer to write:

"".equals(s1);

Please read also How do I compare strings in Java?

Hope it may help not so experienced users, who may find other answers a bit too complicated. :)

Community
  • 1
  • 1
Linuslabo
  • 1,568
  • 2
  • 24
  • 34
10

It's a bit sideways from your original question, but there's always

if(s1.length() == 0)

I believe this is equivalent to isEmpty() method from 1.6.

eaolson
  • 14,717
  • 7
  • 43
  • 58
  • 1
    This one will suffer from a NullPointerException if the String is null. You can always use if(s1 != null && s1.length() == 0)... That way, your conditional will short-circuit out of evaluating length if s1 is null. – rtperson Feb 10 '09 at 18:44
  • 5
    Yes, but so will s1.isEmpty() or s1.equals(""). – eaolson Feb 11 '09 at 04:20
9
"".equals(s)

Seems to be the best option, but there is also Stringutils.isEmpty(s) contained in the Apache commons lang library

Raibaz
  • 9,280
  • 10
  • 44
  • 65
  • 6
    Interesting, a library call which is longer and more obscure than the code it replaces. ;) – Peter Lawrey Feb 10 '09 at 20:17
  • While I wouldn't add commons-lang for this if I wasn't already using it for something else but the chances are I *would* be using it. The null pointer avoiding version of the statement has always given me hives and I hate the check for null way as well so I prefer the StringUtils version. – Michael Rutherfurd Feb 11 '09 at 01:06
  • 1
    while its longer, its not more obscure to use a library call like StringUtil.isNullOrEmpty(someString); , and the reason is that having a name there makes it much more readable. the performance hit is negligible, so its a win. – Chii Feb 11 '09 at 12:44
  • i guess this falls into the subjectivity of readability :) To me StringUtils.isEmpty(foo) is more readable than "".equals(foo), but i can understand Peter Lawrey's point of view. – Raibaz Feb 11 '09 at 12:52
  • 1
    @PeterLawrey "" is hardcoding. Even if you don't type anything, that quotes are harcoding wrappers. The fact that we hate hardcoding forces us to use StringUtils. – Alpaslan Jun 18 '16 at 12:15
  • @Alpaslan I hate people following rules of thumb without using their intelligence. Why anyone would imagine that `""` is likely to be any thing other than an empty String, but somehow believes `isEmpty` could not be broken. A developer who is afraid to write any code is afraid of their own shadow and will find one day when they have to write code have no idea what to do. – Peter Lawrey Jun 18 '16 at 15:47
6

A string, is a string, is a string, whether it's the empty string or not. Use equals().

Rob
  • 47,999
  • 5
  • 74
  • 91
4

Use String.isEmpty(), or StringUtils.isEmpty(String str) if you need a null check.

matsev
  • 32,104
  • 16
  • 121
  • 156
  • I wish java had a String.Empty that you could set a string to like in C#. It would make the isEmpty() method make more sense, and make it easier cleaner to make a variable equal the empty string. – Knoxie Jun 04 '12 at 12:43
0

Given two strings:

String s1 = "abc";
String s2 = "abc";

-or -

String s1 = new String("abc");
String s2 = new String("abc");

The == operator performed on two Objects checks for object identity (it returns true if the two operators return to the same object instance.) The actual behavior of == applied to java.lang.Strings does not always appear to be consistent because of String interning.

In Java, Strings are interned (at least partly at the discretion of the JVM.) At any point in time, s1 and s2 may or may not have been interned to be the same object reference (supposing they have the same value.) Thus s1 == s2 may or may not return true, based solely on whether s1 and s2 have both been interned.

Making s1 and s2 equal to empty Strings has no effect on this - they still may or may not have been interned.

In short, == may or may not return true if s1 and s2 have the same contents. s1.equals(s2) is guaranteed to return true if s1 and s2 have the same contents.

Jared
  • 25,520
  • 24
  • 79
  • 114
0

By using isEquals() method to compare with the empty string and String.

By using another method CompareTo() method.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 05 '22 at 16:20