Printing is unavailable

This course is licensed for personal online viewing only.

Public preview • CL-P000000-C41-L1428-BC1D3288

Home Dashboard
Chapter 78 · Module 9 — Java Collections Framework

HashSet and Hash-Based Set Behavior

5,362
words
30
min read
3
tools

1. Learning Outcomes#

इस chapter को पूरा करने के बाद आप:

  • समझ पाएँगे कि HashSet क्या है और इसका उपयोग क्यों किया जाता है।
  • समझ पाएँगे कि HashSet, Set interface का hash-based implementation कैसे है।
  • समझ पाएँगे कि HashSet internally HashMap की मदद लेता है।
  • empty HashSet और किसी existing collection से HashSet बना पाएँगे।
  • add(), contains(), remove(), size(), isEmpty() और clear() का सही उपयोग कर पाएँगे।
  • समझ पाएँगे कि duplicate element add क्यों नहीं होता।
  • add() के boolean result का अर्थ समझ पाएँगे।
  • समझ पाएँगे कि duplicate detection में hashCode() और equals() दोनों की क्या भूमिका है।
  • समझ पाएँगे कि HashSet केवल एक null element क्यों रखता है।
  • समझ पाएँगे कि HashSet iteration order की guarantee क्यों नहीं देता।
  • hash-based lookup का high-level working समझ पाएँगे।
  • hash collision का basic meaning समझ पाएँगे।
  • custom objects के साथ correct equals() और hashCode() की जरूरत समझ पाएँगे।
  • समझ पाएँगे कि set के अंदर मौजूद object की equality-related state बदलना खतरनाक क्यों हो सकता है।
  • initial capacity, load factor और capacity growth का basic purpose समझ पाएँगे।
  • common HashSet operations की expected performance समझ पाएँगे।
  • समझ पाएँगे कि खराब hash distribution performance को कैसे प्रभावित कर सकता है।
  • समझ पाएँगे कि HashSet synchronized नहीं है।
  • तय कर पाएँगे कि practical code में HashSet कब सही choice है।

2. HashSet की जरूरत क्यों पड़ती है?#

मान लीजिए आपके application में registered city names रखने हैं:

  • Pune
  • Mumbai
  • Delhi
  • Pune

यहाँ Pune दो बार आया है।

अगर requirement यह है कि हर city केवल एक बार रहनी चाहिए, तो हमें ऐसी collection चाहिए जो duplicates को automatically reject कर सके।

यही काम Set करता है।

और जब हमें:

  • unique elements चाहिए,
  • fast membership checking चाहिए,
  • लेकिन insertion या encounter order preserve करना जरूरी नहीं है,

तब HashSet एक बहुत common choice है।

Key Idea

HashSet का मुख्य उद्देश्य unique elements को hash-based structure में रखना है।

3. HashSet क्या है?#

HashSet Java Collections Framework की एक class है जो Set interface को implement करती है।

इसका सबसे important behavior है:

duplicate elements store नहीं होते।

उदाहरण के लिए, अगर हम "Java" को दो बार add करने की कोशिश करें, तो set में "Java" केवल एक बार रहेगा।

JAVA
import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        Set<String> skills = new HashSet<>();

        skills.add("Java");
        skills.add("SQL");
        skills.add("Java");

        System.out.println(skills.size());
    }
}

Expected Output#

TEXT
2

हमने add() तीन बार call किया, लेकिन unique values केवल दो हैं:

  • Java
  • SQL

इसलिए size() का result 2 है।

4. HashSet एक Hash-Based Set है#

यहाँ दो शब्द अलग-अलग समझना जरूरी है:

Set#

Set यह rule define करता है कि duplicate elements नहीं होने चाहिए।

HashSet#

HashSet उस Set behavior को hash-based mechanism की मदद से implement करता है।

इसलिए:

Set बताता है क्या behavior चाहिए।

HashSet तय करता है कि वह behavior कैसे efficiently implement करना है।

आप अक्सर variable को interface type से declare करते हुए देखेंगे:

JAVA
Set<String> names = new HashSet<>();

यहाँ:

  • Set<String> reference type है।
  • HashSet<> actual object है।

5. HashSet internally HashMap की मदद लेता है#

यह HashSet का बहुत important interview concept है।

HashSet internally एक HashMap द्वारा backed होता है।

लेकिन इसका अर्थ यह नहीं है कि आपको HashSet use करते समय manually HashMap बनाना पड़ता है।

