# Code Smell 281 - Hashes

> TL;DR: Misaligned equals() and hashCode() break collections.

# Problems

- The least surprise principle violation
- Contract violations  
- [Mutable](https://maximilianocontieri.com/the-evil-powers-of-mutants) key issues  
- Duplicate hash codes  
- Debugging becomes hard  
- Poor hash distribution  

# Solutions

1. Avoid mutable keys  
2. Use effective hashes  
3. Test behavior carefully  
4. Avoid redefining equal and hash
5. Honor the [Bijection](https://maximilianocontieri.com/the-one-and-only-software-design-principle) 
 
# Context

When you work with hashed collections like *HashMap* or *HashSet*, you should pay special attention to *equals()* and *hashCode()*. 

A [mismatch](https://maximilianocontieri.com/code-smell-167-hashing-comparison) or poor implementation can lead to unpredictable bugs. 

*equals()* method defines logical equality, while *hashCode()* determines an object’s bucket for faster access. 

When these two methods fail to align, collections lose their reliability, leading to poor performance or issues like duplicate entries caused by hash collections.

The best solution is never to override the hash and equals and rely on object identity.

This is what happens in the real world using the [MAPPER](https://maximilianocontieri.com/what-is-wrong-with-software)).

Whenever you get an external object you need to map it to your bijection correspondence and not create a brand new one.

Once within your controlled system, rely on identity and forget equality issues.

# Sample Code

## Wrong

[Gist Url]: # (https://gist.github.com/mcsee/8a78eb904fa716bd84f2d01143ae959c)

```java
class BrokenObject {
    private int value;

    public BrokenObject(int value) {
        this.value = value;
    }

    @Override
    public boolean equals(Object obj) {
        return true; // Always equal
    }

    @Override
    public int hashCode() {
        return super.hashCode(); // Uses default implementation
    }
}
```

## Right

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

```java
class FixedObject {
    private final int value;

    public FixedObject(int value) {
        this.value = value;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        FixedObject that = (FixedObject) obj;
        return value == that.value;
    }

    @Override
    public int hashCode() {
        return Objects.hash(value);
    }
}

// This is the best solution

class CleanObject {
    private final int value;

    public FixedObject(int value) {
        this.value = value;
    }

    // - @Override
    // - public boolean equals(Object obj) {}

    // - @Override
    // - public int hashCode() { 
    }
}
```

# Detection

[X] Semi-Automatic 

Automated linters and IDEs flag issues when you don't properly override *equals()* or *hashCode()*.

# Tags

- Premature Optimization

# Level

[x] Intermediate

# AI Generation

AI-generated code often missteps when generating *equals()* and *hashCode()*, especially for mutable objects. 

# AI Detection

AI tools can help fix this smell with minimal guidance.

## Try Them!

*Remember: AI Assistants make lots of mistakes*

| Without Proper Instructions    | With Specific Instructions |
| -------- | ------- |
| [ChatGPT](https://chat.openai.com/?q=Correct+and+explain+this+code%3A+%60%60%60java%0D%0Aclass+BrokenObject+%7B%0D%0A++++private+int+value%3B%0D%0A%0D%0A++++public+BrokenObject%28int+value%29+%7B%0D%0A++++++++this.value+%3D+value%3B%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+boolean+equals%28Object+obj%29+%7B%0D%0A++++++++return+true%3B+%2F%2F+Always+equal%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+int+hashCode%28%29+%7B%0D%0A++++++++return+super.hashCode%28%29%3B+%2F%2F+Uses+default+implementation%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) | [ChatGPT](https://chat.openai.com/?q=correct+the+hash+and+equals+methods%3A+%60%60%60java%0D%0Aclass+BrokenObject+%7B%0D%0A++++private+int+value%3B%0D%0A%0D%0A++++public+BrokenObject%28int+value%29+%7B%0D%0A++++++++this.value+%3D+value%3B%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+boolean+equals%28Object+obj%29+%7B%0D%0A++++++++return+true%3B+%2F%2F+Always+equal%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+int+hashCode%28%29+%7B%0D%0A++++++++return+super.hashCode%28%29%3B+%2F%2F+Uses+default+implementation%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) |
| [Claude](https://claude.ai/new?q=Correct+and+explain+this+code%3A+%60%60%60java%0D%0Aclass+BrokenObject+%7B%0D%0A++++private+int+value%3B%0D%0A%0D%0A++++public+BrokenObject%28int+value%29+%7B%0D%0A++++++++this.value+%3D+value%3B%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+boolean+equals%28Object+obj%29+%7B%0D%0A++++++++return+true%3B+%2F%2F+Always+equal%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+int+hashCode%28%29+%7B%0D%0A++++++++return+super.hashCode%28%29%3B+%2F%2F+Uses+default+implementation%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) | [Claude](https://claude.ai/new?q=correct+the+hash+and+equals+methods%3A+%60%60%60java%0D%0Aclass+BrokenObject+%7B%0D%0A++++private+int+value%3B%0D%0A%0D%0A++++public+BrokenObject%28int+value%29+%7B%0D%0A++++++++this.value+%3D+value%3B%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+boolean+equals%28Object+obj%29+%7B%0D%0A++++++++return+true%3B+%2F%2F+Always+equal%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+int+hashCode%28%29+%7B%0D%0A++++++++return+super.hashCode%28%29%3B+%2F%2F+Uses+default+implementation%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) |
| [Perplexity](https://perplexity.ai/?q=Correct+and+explain+this+code%3A+%60%60%60java%0D%0Aclass+BrokenObject+%7B%0D%0A++++private+int+value%3B%0D%0A%0D%0A++++public+BrokenObject%28int+value%29+%7B%0D%0A++++++++this.value+%3D+value%3B%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+boolean+equals%28Object+obj%29+%7B%0D%0A++++++++return+true%3B+%2F%2F+Always+equal%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+int+hashCode%28%29+%7B%0D%0A++++++++return+super.hashCode%28%29%3B+%2F%2F+Uses+default+implementation%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) | [Perplexity](https://perplexity.ai/?q=correct+the+hash+and+equals+methods%3A+%60%60%60java%0D%0Aclass+BrokenObject+%7B%0D%0A++++private+int+value%3B%0D%0A%0D%0A++++public+BrokenObject%28int+value%29+%7B%0D%0A++++++++this.value+%3D+value%3B%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+boolean+equals%28Object+obj%29+%7B%0D%0A++++++++return+true%3B+%2F%2F+Always+equal%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+int+hashCode%28%29+%7B%0D%0A++++++++return+super.hashCode%28%29%3B+%2F%2F+Uses+default+implementation%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) |
| [Copilot](https://www.bing.com/chat?showconv=1&sendquery=1&q=Correct+and+explain+this+code%3A+%60%60%60java%0D%0Aclass+BrokenObject+%7B%0D%0A++++private+int+value%3B%0D%0A%0D%0A++++public+BrokenObject%28int+value%29+%7B%0D%0A++++++++this.value+%3D+value%3B%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+boolean+equals%28Object+obj%29+%7B%0D%0A++++++++return+true%3B+%2F%2F+Always+equal%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+int+hashCode%28%29+%7B%0D%0A++++++++return+super.hashCode%28%29%3B+%2F%2F+Uses+default+implementation%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) | [Copilot](https://www.bing.com/chat?showconv=1&sendquery=1&q=correct+the+hash+and+equals+methods%3A+%60%60%60java%0D%0Aclass+BrokenObject+%7B%0D%0A++++private+int+value%3B%0D%0A%0D%0A++++public+BrokenObject%28int+value%29+%7B%0D%0A++++++++this.value+%3D+value%3B%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+boolean+equals%28Object+obj%29+%7B%0D%0A++++++++return+true%3B+%2F%2F+Always+equal%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+int+hashCode%28%29+%7B%0D%0A++++++++return+super.hashCode%28%29%3B+%2F%2F+Uses+default+implementation%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) |
| [Gemini](https://gemini.google.com/?q=Correct+and+explain+this+code%3A+%60%60%60java%0D%0Aclass+BrokenObject+%7B%0D%0A++++private+int+value%3B%0D%0A%0D%0A++++public+BrokenObject%28int+value%29+%7B%0D%0A++++++++this.value+%3D+value%3B%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+boolean+equals%28Object+obj%29+%7B%0D%0A++++++++return+true%3B+%2F%2F+Always+equal%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+int+hashCode%28%29+%7B%0D%0A++++++++return+super.hashCode%28%29%3B+%2F%2F+Uses+default+implementation%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) | [Gemini](https://gemini.google.com/?q=correct+the+hash+and+equals+methods%3A+%60%60%60java%0D%0Aclass+BrokenObject+%7B%0D%0A++++private+int+value%3B%0D%0A%0D%0A++++public+BrokenObject%28int+value%29+%7B%0D%0A++++++++this.value+%3D+value%3B%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+boolean+equals%28Object+obj%29+%7B%0D%0A++++++++return+true%3B+%2F%2F+Always+equal%0D%0A++++%7D%0D%0A%0D%0A++++%40Override%0D%0A++++public+int+hashCode%28%29+%7B%0D%0A++++++++return+super.hashCode%28%29%3B+%2F%2F+Uses+default+implementation%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) | 

# Conclusion

When you misuse *equals()* or *hashCode()*, collections misbehave. 

Stick to their contracts, use effective hashes, and avoid [mutable keys](https://maximilianocontieri.com/the-evil-powers-of-mutants). 
 
# Relations

%[https://maximilianocontieri.com/code-smell-150-equal-comparison]

%[https://maximilianocontieri.com/code-smell-167-hashing-comparison]

%[https://maximilianocontieri.com/code-smell-49-caches]

# More Info

%[https://maximilianocontieri.com/the-evil-powers-of-mutants]

# Disclaimer

Code Smells are my [opinion](https://maximilianocontieri.com/i-wrote-more-than-90-articles-on-2021-here-is-what-i-learned).

# Credits

Photo by [frank mckenna](https://unsplash.com/@frankiefoto) on [Unsplash](https://unsplash.com/photos/two-toddlers-standing-in-front-of-white-window-curtain-8-rErfjcr1k)
        
* * *

> “Bad programmers worry about the code. Good programmers worry about data structures and their relationships.”

_Linus Torvalds_
 
%[https://maximilianocontieri.com/software-engineering-great-quotes]

* * *

This article is part of the CodeSmell Series.

%[https://maximilianocontieri.com/how-to-find-the-stinky-parts-of-your-code]
