46

I am aware that it is better to call the equals method over using the == operator (see this question). I want two strings to compare as equal if they are both null or if they represent the same string. Unfortunately the equals method will throw an NPE if the strings are null. My code is currently:

boolean equals(String s1, String s2) {
  if (s1 == null && s2 == null) {
    return true;
  }
  if (s1 == null || s2 == null) {
    return false;
  }
  return s1.equals(s2);
}

This is inelegant. What is the correct way to perform this test?

Community
  • 1
  • 1
Benjy Kessler
  • 7,356
  • 6
  • 41
  • 69

3 Answers3

84

If Java 7+, use Objects.equals(); its documentation explicitly specifies that:

[...] if both arguments are null, true is returned and if exactly one argument is null, false is returned. Otherwise, equality is determined by using the equals method of the first argument.

which is what you want.

If you don't, your method can be rewritten to:

return s1 == null ? s2 == null : s1.equals(s2);

This works because the .equals() contract guarantees that for any object o, o.equals(null) is always false.

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
fge
  • 119,121
  • 33
  • 254
  • 329
  • 3
    The code inside `Objects.equals()` is `return (a == b) || (a != null && a.equals(b));`. I guess this would be a better way to do it prior to Java 7 since it's straight from the horses mouth. – Chetan Kinger May 06 '15 at 15:53
  • 2
    @SashaSalauyou I saw that. It's ironic that your answer got 3 downvotes when it was the most elegant one. Unfortunately, these things happen and we have to move on :) +1 from me if it is undeleted – Chetan Kinger May 06 '15 at 16:00
  • @ChetanKinger the code of `Objects.equals()` is really a micro optimization at this point; it basically checks the reference equality first, which happens to work for `null` (since `null == null` is true) and then checks that `a` is not null, in which case it calls `.equals()`; my code really does not differ much, really. And I don't understand the downvote at all. – fge May 06 '15 at 18:37
  • @fge I did not downvote you. There was no need to to downvote this answer. I always leave a comment when I downvote an answer. Can the downvoter please leave a comment so that the OP can know what's wrong with the answer? – Chetan Kinger May 07 '15 at 02:59
  • @ChetanKinger I don't know how `.equals` is implemented. However the linked documentation says what it will do. The code suggested in this answer is slightly closer to what that documentation says than your code is. However it would only make a difference for a class in which `a.equals(a)` could return false, which would seem silly. – kasperd May 07 '15 at 17:52
  • @kasperd I don't completely follow what you are saying. Can you quote my comment to which you have replied? – Chetan Kinger May 07 '15 at 18:20
  • @ChetanKinger You suggest using `return (a == b) || (a != null && a.equals(b))`, which would not call `.equals` if `a` and `b` are the same reference. However http://docs.oracle.com/javase/8/docs/api/java/util/Objects.html#equals-java.lang.Object-java.lang.Object- indicate that if neither argument is `null`, then `a.equals` will be called. This means that if `a` is not `null`, then `Objects.equals(a, a)` would return `a.equals(a)` according to the documentation. But your code would return true without calling `a.equals`. – kasperd May 07 '15 at 18:29
  • @kasperd this is the case when documentation contradicts real behavior. Implementation returns true immediately if both args are same reference. – Alex Salauyou May 08 '15 at 06:08
44

From Objects.equals():

return (a == b) || (a != null && a.equals(b));

Very simple, self-explaining and elegant.

Alex Salauyou
  • 14,185
  • 5
  • 45
  • 67
4

If you can't use Java 7+ solution, but you have Guava or Commons Lang in classpath, then you can use the following:

Guava:

import com.google.common.base.Objects;

Objects.equal(s1, s2);

Commons Lang:

import org.apache.commons.lang3.builder.EqualsBuilder;

new EqualsBuilder().append(s1, s2).isEquals();

or

import org.apache.commons.lang3.StringUtils;

StringUtils.equals(s1, s2);
Michal Kordas
  • 10,475
  • 7
  • 58
  • 103
  • 1
    If you're using Commons Lang, wouldn't [`StringUtils.equals`](http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#equals%28java.lang.CharSequence,%20java.lang.CharSequence%29) make more sense? – Brendan Long May 06 '15 at 20:00
  • @BrendanLong - thanks for the hint – Michal Kordas Jul 27 '15 at 21:07