HashSet यह काम internally करता है।

High level पर idea ऐसा है:

  • HashSet का element
  • internal HashMap में key की तरह रखा जाता है
  • उसके साथ एक internal dummy value associate की जाती है

मान लीजिए:

JAVA
set.add("Java");

Conceptually इसे ऐसे सोच सकते हैं:

"Java" internal map में key की तरह store होता है।

इसी कारण HashSet को hash-based lookup behavior मिलता है।

Remember

HashSet को use करते समय आप elements के साथ काम करते हैं। Internal HashMap implementation detail है।

6. Empty HashSet बनाना#

सबसे common तरीका:

JAVA
HashSet<String> languages = new HashSet<>();

Interface reference के साथ:

JAVA
Set<String> languages = new HashSet<>();

दोनों valid हैं।

दूसरा form अक्सर flexible programming style के लिए उपयोग किया जाता है क्योंकि variable Set abstraction पर depend करता है।

7. Existing Collection से HashSet बनाना#

मान लीजिए आपके पास एक List है जिसमें duplicate values मौजूद हैं।

JAVA
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();

        names.add("Amit");
        names.add("Ravi");
        names.add("Amit");

        Set<String> uniqueNames = new HashSet<>(names);

        System.out.println(uniqueNames.size());
    }
}

Expected Output#

TEXT
2

Constructor existing collection के elements को set में add करता है।

क्योंकि HashSet duplicates allow नहीं करता, duplicate "Amit" अलग element बनकर नहीं रहता।

यह pattern practical applications में useful है जब किसी collection से unique values चाहिए।

8. add() क्या करता है?#

add() किसी element को set में add करने की कोशिश करता है।

JAVA
Set<String> technologies = new HashSet<>();

technologies.add("Java");
technologies.add("SQL");

लेकिन HashSet.add() केवल element add नहीं करता।

यह एक boolean result भी देता है।

यही result बताता है कि set वास्तव में बदला या नहीं।

9. add() का Boolean Result#

ध्यान से यह example देखिए:

JAVA
import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        Set<String> skills = new HashSet<>();

        System.out.println(skills.add("Java"));
        System.out.println(skills.add("Java"));
        System.out.println(skills.add("SQL"));
    }
}

Expected Output#

TEXT
true
false
true

पहली बार "Java" मौजूद नहीं था।

इसलिए वह add हुआ और add() ने true return किया।

दूसरी बार "Java" पहले से मौजूद था।

इसलिए set नहीं बदला और add() ने false return किया।

फिर "SQL" नया element था, इसलिए result true आया।

इसे याद रखने का आसान rule:

Situation add() result
नया element successfully add हुआ true
equivalent element पहले से मौजूद था false
Key Idea

add() का boolean result यह नहीं बताता कि method successfully चली या नहीं। यह बताता है कि set में नया element वास्तव में add हुआ या नहीं।

10. Duplicate को HashSet पहचानता कैसे है?#

यह chapter का सबसे important हिस्सा है।

HashSet duplicate detection के लिए मुख्य रूप से दो methods पर निर्भर करता है:

  • hashCode()
  • equals()

इन्हें दो अलग responsibilities की तरह समझिए।

hashCode() की भूमिका#

hashCode() एक integer value देता है।

HashSet इस hash information का उपयोग यह पता लगाने में करता है कि element को किस hash location के आसपास देखना चाहिए।

इसे ऐसे सोचिए:

किसी बहुत बड़े office में employee ढूँढना है।

पहले आपको department पता चल जाए तो पूरे office में search करने की जरूरत नहीं पड़ती।

Hash code इसी तरह search area को narrow करने में मदद करता है।

equals() की भूमिका#

Candidate element मिलने के बाद यह confirm करना जरूरी है:

क्या दोनों objects logically equal हैं?

यह काम equals() करता है।

इसलिए simplified idea है:

  • hashCode() → candidate location खोजने में मदद करता है।
  • equals() → equality confirmation करता है।

अब इसे visual flow से समझिए।

Visual Diagram80%

Rendering diagram…

यह intentionally high-level model है।

Actual internal implementation अधिक optimized हो सकती है, लेकिन beginner के लिए important reasoning यही है:

  1. hash information search को narrow करती है।
  2. equals() logical equality confirm करता है।

11. एक जरूरी equals-hashCode Contract#

