This rule raises an issue when String.equals(Object) is used to compare a String with a CharSequence that is not a String. To compare the character sequence of a String with a CharSequence, call contentEquals(CharSequence) instead.

Why is this an issue?

The String.equals(Object) method explicitly verifies that the argument is an instance of String:

if (!(anObject instanceof String)) {
  return false;
}

Because String is a final class, no other implementation of CharSequence (such as StringBuilder, StringBuffer, or CharBuffer) can be an instance of String. Consequently, calling equals() to compare a String with a non-String CharSequence is guaranteed to return false at runtime, even when both objects represent the exact same sequence of characters.

This usually indicates a bug where developers intend to compare textual content rather than object type and memory representation.

Exceptions

This rule does not report calls when the argument is a null literal or has null type, as contentEquals(null) throws a NullPointerException at runtime while equals(null) safely evaluates to false.

How to fix it

Replace the call to equals() with contentEquals(). The contentEquals() method compares the character sequence represented by the String with any CharSequence, returning true whenever the characters match.

Code examples

Noncompliant code example

boolean isSuccess(String expected, StringBuilder actual) {
  return expected.equals(actual); // Noncompliant: use "contentEquals()" instead of "equals()" to compare a "String" with a "CharSequence"
}

boolean checkPrefix(String text, CharSequence prefix) {
  return text.equals(prefix); // Noncompliant: use "contentEquals()" instead of "equals()" to compare a "String" with a "CharSequence"
}

Compliant solution

boolean isSuccess(String expected, StringBuilder actual) {
  return expected.contentEquals(actual);
}

boolean checkPrefix(String text, CharSequence prefix) {
  return text.contentEquals(prefix);
}

Resources

Documentation

Related rules