289

I want to compare two strings for equality when either or both can be null.

So, I can't simply call .equals() as it can contain null values.

The code I have tried so far :

boolean compare(String str1, String str2) {
  return ((str1 == str2) || (str1 != null && str1.equals(str2)));
}

What will be the best way to check for all possible values including null ?

Anish B.
  • 9,111
  • 3
  • 21
  • 41
priceline
  • 3,157
  • 5
  • 20
  • 21
  • possible duplicate of [A better way to compare Strings which could be null](http://stackoverflow.com/questions/8336856/a-better-way-to-compare-strings-which-could-be-null) – jimr Jun 30 '12 at 05:12
  • 2
    Note that it is a bit confusing that you call the method `compare`, it has a different meaning for strings. You should call it `equals`. – Florian F Oct 12 '20 at 07:12

12 Answers12

491

Since Java 7 you can use the static method java.util.Objects.equals(Object, Object) to perform equals checks on two objects without caring about them being null.

If both objects are null it will return true, if one is null and another isn't it will return false. Otherwise it will return the result of calling equals on the first object with the second as argument.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • 1
    this approach defers the type check until the runtime of the program. two consequences: it will be slower at runtime and IDE won't let you know if you by accident try to compare different types. – averasko Jul 30 '16 at 01:51
  • 14
    @averasko When you use `Object.equals(Object)` there is no compile time type check. The `Objects.equals(Object, Object)` works very much the same as a normal `equals`, and re inference/checks by IDE, those rules are heuristics that are also supported for `Objects.equals(Object, Object)` (eg IntelliJ IDEA 2016.2 has the same check for both the normal equals and the one from Objects). – Mark Rotteveel Jul 30 '16 at 08:11
  • 4
    I like this approach. No need to include some ApacheCommons library for things these days. – Torsten Ojaperv Dec 21 '16 at 12:59
  • 1
    @SimonBaars This isn't running a function on a null object, this is a static method that you pass two arguments, which can be null, or a reference to an object. – Mark Rotteveel Oct 08 '17 at 15:46
  • @MarkRotteveel Ah, didn't read it too well. Thought you could just do object.equals(object) and the compiler fixed it into something that would prevent a NullPointerException. – Simon Baars Oct 09 '17 at 06:08
  • 11
    imho this should be the accepted answer. I don't want to reinvent the wheel in every single application I write – Neuron Jan 09 '18 at 19:46
  • pls include package: `java.util.Objects` – hyperpallium Jun 25 '19 at 09:04
  • @hyperpallium I link to the Javadoc, and any decent IDE will automatically suggest the import for you, but I'll add it. – Mark Rotteveel Jun 25 '19 at 09:50
  • This is not helpful as it will always give false for 2 different objects having the exact same properties and values. – saran3h May 05 '21 at 08:54
  • @saran3h That means that you haven't overridden `equals(Object)` in that class. See also [Why this two simple objects are not equal?](https://stackoverflow.com/questions/22658385/why-this-two-simple-objects-are-not-equal) – Mark Rotteveel May 05 '21 at 11:48
  • @Maurice You're wrong: `java.util.Objects.equals(Long.valueOf(10), Long.valueOf(10))` returns true (though you probably meant `new Long(10)` as `Long.valueOf(10)` will return cached values for [-128, 127], but even with `new Long(10)` it still returns true). The implementation does `(a == b) || (a != null && a.equals(b))`, which returns true for two different objects with the same value. That is the whole point of that method. – Mark Rotteveel May 29 '21 at 17:04
222

This is what Java internal code uses (on other compare methods):

public static boolean compare(String str1, String str2) {
    return (str1 == null ? str2 == null : str1.equals(str2));
}
Cat
  • 66,919
  • 24
  • 133
  • 141
  • 3
    Why not just change the String types to Objects - making it more generic? And then it is the same as what you will get if you move to Java 7. – Tom Nov 07 '13 at 18:31
  • 4
    Which java class contains method you provided? – Volodymyr Levytskyi Jul 25 '14 at 13:58
  • @VolodymyrLevytskyi This particular `compare` method is not in the Java JDK. If it was, I would suggest using that. – Cat Jul 28 '14 at 04:59
  • 51
    Hey! you shouldn't have a compare method returning true/false. Equals is not the same as compare. Compare should be useful for sorting. You should return `<0`, `==0` or `>0` to indicate which one is lower/grater than the other – coya Dec 15 '16 at 23:24
  • 28
    i suggest using `Objects.equals(Object, Object)` as Mark Rotteveel has pointed out in his answer (please upvote it) – Neuron Jan 09 '18 at 20:13
  • @LonelyNeuron That only applies to Java 7+. – Cat Jan 09 '18 at 20:14
  • 1
    @Eric that doesn't really make it less of a good answer. I am sure you wouldn't argue the best answer is always the one containing only code which is compatible with every java version that has always existed – Neuron Jan 09 '18 at 20:16
  • @LonelyNeuron Definitely not, but a generic "I suggest using" is misleading to people who are not using newer versions of Java. – Cat Jan 09 '18 at 20:18
  • 1
    @Eric A comment is not meant to be a full fledged answer containing all the details, so you calling it "misleading" feels a little over the top. And its not even a problem if people actually go and look at the answer I am referencing. – Neuron Jan 09 '18 at 20:21
  • This is the *clearest* implementation, but the answer added to the question checks reference equality first, so is *faster* (if many strings are interned), even though it has worst-case three comparisons. I choose clarity! – hyperpallium Jun 25 '19 at 09:10
  • 1
    @hyperpallium the first thing, `String.equals` does internally, is a reference comparison, like `if(this == other) return true;`. Since `String` is `final`, even the simplest JVMs will be capable of inlining that code, not to speak of modern common implementations. So if the strings are identical (equal and interned), the early reference comparison doesn’t gain much and in all other cases, it doesn’t help at all, except for the scenario where both are `null`, perhaps. – Holger May 25 '20 at 10:20
55

For these cases it would be better to use Apache Commons StringUtils#equals, it already handles null strings. Code sample:

public boolean compare(String s1, String s2) {
    return StringUtils.equals(s1, s2);
}

If you dont want to add the library, just copy the source code of the StringUtils#equals method and apply it when you need it.

Neuron
  • 5,141
  • 5
  • 38
  • 59
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
29

For those on android, who can't use API 19's Objects.equals(str1, str2), there is this:

android.text.TextUtils.equals(str1, str2);

It is null safe. It rarely has to use the more expensive string.equals() method because identical strings on android almost always compare true with the "==" operand thanks to Android's String Pooling, and length checks are a fast way to filter out most mismatches.

Source Code:

/**
 * Returns true if a and b are equal, including if they are both null.
 * <p><i>Note: In platform versions 1.1 and earlier, this method only worked  well if
 * both the arguments were instances of String.</i></p>
 * @param a first CharSequence to check
 * @param b second CharSequence to check
 * @return true if a and b are equal
 */
public static boolean equals(CharSequence a, CharSequence b) {
    if (a == b) return true;
    int length;
    if (a != null && b != null && (length = a.length()) == b.length()) {
        if (a instanceof String && b instanceof String) {
            return a.equals(b);
        } else {
            for (int i = 0; i < length; i++) {
                if (a.charAt(i) != b.charAt(i)) return false;
            }
            return true;
        }
    }
    return false;
}
NameSpace
  • 10,009
  • 3
  • 39
  • 40
9

Using Java 8:

private static Comparator<String> nullSafeStringComparator = Comparator
        .nullsFirst(String::compareToIgnoreCase); 

private static Comparator<Metadata> metadataComparator = Comparator
        .comparing(Metadata::getName, nullSafeStringComparator)
        .thenComparing(Metadata::getValue, nullSafeStringComparator);

public int compareTo(Metadata that) {
    return metadataComparator.compare(this, that);
}

Or you can also use the below method using Java

public static boolean compare(String first, String second) { return(Objects.isNull(first) ? Objects.isNull(second) : first.equals(second)); }

TanvirChowdhury
  • 2,498
  • 23
  • 28
7

Since version 3.5 Apache Commons StringUtils has the following methods:

static int  compare(String str1, String str2)
static int  compare(String str1, String str2, boolean nullIsLess)
static int  compareIgnoreCase(String str1, String str2)
static int  compareIgnoreCase(String str1, String str2, boolean nullIsLess)

These provide null safe String comparison.

phn
  • 1,720
  • 1
  • 14
  • 10
5

Compare two string using equals(-,-) and equalsIgnoreCase(-,-) method of Apache Commons StringUtils class.

StringUtils.equals(-, -) :

StringUtils.equals(null, null)   = true
StringUtils.equals(null, "abc")  = false
StringUtils.equals("abc", null)  = false
StringUtils.equals("abc", "abc") = true
StringUtils.equals("abc", "ABC") = false

StringUtils.equalsIgnoreCase(-, -) :

StringUtils.equalsIgnoreCase(null, null)   = true
StringUtils.equalsIgnoreCase(null, "abc")  = false
StringUtils.equalsIgnoreCase("xyz", null)  = false
StringUtils.equalsIgnoreCase("xyz", "xyz") = true
StringUtils.equalsIgnoreCase("xyz", "XYZ") = true
Prashant Sahoo
  • 979
  • 16
  • 19
4

You can use java.util.Objects as following.

public static boolean compare(String str1, String str2) {
    return Objects.equals(str1, str2);
}
Vivek
  • 11,938
  • 19
  • 92
  • 127
1
boolean compare(String str1, String str2) {
    if(str1==null || str2==null) {
        //return false; if you assume null not equal to null
        return str1==str2;
    }
    return str1.equals(str2);
}

is this what you desired?

didxga
  • 5,935
  • 4
  • 43
  • 58
0
boolean compare(String str1, String str2) {
    if (str1 == null || str2 == null)
        return str1 == str2;

    return str1.equals(str2);
}
Kierrow
  • 685
  • 1
  • 7
  • 14
0
boolean compare(String str1, String str2) {
  return (str1==null || str2==null) ? str1 == str2 : str1.equals(str2);
}
Sumit Singh
  • 15,743
  • 6
  • 59
  • 89
0

OK, so what does "best possible solution" mean?

If you mean most readable, then all the possible solutions are pretty much equivalent for an experienced Java programmer. But IMO the most readable is this

 public boolean compareStringsOrNulls(String str1, String str2) {
     // Implement it how you like
 }

In other words, hide the implementation inside a simple method that (ideally) can be inlined.

(You could also "out-source" to a 3rd party utility library ... if you already use it in your codebase.)


If you mean most performant, then:

  1. the most performant solution depends on the platform and the context,
  2. one of the "context" issues is the relative (dynamic) frequency of occurrence of null arguments,
  3. it probably doesn't matter which version is faster ... because the difference is probably too small to make a difference to the overall application performance, and
  4. if it does matter, the only way to figure out which is fastest ON YOUR PLATFORM is to try both versions and measure the difference.
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216