← Back to Home

Module 3: Exception Handling

Module Overview

Master exception handling and error management in Java applications.

Learning Objectives

Hashing and HashCode Implementation in Detail

Hashing is a fundamental concept in computer science that allows for efficient data retrieval. In Java, proper implementation of hashCode() is essential for the correct functioning of hash-based collections like HashMap, HashSet, and Hashtable.

Hash Functions and Hash Codes:

  • Hash Function: A function that converts data of arbitrary size to fixed-size values (hash codes)
  • Hash Code: The integer value returned by a hash function
  • Hash Code Collision: Occurs when two different objects have the same hash code

The hashCode() and equals() Contract:

  • If two objects are equal according to equals(), they MUST have the same hash code
  • If two objects have the same hash code, they are NOT necessarily equal
  • hashCode() should consistently return the same value for the same object (unless state changes)
  • For good performance, different objects should have different hash codes when possible

Proper hashCode() Implementation:

public class Person {
    private final String firstName;
    private final String lastName;
    private final int age;
    
    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        
        Person person = (Person) o;
        return age == person.age && 
               Objects.equals(firstName, person.firstName) && 
               Objects.equals(lastName, person.lastName);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(firstName, lastName, age);
    }
}

Hash Collision Resolution:

  • Chaining: Store multiple entries with the same hash in a linked list or similar structure
  • Open Addressing: When a collision occurs, look for the next available slot
  • Java's HashMap uses chaining with balanced trees for buckets that become too large

Common Issues with hashCode() Implementations:

  • Mutable Fields: Using mutable fields in hashCode() can cause objects to be "lost" in hash-based collections if the fields change
  • Inconsistency with equals(): If hashCode() doesn't use all fields used in equals(), objects considered equal might have different hash codes
  • Poor Distribution: A hashCode() that doesn't distribute values well leads to more collisions and worse performance

Implementing hashCode() in Subclasses:

public class Employee extends Person {
    private final String employeeId;
    
    public Employee(String firstName, String lastName, int age, String employeeId) {
        super(firstName, lastName, age);
        this.employeeId = employeeId;
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;
        
        Employee employee = (Employee) o;
        return Objects.equals(employeeId, employee.employeeId);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), employeeId);
    }
}

Resources