Skip to main content

Avoid Using @Nonnull in equals Method Parameters

High
reliabilitybug

What is it?

This practice advises against using @Nonnull in the parameter of the overridden equals method, as the contract of equals requires it to properly handle null parameters.

Why apply it?

The equals method should be able to process a null argument by returning false, as specified in the java.lang.Object documentation. Using @Nonnull contradicts this requirement and can lead to unexpected behavior.

How to fix it?

Remove the @Nonnull annotation from the equals method parameter and handle null appropriately within the method's implementation.

Examples

Example 1:

Negative

The negative example shows a noncompliant equals method with a @Nonnull parameter, violating the method's contract.

import javax.annotation.Nonnull;

public class Car {
private String model;

public Car(String model) {
this.model = model;
}

@Override
public boolean equals(@Nonnull Object obj) { // Noncompliant
if (this == obj) {
return true;
}
if (getClass() != obj.getClass()) {
return false;
}
Car car = (Car) obj;
return model != null ? model.equals(car.model) : car.model == null;
}

@Override
public int hashCode() {
// Simplified hash code implementation
return model != null ? model.hashCode() : 0;
}
}

Example 2:

Positive

The positive example shows a compliant equals method that checks for null without using @Nonnull.

public class Car {
private String model;

public Car(String model) {
this.model = model;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Car car = (Car) obj;
return model != null ? model.equals(car.model) : car.model == null;
}

@Override
public int hashCode() {
// Simplified hash code implementation
return model != null ? model.hashCode() : 0;
}
}

Negative

This negative example incorrectly uses @Nonnull in the equals method parameter, which should accept null.

import javax.annotation.Nonnull;

public class Book {
private String title;

public Book(String title) {
this.title = title;
}

@Override
public boolean equals(@Nonnull Object obj) { // Noncompliant
if (this == obj) {
return true;
}
if (getClass() != obj.getClass()) {
return false;
}
Book book = (Book) obj;
return title != null ? title.equals(book.title) : book.title == null;
}

@Override
public int hashCode() {
return title != null ? title.hashCode() : 0;
}
}

Example 3:

Positive

This positive example correctly handles null by checking for it at the beginning of the equals method.

public class Book {
private String title;

public Book(String title) {
this.title = title;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Book book = (Book) obj;
return title != null ? title.equals(book.title) : book.title == null;
}

@Override
public int hashCode() {
return title != null ? title.hashCode() : 0;
}
}