# Refactoring 015 - Remove NULL

> TL;DR: Use the Null Object Pattern to eliminate null checks and simplify your code.

# Problems Addressed

- Frequent null checks and [IFs](https://maximilianocontieri.com/refactoring-014-remove-if) cluttering your code

- [Null pointer exceptions](https://maximilianocontieri.com/code-smell-260-crowdstrike-null)

- Hard-to-read and maintain code

- Lack of extensibility

- Unnecessary complexity with excessive null checks.

- More [detail about NULL creation and regrets](https://maximilianocontieri.com/null-the-billion-dollar-mistake)

# Related Code Smells

%[https://maximilianocontieri.com/code-smell-12-null]

%[https://maximilianocontieri.com/code-smell-260-crowdstrike-null]

%[https://maximilianocontieri.com/code-smell-149-optional-chaining]

%[https://maximilianocontieri.com/code-smell-212-elvis-operator]

%[https://maximilianocontieri.com/code-smell-192-optional-attributes]

%[https://maximilianocontieri.com/code-smell-126-fake-null-object]

%[https://maximilianocontieri.com/code-smell-208-null-island]

# Steps

These steps are a special case of [Remove IF Refactoring](https://maximilianocontieri.com/refactoring-014-remove-if)

1. Create a Null Object class that implements the same interface

2. Replace null checks with the polymorphic Null Object

# Sample Code

## Before

[Gist Url]: # (https://gist.github.com/mcsee/11ff9fab5c27f29304b0b7e31ee3b71d)

```java
public class SoccerMatch {
    private Team homeTeam;
    private Team awayTeam;
    private TimeRecord regularTime;
    private TimeRecord extraTime;

    public SoccerMatch(Team homeTeam, 
                       Team awayTeam,
                       TimeRecord regularTime, 
                       TimeRecord extraTime) {
        this.homeTeam = homeTeam;
        this.awayTeam = awayTeam;
        this.regularTime = regularTime;
        this.extraTime = extraTime;
    }

    public int totalGoals() {
        int goals = regularTime.goals();
        // You might forget this iF check 
        // resulting in a null error
        if (extraTime != null) {
            goals += extraTime.goals();
        }
        return goals;
    }
}

class TimeRecord {
    private int goals;

    public TimeRecord(int goals) {
        this.goals = goals;
    }

    public int goals() {
        return goals;
    }
}
```

## After

[Gist Url]: # (https://gist.github.com/mcsee/785aa63b08fbecb6ea243c80c3c36389)

```java
// 1. Create a Null Object class that implements the same interface

interface TimeRecord {
    // The common protocol between the real object 
    // and the Null Object
    int goals();
}

class PlayedTimeRecord implements TimeRecord {
    // This class is suitable to be
    // a Regular Time or an Extra Time
    private int goals;

    public PlayedTimeRecord (int goals) {
        this.goals = goals;
    }

    public int goals() {
        return goals;
    }
}

class NoExtraTime implements TimeRecord {
    public int goals() {
        // They are polymorphic
        // They don't need IF checks
        return 0;
    }
}

public class SoccerMatch {
    private Team homeTeam;
    private Team awayTeam;
    private PlayedTimeRecord regularTime;
    private TimeRecord extraTime;

    public SoccerMatch(Team homeTeam, 
                       Team awayTeam,
                       PlayedTimeRecord regularTime,
                       TimeRecord extraTime) {
        this.homeTeam = homeTeam;
        this.awayTeam = awayTeam;        
        // There's a business rule telling
        // Regular time is not optional
        // Therefore is an instance of PlayedTimeRecord
        this.regularTime = regularTime;
        this.extraTime = extraTime;
    }

    public int totalGoals() {
        // 2. Replace null checks with the polymorphic Null Object
        // No Ifs 
        // No null checks
        return regularTime.goals() + extraTime.goals();
    }
}
```

*As a side note when you prompt Gemini-AI with the After version it says:*

> While the code is well-structured, there's a minor optimization opportunity. 
> The NoExtraTime class can be eliminated without compromising the code's 
> functionality.

* .. and suggests using the first version with [the billion-dollar mistake problem!](https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/)*

# Type

[X] Semi-Automatic

The refactoring has a semantic part that needs to find an existing NullObejct in the domain.

# Safety

This refactoring is generally safe.

You must ensure that the Null Object's behavior matches the expected behavior for real cases in your code.

The null object needs to be partially polymorphic with real ones.

In strongly typed languages, they must adhere to the same interface or belong to the same hierarchy.

# Why is the code better?

You eliminate null checks with [accidental IF conditions](https://maximilianocontieri.com/refactoring-014-remove-if), making the code cleaner and easier to understand. 

The Null Object Pattern ensures you always work with objects, avoiding null pointer exceptions - [The Billion Dollar Mistake](https://maximilianocontieri.com/null-the-billion-dollar-mistake).

# Limitations

# Tags

- Null

# Related Refactorings

%[https://maximilianocontieri.com/refactoring-014-remove-if]

# See also

%[https://maximilianocontieri.com/null-the-billion-dollar-mistake]

%[https://en.wikipedia.org/wiki/Null_Object_pattern]

%[https://refactoring.guru/es/replace-conditional-with-polymorphism]

* * * 

This article is part of the Refactoring Series.

%[https://maximilianocontieri.com/how-to-improve-your-code-with-easy-refactorings]
