Compare two objects in Java with possible null values

Java

Java Problem Overview


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 ?

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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));
}

Solution 3 - Java

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.

Solution 4 - Java

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;
}

Solution 5 - Java

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.

Solution 6 - Java

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)); }

Solution 7 - Java

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

Solution 8 - Java

You can use java.util.Objects as following.

public static boolean compare(String str1, String str2) {
    return Objects.equals(str1, str2);
}

Solution 9 - Java

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?

Solution 10 - Java

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

Solution 11 - Java

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

Solution 12 - Java

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionpricelineView Question on Stackoverflow
Solution 1 - JavaMark RotteveelView Answer on Stackoverflow
Solution 2 - JavaCatView Answer on Stackoverflow
Solution 3 - JavaLuiggi MendozaView Answer on Stackoverflow
Solution 4 - JavaNameSpaceView Answer on Stackoverflow
Solution 5 - JavaphnView Answer on Stackoverflow
Solution 6 - JavaTanvirChowdhuryView Answer on Stackoverflow
Solution 7 - JavaPrashant SahooView Answer on Stackoverflow
Solution 8 - JavaJobi SubramunianView Answer on Stackoverflow
Solution 9 - JavadidxgaView Answer on Stackoverflow
Solution 10 - JavaKierrowView Answer on Stackoverflow
Solution 11 - JavaSumit SinghView Answer on Stackoverflow
Solution 12 - JavaStephen CView Answer on Stackoverflow