अगर दो objects equals() के अनुसार equal हैं, तो उनका hashCode() भी same होना चाहिए।

Conceptually:

यदि:

JAVA
a.equals(b)

true है, तो:

JAVA
a.hashCode() == b.hashCode()

भी होना चाहिए।

उल्टा rule जरूरी नहीं है।

Same hash code वाले दो objects अलग भी हो सकते हैं।

यहीं से hash collision की concept आती है।

12. String के साथ Duplicate Detection#

String class पहले से meaningful equals() और hashCode() behavior देती है।

इसलिए:

JAVA
Set<String> names = new HashSet<>();

System.out.println(names.add("Amit"));
System.out.println(names.add("Amit"));

Expected Output#

TEXT
true
false

दूसरा "Amit" logically पहले वाले "Amit" के बराबर है।

इसलिए duplicate reject होता है।

13. contains() से Membership Check करना#

contains() यह बताता है कि equivalent element set में मौजूद है या नहीं।

JAVA
import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        Set<String> courses = new HashSet<>();

        courses.add("Java");
        courses.add("SQL");

        System.out.println(courses.contains("Java"));
        System.out.println(courses.contains("Python"));
    }
}

Expected Output#

TEXT
true
false

contains("Java") के लिए matching element मौजूद है।

contains("Python") के लिए matching element मौजूद नहीं है।

contains() भी hash-based lookup का benefit लेता है।

इसलिए अच्छे hash distribution के साथ membership checking generally बहुत fast होती है।

14. remove() से Element हटाना#

remove() matching element को set से हटाने की कोशिश करता है।

यह भी boolean return करता है।

JAVA
import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        Set<String> skills = new HashSet<>();

        skills.add("Java");
        skills.add("SQL");

        System.out.println(skills.remove("Java"));
        System.out.println(skills.remove("Python"));
        System.out.println(skills.size());
    }
}

Expected Output#

TEXT
true
false
1

पहले call में "Java" मौजूद था, इसलिए remove हुआ और true मिला।

दूसरे call में "Python" था ही नहीं, इसलिए false मिला।

15. size()#

size() वर्तमान में मौजूद elements की संख्या देता है।

JAVA
Set<Integer> numbers = new HashSet<>();

numbers.add(10);
numbers.add(20);
numbers.add(10);

System.out.println(numbers.size());

Expected Output#

TEXT
2

Duplicate 10 दूसरी entry नहीं बनाता।

इसलिए size 2 है।

16. isEmpty()#

isEmpty() यह check करता है कि set में कोई element है या नहीं।

JAVA
Set<String> names = new HashSet<>();

System.out.println(names.isEmpty());

names.add("Amit");

System.out.println(names.isEmpty());

Expected Output#

TEXT
true
false

Empty set के लिए result true है।

Element add करने के बाद result false हो जाता है।

17. clear()#

clear() set के सभी elements remove कर देता है।

JAVA
Set<String> names = new HashSet<>();

names.add("Amit");
names.add("Ravi");

names.clear();

System.out.println(names.size());
System.out.println(names.isEmpty());

Expected Output#

TEXT
0
true

clear() के बाद set object अभी भी मौजूद है।

बस उसके elements remove हो गए हैं।

18. HashSet में null#

HashSet एक null element support करता है।

ध्यान दीजिए: एक null।

क्यों?

क्योंकि set duplicates allow नहीं करता।

दो बार null add करने पर दूसरी बार नया unique element नहीं बनता।

JAVA
import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        Set<String> values = new HashSet<>();

        System.out.println(values.add(null));
        System.out.println(values.add(null));
        System.out.println(values.size());
    }
}

Expected Output#

TEXT
true
false
1

पहला null नया element था।

दूसरा null duplicate माना गया।

Remember

HashSet एक null रख सकता है, लेकिन repeated null अलग-अलग elements नहीं बनते।

19. HashSet Order की Guarantee नहीं देता#

यह बहुत common beginner mistake है।

मान लीजिए आपने values इस क्रम में add कीं:

  1. "Java"
  2. "SQL"
  3. "Python"

इससे यह guarantee नहीं मिलती कि iteration के समय values इसी क्रम में मिलेंगी।

HashSet का contract insertion order या encounter order preserve करने का promise नहीं करता।

इसलिए ऐसा code:

JAVA
for (String skill : skills) {
    System.out.println(skill);
}

