Why is this an issue?

It is equivalent to use the equality == operator and the equals method to compare two objects if the equals method inherited from Object has not been overridden. In this case both checks compare the object references.

But as soon as equals is overridden, two objects not having the same reference but having the same value can be equal. This rule spots suspicious uses of == and != operators on objects whose equals methods are overridden.

Noncompliant code example

String firstName = getFirstName(); // String overrides equals
String lastName = getLastName();

if (firstName == lastName) { ... }; // Non-compliant; false even if the strings have the same value

Compliant solution

String firstName = getFirstName();
String lastName = getLastName();

if (firstName != null && firstName.equals(lastName)) { ... };

Exceptions

Comparing two instances of the Class object will not raise an issue:

Class c;
if(c == Integer.class) { // No issue raised
}

Comparing Enum will not raise an issue:

public enum Fruit {
   APPLE, BANANA, GRAPE
}
public boolean isFruitGrape(Fruit candidateFruit) {
  return candidateFruit == Fruit.GRAPE; // it's recommended to activate S4551 to enforce comparison of Enums using ==
}

Comparing with final reference will not raise an issue:

private static final Type DEFAULT = new Type();

void foo(Type other) {
  if (other == DEFAULT) { // Compliant
  //...
  }
}

Comparing with this will not raise an issue:

  public boolean equals(Object other) {
    if (this == other) {  // Compliant
      return false;
    }
 }

Comparing with java.lang.String and boxed types java.lang.Integer, …​ will not raise an issue.

Resources