चलने पर जो order दिखे, उसे application logic का आधार नहीं बनाना चाहिए।

Common Mistake

किसी particular run में HashSet expected order में print हो गया, इसलिए यह मान लेना गलत है कि वही order हमेशा रहेगा।

20. Iteration Order समय के साथ बदल भी सकता है#

HashSet का observed order कई factors से प्रभावित हो सकता है।

उदाहरण के लिए:

  • elements add या remove होना,
  • internal capacity बदलना,
  • hash distribution बदलना,
  • implementation details बदलना

iteration order को प्रभावित कर सकते हैं।

इसलिए:

आज जो order दिखाई दिया, वह future में भी रहेगा — ऐसी assumption मत बनाइए।

अगर business requirement order पर depend करती है, तो plain HashSet की unspecified order को contract मत मानिए।

21. Hash-Based Lookup का Mental Model#

अब contains() को high level पर समझते हैं।

मान लीजिए:

JAVA
set.contains(value);

Conceptually HashSet ऐसा काम करता है:

Visual Diagram80%

Rendering diagram…

इसका फायदा यह है कि implementation को हर element को शुरुआत से अंत तक sequentially compare करने की जरूरत सामान्यतः नहीं पड़ती।

यही hash-based collections की performance का core idea है।

22. Hash Code केवल Equality Decide नहीं करता#

यह distinction interview में बहुत important है।

मान लीजिए दो अलग objects का same hash code आ गया।

क्या वे automatically equal हैं?

नहीं।

Same hash code केवल इतना बताता है कि दोनों hash-based processing में same candidate area में आ सकते हैं।

Final logical equality के लिए equals() जरूरी है।

इसे याद रखें:

Key Idea

Same objects according to equals() must have compatible same hash codes, लेकिन same hash code का अर्थ automatically equal objects नहीं है।

23. Hash Collision क्या है?#

जब दो unequal objects का hash code same हो जाए, या hashing के बाद वे same internal bucket/location के candidates बन जाएँ, तो इसे broadly hash collision से समझा जा सकता है।

उदाहरण के लिए:

  • Object A
  • Object B

दोनों अलग हैं।

लेकिन उनकी hash-based location collide कर सकती है।

ऐसी स्थिति में HashSet केवल hash देखकर यह नहीं कह सकता कि दोनों duplicate हैं।

उसे equality comparison भी करना पड़ता है।

इसलिए collision होने पर equals() की भूमिका बहुत महत्वपूर्ण हो जाती है।

Remember

Collision का अर्थ duplicate होना नहीं है।

24. Custom Object के साथ Problem कहाँ आती है?#

Built-in classes जैसे String equality behavior पहले से properly define करती हैं।

लेकिन custom class में आपको सोचना पड़ता है कि दो objects logically same कब माने जाएँ।

मान लीजिए हमारे पास employee है और business rule कहता है कि same employee ID वाले employees logically same हैं।

JAVA
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

class Employee {
    private final int id;
    private final String name;

    Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (!(obj instanceof Employee other)) {
            return false;
        }

        return id == other.id;
    }

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

public class Main {
    public static void main(String[] args) {
        Set<Employee> employees = new HashSet<>();

        System.out.println(employees.add(new Employee(101, "Amit")));
        System.out.println(employees.add(new Employee(101, "Amit Kumar")));
        System.out.println(employees.size());
    }
}

Expected Output#

TEXT
true
false
1

यहाँ दोनों objects memory में अलग objects हैं।

लेकिन हमारे equals() rule के अनुसार दोनों का id 101 है।

इसलिए वे logically equal हैं।

hashCode() भी उसी equality-relevant field id पर based है।

इसलिए HashSet दूसरे employee को duplicate के रूप में पहचान सकता है।

25. equals() और hashCode() दोनों सही क्यों होने चाहिए?#

मान लीजिए आपने equals() में कहा:

दो employees same हैं अगर उनका id same है।

लेकिन hashCode() को ऐसी information पर based किया जो equality के साथ consistent नहीं है।

तब logically equal objects अलग hash locations की तरफ जा सकते हैं।

इससे hash-based collection का expected behavior टूट सकता है।

इसलिए practical rule:

जिन fields को logical equality के लिए use कर रहे हैं, hashCode() भी उनके साथ consistent होना चाहिए।

Interview Point

If equals() is overridden for value-based equality, hashCode() must also be overridden consistently for correct behavior in hash-based collections.

26. Equality-Relevant State Mutate करना क्यों Dangerous है?#

यह HashSet का subtle लेकिन बहुत important trap है।

मान लीजिए किसी object का id उसके equals() और hashCode() में use होता है।

Object को HashSet में add करते समय उसका id 101 है।

उस समय object hash information के आधार पर एक internal location में रखा गया।

बाद में आपने उसी object का id बदलकर 202 कर दिया।

अब उस object का नया hashCode() अलग हो सकता है।

लेकिन object physically उस old hash-based location में पड़ा है जहाँ उसे पुराने hash के आधार पर रखा गया था।

अब lookup गलत direction में जा सकता है।

इसे code से समझिए।

JAVA
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

class User {
    private int id;

    User(int id) {
        this.id = id;
    }

    void setId(int id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (!(obj instanceof User other)) {
            return false;
        }

        return id == other.id;
    }

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

public class Main {
    public static void main(String[] args) {
        Set<User> users = new HashSet<>();

        User user = new User(101);
        users.add(user);

        System.out.println(users.contains(user));

        user.setId(202);

        System.out.println(users.contains(user));
        System.out.println(users.remove(user));
        System.out.println(users.size());
    }
}

Expected Output#

TEXT
true
false
false
1

यह result पहली बार देखकर अजीब लग सकता है।

Object set में physically मौजूद है।

फिर भी mutation के बाद contains() उसे नहीं ढूँढ पा रहा।

क्यों?

क्योंकि equality-relevant state बदलने से उसका hash-based identity बदल गया।

Lookup नई hash information से search करता है, जबकि stored entry पुराने hash के आधार पर रखी गई थी।

Warning

HashSet में object डालने के बाद उन fields को बदलना avoid करें जो equals() या hashCode() को प्रभावित करती हैं।

Practical design में equality-relevant fields को immutable रखना अक्सर safer होता है।

27. Initial Capacity क्या है?#

Hash-based structure को internally storage space manage करना पड़ता है।

initial capacity roughly उस starting hash-table capacity को configure करने का तरीका है जिसके साथ collection growth planning शुरू करती है।

आप constructor में capacity दे सकते हैं:

JAVA
Set<String> values = new HashSet<>(32);

इसका अर्थ यह नहीं है कि आपने set में पहले से 32 elements डाल दिए।

size() अभी भी 0 है।

JAVA
import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        Set<String> values = new HashSet<>(32);

        System.out.println(values.size());
    }
}

Expected Output#

TEXT
0

Capacity और size अलग concepts हैं।

Size#

वास्तव में कितने elements मौजूद हैं।

Capacity#

Internal hash table की storage organization से जुड़ा concept है।

Common Mistake

new HashSet<>(100) का अर्थ 100 elements वाला set बनाना नहीं है।

28. Load Factor क्या है?#

Load factor यह तय करने में मदद करता है कि internal hash table को कब grow करना चाहिए।

Default load factor सामान्यतः 0.75 होता है।

High-level idea:

अगर capacity 16 हो और load factor 0.75 हो, तो threshold लगभग:

16 × 0.75 = 12

के आसपास होगा।

जब stored entries उस threshold को पार करने लगती हैं, internal structure को अधिक capacity की जरूरत पड़ सकती है।

इसका उद्देश्य balance बनाना है:

  • बहुत कम capacity → ज्यादा collisions हो सकती हैं।
  • बहुत ज्यादा unused capacity → memory waste हो सकती है।

0.75 सामान्य-purpose compromise है।

29. Custom Load Factor#

Constructor में initial capacity और load factor दोनों दिए जा सकते हैं:

JAVA
Set<String> values = new HashSet<>(32, 0.75f);

लेकिन beginner applications में manually load factor tune करना सामान्यतः जरूरी नहीं होता।

Default behavior अक्सर पर्याप्त होता है।

जब तक आपको real performance requirement और measured reason न हो, केवल optimization के नाम पर random capacity/load factor values बदलना useful नहीं है।

30. Capacity Growth High Level पर कैसे होती है?#

जैसे-जैसे elements बढ़ते हैं, internal hash table पर load बढ़ता है।

जब configured threshold cross होता है, implementation capacity बढ़ा सकती है और entries को नई table organization के अनुसार distribute कर सकती है।

High-level flow:

Visual Diagram80%

Rendering diagram…

Resize free operation नहीं है।

इसलिए अगर आपको पहले से पता है कि बहुत बड़ी संख्या में elements आने वाले हैं, तो suitable initial capacity कुछ situations में unnecessary resizing कम कर सकती है।

लेकिन premature tuning की जगह measured requirement को priority दें।

31. Expected Performance#

Good hash distribution और सामान्य conditions में common HashSet operations की expected performance:

Operation Expected Time
add() O(1)
contains() O(1)
remove() O(1)

यह expected या average-style behavior है।

इसे यह समझकर मत पढ़िए कि हर situation में हर operation mathematically guaranteed constant time ही होगा।

Performance hash distribution, collisions और internal state से प्रभावित हो सकती है।

32. Hash Quality Performance को कैसे प्रभावित करती है?#

मान लीजिए बहुत सारे objects खराब hashCode() implementation के कारण same hash value return करते हैं।

उदाहरण:

JAVA
@Override
public int hashCode() {
    return 1;
}

यह technically हर object के लिए integer देता है।

लेकिन distribution बहुत खराब है।

बहुत सारे elements same hash area में पहुँच सकते हैं।

फिर collection को equality confirmation के लिए अधिक candidates inspect करने पड़ सकते हैं।

इसलिए good hashCode() implementation का लक्ष्य केवल contract satisfy करना नहीं है।

अच्छा distribution performance के लिए भी useful है।

Key Idea

Good hashing elements को hash space में अच्छी तरह distribute करने में मदद करती है। Poor hashing collisions बढ़ा सकती है।

33. HashSet synchronized नहीं है#

HashSet अपने आप synchronized collection नहीं है।

इसका मतलब:

अगर multiple threads एक ही HashSet को concurrently modify कर रहे हैं, तो केवल plain HashSet use करके thread safety assume नहीं करनी चाहिए।

Single-threaded या externally controlled usage में यह problem नहीं होती।

Concurrent requirement होने पर suitable synchronization strategy या concurrent collection की जरूरत हो सकती है।

यहाँ important बात केवल इतनी है:

Remember

Plain HashSet को automatically thread-safe मत मानिए।

34. HashSet कब चुनना चाहिए?#

HashSet अच्छा choice है जब आपकी requirement मुख्य रूप से यह हो:

  • unique elements चाहिए,
  • duplicate values reject करनी हैं,
  • membership checking frequently करनी है,
  • add/remove fast expected होना चाहिए,
  • iteration order important नहीं है।

उदाहरण:

  • unique user IDs collect करना
  • duplicate email addresses detect करना
  • processed request identifiers track करना
  • unique tags रखना
  • allowed values की membership check करना

35. Practical Example — Duplicate Registration Detect करना#

मान लीजिए registration system में email addresses unique रखने हैं।

हम simplified example में HashSet<String> use कर सकते हैं।

JAVA
import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        Set<String> registeredEmails = new HashSet<>();

        boolean first = registeredEmails.add("amit@example.com");
        boolean second = registeredEmails.add("ravi@example.com");
        boolean duplicate = registeredEmails.add("amit@example.com");

        System.out.println(first);
        System.out.println(second);
        System.out.println(duplicate);
        System.out.println(registeredEmails.size());
    }
}

Expected Output#

TEXT
true
true
false
2

यहाँ add() का boolean result सीधे useful business decision दे सकता है।

अगर result false है, equivalent email पहले से set में मौजूद है।

Real application में email normalization जैसी additional business requirements हो सकती हैं, लेकिन HashSet का uniqueness mechanism यही रहता है।

36. Common Mistakes#

Mistake 1 — HashSet insertion order preserve करेगा#

गलत assumption।

HashSet iteration order guarantee नहीं करता।

Mistake 2 — add() हमेशा true देगा#

नहीं।

Duplicate equivalent element पर add() false देता है।

Mistake 3 — Same hashCode मतलब objects equal हैं#

नहीं।

Hash collision possible है।

Logical equality confirm करने के लिए equals() महत्वपूर्ण है।

Mistake 4 — equals() override किया, hashCode() नहीं किया#

Hash-based collections के लिए यह serious correctness problem पैदा कर सकता है।

दोनों को consistent रखना जरूरी है।

Mistake 5 — Set में object add करने के बाद equality field बदल दी#

इससे contains() और remove() unexpected तरीके से fail कर सकते हैं।

Mistake 6 — new HashSet<>(100) का मतलब size 100 है#

नहीं।

यह capacity configuration है।

Actual size() initially 0 रहता है।

Mistake 7 — HashSet हर situation में O(1) guarantee देता है#

नहीं।

Common operations की expected performance O(1) है, लेकिन poor hashing और collisions performance को प्रभावित कर सकते हैं।

Mistake 8 — HashSet thread-safe है#

Plain HashSet synchronized नहीं है।

37. Quick Recap#

इस chapter से सबसे important बातें:

  • HashSet unique elements store करता है।
  • यह Set का hash-based implementation है।
  • यह internally HashMap द्वारा backed होता है।
  • add() नया element add होने पर true, duplicate मिलने पर false देता है।
  • contains() membership check करता है।
  • remove() matching element remove करता है।
  • size(), isEmpty() और clear() basic state operations हैं।
  • केवल एक null element रखा जा सकता है।
  • iteration order guaranteed नहीं है।
  • hashCode() candidate location खोजने में मदद करता है।
  • equals() logical equality confirm करता है।
  • collision का अर्थ duplicate नहीं है।
  • equal objects के hash codes consistent होने चाहिए।
  • equality-related mutable fields HashSet के अंदर dangerous हो सकती हैं।
  • initial capacity और load factor internal resizing behavior से जुड़े हैं।
  • add(), contains() और remove() की expected performance सामान्यतः O(1) है।
  • poor hash distribution performance खराब कर सकती है।
  • plain HashSet synchronized नहीं है।
  • uniqueness चाहिए लेकिन order की जरूरत नहीं है, तो HashSet strong candidate है।

38. Interview Preparation#

How does HashSet detect duplicate elements?Show Answer

HashSet uses hash-based lookup together with hashCode() and equals(). The hash code helps locate candidate entries, and equals() confirms logical equality. If an equivalent element already exists, add() does not insert another element and returns false.

Key Points:

  • hashCode() helps narrow the lookup.
  • equals() confirms logical equality.
  • Duplicate insertion does not increase the set size.
  • add() returns false when an equivalent element already exists.

Why interviewer asks this:

The interviewer wants to verify that you understand HashSet beyond the simple statement that it stores unique values.


Why must equals() and hashCode() be consistent when objects are stored in a HashSet?Show Answer

Hash-based collections use the hash code to locate candidate entries and equals() to confirm equality. If two objects are equal according to equals() but produce inconsistent hash codes, the collection may search in the wrong hash location and fail to recognize logically equal objects correctly.

Key Points:

  • Equal objects must produce equal hash codes.
  • The reverse is not required.
  • Same hash code does not necessarily mean equal objects.
  • Incorrect implementations can break lookup and duplicate detection.

Why interviewer asks this:

This checks whether you understand the equality contract required by hash-based collections.


Does HashSet maintain insertion order?Show Answer

No. HashSet does not guarantee insertion or iteration order. The observed order must not be relied upon because it can change when the set changes or when internal implementation details change.

Key Points:

  • No insertion-order guarantee.
  • Observed iteration order is not a contract.
  • Application logic should not depend on a particular HashSet order.

Why interviewer asks this:

The interviewer is checking whether you understand the behavioral guarantees of the collection rather than relying on accidental output from one execution.


What are the expected time complexities of add(), contains(), and remove() in HashSet?Show Answer

With a suitable hash distribution and normal operating conditions, add(), contains(), and remove() have expected O(1) time complexity. Heavy collisions or poor hash quality can reduce performance.

Key Points:

  • add() — expected O(1)
  • contains() — expected O(1)
  • remove() — expected O(1)
  • Hash quality affects practical performance.

Why interviewer asks this:

The interviewer wants to know whether you understand why HashSet is commonly selected for uniqueness and membership checks.


What problem can occur if an object is modified after being added to a HashSet?Show Answer

If fields used by equals() or hashCode() are modified while the object is inside the HashSet, its current hash may no longer correspond to the location where it was stored. As a result, operations such as contains() or remove() may fail unexpectedly.

Key Points:

  • Equality-relevant mutable state is risky.
  • The stored location was chosen using the earlier hash information.
  • Later mutation can make lookup inconsistent.
  • Immutable equality keys are generally safer.

Why interviewer asks this:

This tests practical understanding of hash-based collections and object design.

Interactive learning

Practice lab

Apply this chapter with guided activities, immediate feedback, explanations, and retry.

Practice loads when this section enters view.