Generics, Collections, and Core Data Structures

Working with `Set`

ReadingPreview

You are viewing a free preview lesson.

Lesson Overview

আগের lesson-এ আমরা List শিখেছি।

List useful যখন:

  • Element order গুরুত্বপূর্ণ
  • Index দিয়ে access করতে হবে
  • Duplicate values গ্রহণযোগ্য
  • Sequence business meaning বহন করে

কিন্তু কিছু data naturally unique।

Examples:

Course codes
User roles
Supported languages
Unique learner enrollments
Completed lesson IDs
Applied coupon codes

একজন learner একই course-এ দুইবার enrolled হওয়া উচিত নয়।

একটি course catalog-এ একই course code দুইবার থাকা উচিত নয়।

এ ধরনের requirement-এর জন্য Java provides:

Set<E>

Set:

  • Duplicate elements রাখে না
  • Index-based নয়
  • Equality-এর মাধ্যমে duplicate detect করে
  • Mutable বা immutable হতে পারে
  • Different ordering behavior-এর implementations থাকতে পারে

Common mutable implementation:

HashSet<E>

এই lesson-এ আমরা শিখব:

  • Set কী
  • HashSet
  • Unique element insertion
  • add()-এর return value
  • Searching এবং removal
  • Set iteration
  • Ordering guarantees
  • Set.of() এবং Set.copyOf()
  • equals() এবং hashCode()
  • Custom objects-এর uniqueness
  • Mutable set elements-এর risk
  • List বনাম Set
  • Unique enrollment registry design

Learning Objectives

এই lesson শেষ করার পর আপনি পারবেন:

  • Set declare এবং initialize করতে
  • HashSet ব্যবহার করতে
  • Duplicate insertion detect করতে
  • contains() এবং remove() ব্যবহার করতে
  • Set safely iterate করতে
  • HashSet ordering-এর limitation বুঝতে
  • Set.of() এবং Set.copyOf() ব্যবহার করতে
  • equals() এবং hashCode() uniqueness-এ কীভাবে কাজ করে explain করতে
  • Custom immutable set element design করতে
  • Mutable hash-based element-এর risk identify করতে
  • List এবং Set-এর মধ্যে appropriate choice নিতে

What Is a Set?

Set একটি collection যা duplicate elements রাখে না।

Set<String> courseCodes =
        new HashSet<>();

Add:

courseCodes.add(
        "JAVA-OOP"
);

courseCodes.add(
        "BACKEND"
);

courseCodes.add(
        "JAVA-OOP"
);

Set-এর content থাকবে:

JAVA-OOP
BACKEND

Second "JAVA-OOP" আলাদা duplicate element হিসেবে add হবে না।


Importing Set and HashSet

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

Declaration:

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

Variable type:

Set<String>

Implementation:

HashSet<String>

Set interface-এর ওপর depend করলে implementation detail unnecessaryভাবে expose হয় না।


Creating an Empty Mutable Set

Set<String> supportedLanguages =
        new HashSet<>();

Initially:

supportedLanguages.isEmpty()

returns:

true

And:

supportedLanguages.size()

returns:

0

Adding Elements

Use:

add(E element)

Example:

supportedLanguages.add(
        "BN"
);

supportedLanguages.add(
        "EN"
);

supportedLanguages.add(
        "ET"
);

Set now contains three unique elements।


add() Returns Whether the Set Changed

Set.add()-এর return value খুব useful।

boolean added =
        supportedLanguages.add(
                "BN"
        );

First insertion:

true

Add same value again:

boolean addedAgain =
        supportedLanguages.add(
                "BN"
        );

Result:

false

কারণ set already "BN" contains করে।

Set change হয়নি।


Using add() for Duplicate Detection

public static boolean registerCourseCode(
        Set<String> courseCodes,
        String courseCode
) {
    if (
            courseCodes == null
            || courseCode == null
            || courseCode.isBlank()
    ) {
        return false;
    }

    return courseCodes.add(
            courseCode.strip()
                    .toUpperCase()
    );
}

Usage:

Set<String> courseCodes =
        new HashSet<>();

System.out.println(
        registerCourseCode(
                courseCodes,
                "java-oop"
        )
);

System.out.println(
        registerCourseCode(
                courseCodes,
                "JAVA-OOP"
        )
);

Output:

true
false

Normalization-এর কারণে দুইটি input একই logical code হিসেবে treated হয়েছে।


Uniqueness Depends on Equality

Set duplicate decide করে values logically equal কি না।

For String:

"JAVA".equals(
        "JAVA"
)

returns:

true

তাই second "JAVA" duplicate।

But:

"JAVA".equals(
        "java"
)

returns:

false

So without normalization:

Set<String> codes =
        new HashSet<>();

codes.add(
        "JAVA"
);

codes.add(
        "java"
);

Set দুইটি values রাখতে পারে।

Domain-level normalization এখনও application responsibility।


Set Has No Index

A Set is not index-based।

Invalid:

courseCodes.get(
        0
);

Set interface-এ get() method নেই।

Also no:

set(
        index,
        value
)

কারণ set element position contract-এর অংশ নয়।

If position matters, use List


Checking Whether a Value Exists

boolean supportsBangla =
        supportedLanguages.contains(
                "BN"
        );

Result:

true

If value absent:

supportedLanguages.contains(
        "DE"
);

returns:

false

contains() equality rules use করে।


Removing an Element

boolean removed =
        supportedLanguages.remove(
                "ET"
        );

If value existed:

true

If absent:

false

Unlike List, Set.remove() index-based overload expose করে না।

remove(value)

means element value remove করা।


Set Size

int languageCount =
        supportedLanguages.size();

Duplicate insertion size increase করে না।

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

values.add(
        "JAVA"
);

values.add(
        "JAVA"
);

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

Output:

1

Clearing a Set

supportedLanguages.clear();

After clearing:

supportedLanguages.isEmpty()

returns:

true

Domain object-এর internal set direct clear করা business rules bypass করতে পারে।

Controlled methods prefer করুন।


Adding Multiple Elements

Set<String> primaryLanguages =
        new HashSet<>();

primaryLanguages.add(
        "BN"
);

Set<String> additionalLanguages =
        Set.of(
                "EN",
                "ET"
        );

primaryLanguages.addAll(
        additionalLanguages
);

Result contains:

BN
EN
ET

Existing duplicates add হলেও set size বাড়বে না।


Removing Multiple Elements

supportedLanguages.removeAll(
        Set.of(
                "ET",
                "DE"
        )
);

Matching elements remove হয়।

Missing values harmless।


Keeping Common Elements

Set<String> instructorLanguages =
        new HashSet<>(
                Set.of(
                        "BN",
                        "EN",
                        "ET"
                )
        );

Set<String> learnerLanguages =
        Set.of(
                "BN",
                "FI"
        );

instructorLanguages.retainAll(
        learnerLanguages
);

Result:

BN

retainAll() শুধু common elements রাখে।

এটি basic set intersection-এর মতো কাজ করে।


Checking Whether All Values Exist

Set<String> requiredRoles =
        Set.of(
                "INSTRUCTOR",
                "COURSE_EDITOR"
        );

Set<String> userRoles =
        Set.of(
                "INSTRUCTOR",
                "COURSE_EDITOR",
                "CONTENT_REVIEWER"
        );

boolean hasRequiredRoles =
        userRoles.containsAll(
                requiredRoles
        );

Result:

true

Iterating Over a Set

Enhanced for loop:

for (
        String language
        : supportedLanguages
) {
    System.out.println(
            language
    );
}

Unlike List, index variable নেই।

Each element once process করা হয়।


HashSet Does Not Guarantee Iteration Order

Suppose:

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

languages.add(
        "BN"
);

languages.add(
        "EN"
);

languages.add(
        "ET"
);

Printing may produce:

BN
EN
ET

or another order।

You must not assume:

Insertion order
Alphabetical order
Stable display order

HashSet-এর contract order guarantee করে না।


Do Not Depend on Current Printed Order

A small example may repeatedly print same order on one machine।

That does not make the order guaranteed।

Order can change due to:

  • Different values
  • Different Java versions
  • Internal resizing
  • Hash distribution
  • Application changes

If output order matters, choose an ordered collection deliberately।


LinkedHashSet

LinkedHashSet uniqueness এবং insertion order দুটো preserve করে।

import java.util.LinkedHashSet;
Set<String> languages =
        new LinkedHashSet<>();

languages.add(
        "BN"
);

languages.add(
        "EN"
);

languages.add(
        "ET"
);

Iteration order:

BN
EN
ET

Use when:

  • Unique values প্রয়োজন
  • Insertion orderও meaningful

Variable type still:

Set<String>

Implementation:

new LinkedHashSet<>()

TreeSet: Brief Introduction

TreeSet unique values sorted order-এ রাখতে পারে।

import java.util.TreeSet;
Set<String> languages =
        new TreeSet<>();

languages.add(
        "ET"
);

languages.add(
        "BN"
);

languages.add(
        "EN"
);

Iteration:

BN
EN
ET

But element types must have a natural ordering or supplied comparator।

Detailed sorting এবং comparators later শেখানো হবে।

For now:

HashSet       → No ordering guarantee
LinkedHashSet → Insertion order
TreeSet       → Sorted order

Creating an Immutable Set with Set.of()

Set<String> supportedLanguages =
        Set.of(
                "BN",
                "EN",
                "ET"
        );

This set:

  • Cannot be structurally modified
  • Does not allow null
  • Does not allow duplicate arguments
  • Does not guarantee a particular iteration order

Modifying Set.of()

supportedLanguages.add(
        "FI"
);

Runtime-এ throws:

UnsupportedOperationException

Also:

supportedLanguages.remove(
        "BN"
);

fails।


Duplicate Arguments in Set.of()

Set<String> values =
        Set.of(
                "JAVA",
                "JAVA"
        );

Runtime-এ throws:

IllegalArgumentException

Unlike HashSet.add(), which returns false for a duplicate, Set.of() rejects duplicate construction input।


Null in Set.of()

Set<String> values =
        Set.of(
                "JAVA",
                null
        );

Throws:

NullPointerException

Creating an Immutable Copy

Set<String> copy =
        Set.copyOf(
                supportedLanguages
        );

The returned set cannot be structurally changed।

copy.add(
        "FI"
);

throws:

UnsupportedOperationException

Set.copyOf() and Duplicates

If source is a collection with duplicates:

List<String> values =
        List.of(
                "JAVA",
                "JAVA",
                "SPRING"
        );

Then:

Set<String> uniqueValues =
        Set.copyOf(
                values
        );

Result contains unique elements:

JAVA
SPRING

Unlike Set.of("JAVA", "JAVA"), copying a general collection collapses duplicate elements according to set semantics।

Do not rely on its iteration order।


Mutable Copy of an Immutable Set

Set<String> mutableLanguages =
        new HashSet<>(
                Set.of(
                        "BN",
                        "EN"
                )
        );

Now:

mutableLanguages.add(
        "ET"
);

works।


How HashSet Finds Elements

HashSet uses two important methods:

hashCode()
equals()

High-level process:

1. hashCode() helps find a possible storage location
2. equals() confirms whether an equal element already exists

Both methods must follow a valid contract।


The Equality Contract for Hash-Based Collections

Most important rule:

If two objects are equal according to equals(), they must return the same hashCode().

Formally:

first.equals(
        second
)

is true, then:

first.hashCode()
        == second.hashCode()

must also be true

The reverse is not required।

Two unequal objects may have the same hash code।

That situation is called a hash collision।

equals() then distinguishes them।


Strings Already Implement Equality Correctly

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

String provides compatible:

equals()
hashCode()

So logically equal strings behave correctly in a set।

Java wrapper classes and many standard immutable types also implement these methods appropriately।


Custom Objects Without equals() and hashCode()

Consider:

public final class CourseCode {

    private final String value;

    public CourseCode(
            String value
    ) {
        this.value =
                value.strip()
                        .toUpperCase();
    }
}

Create two objects:

CourseCode first =
        new CourseCode(
                "java-oop"
        );

CourseCode second =
        new CourseCode(
                "JAVA-OOP"
        );

Logically they represent the same code।

But without overriding equality:

first.equals(
        second
)

usually returns:

false

because default Object.equals() compares identity।


Duplicate Logical Values Can Enter the Set

Set<CourseCode> courseCodes =
        new HashSet<>();

courseCodes.add(
        first
);

courseCodes.add(
        second
);

Without custom equality, size may be:

2

Even though both represent:

JAVA-OOP

Set only enforces uniqueness according to the element’s equality contract।


Implementing equals() and hashCode()

import java.util.Objects;

public final class CourseCode {

    private final String value;

    public CourseCode(
            String value
    ) {
        if (
                value == null
                || value.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Course code is required."
            );
        }

        this.value =
                value.strip()
                        .toUpperCase();
    }

    public String getValue() {
        return value;
    }

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

        if (
                !(other
                instanceof CourseCode courseCode)
        ) {
            return false;
        }

        return value.equals(
                courseCode.value
        );
    }

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

    @Override
    public String toString() {
        return value;
    }
}

Now:

CourseCode first =
        new CourseCode(
                "java-oop"
        );

CourseCode second =
        new CourseCode(
                "JAVA-OOP"
        );
first.equals(
        second
);

returns:

true

And both have compatible hash codes।


Set Now Rejects the Logical Duplicate

Set<CourseCode> courseCodes =
        new HashSet<>();

System.out.println(
        courseCodes.add(
                first
        )
);

System.out.println(
        courseCodes.add(
                second
        )
);

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

Output:

true
false
1

This is value-based uniqueness।


Why hashCode() Must Match equals()

Bad class:

@Override
public boolean equals(
        Object other
) {
    // Compares course code value
}

@Override
public int hashCode() {
    return super.hashCode();
}

Two logically equal objects may get different identity-based hash codes।

HashSet may look in different locations and fail to detect the duplicate।

Result:

Logically equal values coexist unexpectedly
contains() may fail
remove() may fail

Always override both together when equality is value-based।


Do Not Use Random Values in hashCode()

Wrong:

@Override
public int hashCode() {
    return (int) (
            Math.random()
            * 1_000
    );
}

Hash code must remain consistent while equality-relevant state remains unchanged।

Same object changing hash code across calls breaks hash-based collections।


Mutable Elements Are Dangerous in HashSet

Consider a mutable class:

public final class MutableCourseCode {

    private String value;

    public void changeValue(
            String value
    ) {
        this.value = value;
    }

    @Override
    public boolean equals(
            Object other
    ) {
        // Compares value
    }

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

Add:

MutableCourseCode code =
        new MutableCourseCode(
                "JAVA"
        );

Set<MutableCourseCode> codes =
        new HashSet<>();

codes.add(
        code
);

Then mutate equality-relevant state:

code.changeValue(
        "SPRING"
);

Object was stored using old hash:

JAVA hash

Now it produces:

SPRING hash

Lookup Can Fail After Mutation

codes.contains(
        code
);

may unexpectedly return:

false

And:

codes.remove(
        code
);

may fail।

The object still physically exists inside the set, but its equality/hash identity changed after insertion।


Prefer Immutable Set Elements

Strong design:

public final class CourseCode {

    private final String value;
}

No setter।

Equality-relevant state cannot change।

Useful immutable set elements include:

CourseCode
EnrollmentKey
UserRole
LanguageCode
LessonId

If an object must be mutable, avoid changing fields used by equals() and hashCode() while it belongs to a hash-based collection।


Entity Equality Requires Care

Suppose Course equality uses:

ID

and ID is stable।

Then mutable title may not affect hash-based membership।

But if equality uses mutable title:

title

renaming the course can break set lookup।

Practical guideline:

Hash-based equality should rely on stable identity or immutable value state.

Equality design is a domain decision, not only a technical method-generation task।


Set Equality

Two sets are generally equal when they contain the same elements, regardless of iteration order।

Set<String> first =
        Set.of(
                "BN",
                "EN"
        );

Set<String> second =
        Set.of(
                "EN",
                "BN"
        );
first.equals(
        second
);

returns:

true

This differs from List equality, where order matters।


List Equality vs Set Equality

Lists:

List.of(
        "BN",
        "EN"
).equals(
        List.of(
                "EN",
                "BN"
        )
);

returns:

false

Sets:

Set.of(
        "BN",
        "EN"
).equals(
        Set.of(
                "EN",
                "BN"
        )
);

returns:

true

Because list models sequence।

Set models membership।


Null in HashSet

HashSet permits one null element।

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

values.add(
        null
);

values.add(
        null
);

Size:

1

But allowing null often complicates processing।

for (
        String value
        : values
) {
    value.toUpperCase();
}

can throw:

NullPointerException

Unless null has deliberate domain meaning, reject it।


Uniqueness Is Not Complete Business Protection

A Set prevents duplicates within one in-memory collection instance।

It does not automatically protect against:

  • Two application servers inserting concurrently
  • Database duplicate rows
  • Multiple processes
  • Restarted application state
  • Race conditions
  • Distributed requests

Production uniqueness may also require:

Database unique constraint
Transactional check
Idempotency
Concurrency control

Set is an in-memory data structure, not a complete distributed consistency mechanism।


Performance Mental Model

HashSet is designed for fast:

add
contains
remove

Average lookup is commonly described as near constant time।

But actual behavior depends on:

  • Good hashCode()
  • Number of collisions
  • Collection size
  • Runtime implementation
  • Element equality cost

Do not choose a set only from Big-O memorization।

Choose it first because uniqueness and membership match the domain requirement।


Complete Example: Unique Enrollment Registry

একজন learner একই course-এ শুধু একবার enrolled হতে পারবে।

Uniqueness key:

learnerId + courseId

We will model it with an immutable value object।


EnrollmentKey.java

import java.util.Objects;

public final class EnrollmentKey {

    private final long learnerId;
    private final long courseId;

    public EnrollmentKey(
            long learnerId,
            long courseId
    ) {
        if (learnerId <= 0) {
            throw new IllegalArgumentException(
                    "Learner ID must be positive."
            );
        }

        if (courseId <= 0) {
            throw new IllegalArgumentException(
                    "Course ID must be positive."
            );
        }

        this.learnerId = learnerId;
        this.courseId = courseId;
    }

    public long getLearnerId() {
        return learnerId;
    }

    public long getCourseId() {
        return courseId;
    }

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

        if (
                !(other
                instanceof EnrollmentKey key)
        ) {
            return false;
        }

        return learnerId
                == key.learnerId
                && courseId
                == key.courseId;
    }

    @Override
    public int hashCode() {
        return Objects.hash(
                learnerId,
                courseId
        );
    }

    @Override
    public String toString() {
        return "EnrollmentKey{"
                + "learnerId="
                + learnerId
                + ", courseId="
                + courseId
                + '}';
    }
}

EnrollmentRegistry.java

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

public final class EnrollmentRegistry {

    private final Set<EnrollmentKey> enrollments;

    public EnrollmentRegistry() {
        this.enrollments =
                new HashSet<>();
    }

    public boolean enroll(
            long learnerId,
            long courseId
    ) {
        EnrollmentKey key =
                new EnrollmentKey(
                        learnerId,
                        courseId
                );

        return enrollments.add(
                key
        );
    }

    public boolean isEnrolled(
            long learnerId,
            long courseId
    ) {
        EnrollmentKey key =
                new EnrollmentKey(
                        learnerId,
                        courseId
                );

        return enrollments.contains(
                key
        );
    }

    public boolean cancelEnrollment(
            long learnerId,
            long courseId
    ) {
        EnrollmentKey key =
                new EnrollmentKey(
                        learnerId,
                        courseId
                );

        return enrollments.remove(
                key
        );
    }

    public int getEnrollmentCount() {
        return enrollments.size();
    }

    public Set<EnrollmentKey> getEnrollments() {
        return Set.copyOf(
                enrollments
        );
    }
}

Main.java

public class Main {

    public static void main(
            String[] args
    ) {
        EnrollmentRegistry registry =
                new EnrollmentRegistry();

        boolean firstEnrollment =
                registry.enroll(
                        101L,
                        501L
                );

        boolean duplicateEnrollment =
                registry.enroll(
                        101L,
                        501L
                );

        boolean anotherCourse =
                registry.enroll(
                        101L,
                        502L
                );

        boolean anotherLearner =
                registry.enroll(
                        102L,
                        501L
                );

        System.out.println(
                "First enrollment: "
                + firstEnrollment
        );

        System.out.println(
                "Duplicate enrollment: "
                + duplicateEnrollment
        );

        System.out.println(
                "Another course: "
                + anotherCourse
        );

        System.out.println(
                "Another learner: "
                + anotherLearner
        );

        System.out.println(
                "Enrollment count: "
                + registry
                        .getEnrollmentCount()
        );

        System.out.println(
                "Learner 101 enrolled in course 501: "
                + registry.isEnrolled(
                        101L,
                        501L
                )
        );

        boolean cancelled =
                registry.cancelEnrollment(
                        101L,
                        501L
                );

        System.out.println(
                "Cancelled: "
                + cancelled
        );

        System.out.println(
                "Enrollment count after cancellation: "
                + registry
                        .getEnrollmentCount()
        );
    }
}

Possible output:

First enrollment: true
Duplicate enrollment: false
Another course: true
Another learner: true
Enrollment count: 3
Learner 101 enrolled in course 501: true
Cancelled: true
Enrollment count after cancellation: 2

Why Duplicate Enrollment Was Rejected

First call creates:

new EnrollmentKey(
        101L,
        501L
)

Second call creates another object with same values।

They are different object references।

But:

equals()

returns true because learner ID and course ID match।

And:

hashCode()

is compatible।

Therefore HashSet.add() returns:

false

for the second object।


Why EnrollmentKey Is Immutable

Fields:

private final long learnerId;
private final long courseId;

No setters।

Once added to HashSet, equality-relevant state cannot change।

This protects lookup behavior।


Why the Getter Returns Set.copyOf()

Weak:

public Set<EnrollmentKey> getEnrollments() {
    return enrollments;
}

Caller could:

registry.getEnrollments()
        .clear();

and bypass registry rules।

Safer:

return Set.copyOf(
        enrollments
);

Caller gets an immutable structural copy।


When to Use Set

Use Set when:

  • Duplicate values are invalid or meaningless
  • Membership check is important
  • Index access is unnecessary
  • Order is irrelevant or separately specified
  • Elements have stable equality semantics

Examples:

User roles
Course codes
Completed lesson IDs
Unique tags
Enrollment keys
Supported currencies
Feature permissions

When Set May Not Be Best

If requirements need:

Sequence
Position
Duplicate occurrences

use List

If requirements need:

Lookup from key to associated value

use Map

If requirements need:

Unique values in insertion order

consider LinkedHashSet

If requirements need:

Unique sorted values

consider TreeSet


List vs Set

RequirementListSet
Preserves sequenceYesDepends on implementation
Index accessYesNo
Allows duplicatesYesNo
Membership-focusedPossibleNatural
Equality mattersYesYes
Unique elementsManual ruleBuilt-in contract
Multiple equal occurrencesSupportedNot supported

Domain Choice Example

Course Lesson Sequence

List<Lesson>

Because:

  • Order matters
  • Same lesson position matters
  • Index may be useful

User Roles

Set<Role>

Because:

  • Duplicate INSTRUCTOR role has no meaning
  • Membership check matters
  • Position usually irrelevant

Learner Activity History

List<Activity>

Because:

  • Repeated activities valid
  • Chronological sequence matters

Completed Lesson IDs

Set<Long>

Because:

  • A lesson is either completed or not
  • Duplicate completion ID adds no meaning

Common Mistakes

Expecting Index Access

set.get(
        0
);

Set has no index contract।


Depending on HashSet Iteration Order

Current output order is not guaranteed।


Forgetting to Check add() Result

The return value can directly indicate duplicate insertion।


Overriding equals() Without hashCode()

Hash-based lookup and duplicate detection become unreliable।


Using Mutable Equality Fields

Changing a field used by hashCode() after insertion may make the element unreachable।


Assuming Set Understands Domain Normalization

JAVA
java

remain distinct unless normalized or equality handles case-insensitivity।


Returning an Internal Mutable Set

Caller can bypass domain operations।


Using Set.of() and Then Mutating It

It throws UnsupportedOperationException


Passing Duplicate Values to Set.of()

It throws IllegalArgumentException


Assuming Set Solves Database Uniqueness

It only controls one in-memory collection।


Using Set When Order Is Business-Critical

Choose List, LinkedHashSet, or another explicit ordered model।


Practice Exercises

Exercise 1: Unique Course Codes

Create:

Set<String> courseCodes

Requirements:

  • Normalize with strip() and toUpperCase()
  • Reject blank input
  • Return false for duplicates
  • Print final count

Exercise 2: User Roles

Create:

Set<String> roles

Add:

LEARNER
INSTRUCTOR
LEARNER
CONTENT_EDITOR

Predict and verify size।


Exercise 3: Immutable Supported Currencies

Create an immutable set:

BDT
EUR
USD

Verify add operation fails।


Exercise 4: Implement CourseCode

Create an immutable value object with:

value
equals()
hashCode()
toString()

Verify:

new CourseCode(
        "java"
)

and:

new CourseCode(
        "JAVA"
)

behave as one set element।


Exercise 5: Explain Mutation Risk

Create a mutable object whose name field is used by:

equals()
hashCode()

Add it to HashSet, change the name, then test:

contains()
remove()

Explain the unexpected behavior।


Exercise 6: Choose the Collection

Choose List, HashSet, or LinkedHashSet:

  1. Course lesson order
  2. Unique user permissions
  3. Unique tags displayed in insertion order
  4. Learner activity history
  5. Completed content IDs
  6. Playlist where duplicate songs are allowed

Explain each choice।


Exercise 7: Extend the Enrollment Registry

Add:

public Set<Long> findCourseIdsByLearnerId(
        long learnerId
)

Requirements:

  • Return unique course IDs
  • Do not expose mutable internal state
  • Return empty set when none found

Predict the Result

Question 1

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

System.out.println(
        values.add(
                "JAVA"
        )
);

System.out.println(
        values.add(
                "JAVA"
        )
);

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

Question 2

Set<String> values =
        Set.of(
                "JAVA",
                "JAVA"
        );

What happens?


Question 3

Set<String> values =
        Set.of(
                "BN",
                "EN"
        );

values.remove(
        "BN"
);

What happens?


Question 4

Set<String> first =
        Set.of(
                "BN",
                "EN"
        );

Set<String> second =
        Set.of(
                "EN",
                "BN"
        );

System.out.println(
        first.equals(
                second
        )
);

Question 5

Two custom objects have equal field values but do not override equals() or hashCode()

Can both enter a HashSet?


Question 6

An object’s hash-relevant field changes after insertion into a HashSet

Can contains() unexpectedly fail?


Predict the Result Answers

Answer 1

true
false
1

Answer 2

Runtime-এ:

IllegalArgumentException

Duplicate arguments are not allowed।

Answer 3

Runtime-এ:

UnsupportedOperationException

Set.of() immutable।

Answer 4

true

Set equality element membership compare করে, order নয়।

Answer 5

হ্যাঁ।

Default equality normally compares object identity।

Answer 6

হ্যাঁ।

Object may now hash to a different location than where it was stored।


Knowledge Check

Question 1

Set-এর primary characteristic কী?

Question 2

HashSet.add() কী return করে?

Question 3

Set কি index-based?

Question 4

HashSet insertion order guarantee করে কি?

Question 5

Which set implementation preserves insertion order?

Question 6

Set.of() mutable কি?

Question 7

Set.of() duplicate arguments accept করে কি?

Question 8

HashSet duplicate detection-এ কোন methods গুরুত্বপূর্ণ?

Question 9

Equal objects-এর hash code সম্পর্কে rule কী?

Question 10

Same hash code কি objects equal হওয়া guarantee করে?

Question 11

Custom value object-এর জন্য শুধু equals() override করা যথেষ্ট কি?

Question 12

Mutable equality state hash set-এর জন্য risky কেন?

Question 13

Set equality-তে order matter করে কি?

Question 14

List এবং Set-এর central difference কী?

Question 15

Set কি database-level uniqueness guarantee করে?


Knowledge Check Answers

Answer 1

Duplicate elements রাখে না।

Answer 2

Set changed হলে true, equal element already থাকলে false

Answer 3

না।

Answer 4

না।

Answer 5

LinkedHashSet

Answer 6

না।

Answer 7

না। Duplicate থাকলে IllegalArgumentException হয়।

Answer 8

hashCode() এবং equals()

Answer 9

Objects equal হলে তাদের hash codes same হতে হবে।

Answer 10

না।

Unequal objects একই hash code রাখতে পারে।

Answer 11

না।

Compatible hashCode()-ও override করতে হবে।

Answer 12

Mutation-এর পরে object অন্য hash location produce করতে পারে, ফলে lookup/remove fail করতে পারে।

Answer 13

না।

Same members থাকলে sets equal হতে পারে।

Answer 14

List sequence এবং duplicates model করে। Set unique membership model করে।

Answer 15

না।

Database constraints এবং concurrency protection separately প্রয়োজন হতে পারে।


Lesson Summary

এই lesson-এ আমরা শিখেছি:

  • Set unique elements store করে
  • Set একটি generic interface
  • HashSet common mutable implementation
  • add() duplicate insertion detect করতে boolean return করে
  • Duplicate insertion set size increase করে না
  • Set index-based নয়
  • contains() membership check করে
  • remove() element value remove করে
  • addAll(), removeAll(), retainAll(), এবং containsAll() set operations support করে
  • Enhanced for দিয়ে set iterate করা যায়
  • HashSet order guarantee করে না
  • LinkedHashSet insertion order preserve করে
  • TreeSet sorted uniqueness provide করতে পারে
  • Set.of() immutable set তৈরি করে
  • Set.of() duplicate এবং null reject করে
  • Set.copyOf() immutable unique copy তৈরি করে
  • Set uniqueness element equality-এর ওপর depend করে
  • HashSet hashCode() দিয়ে location narrow করে এবং equals() দিয়ে equality confirm করে
  • Equal objects must have equal hash codes
  • Same hash code equal objects guarantee করে না
  • Custom logical values-এর জন্য equals() এবং hashCode() override করা প্রয়োজন
  • Hash-relevant mutable state collection behavior break করতে পারে
  • Immutable value objects strong set elements
  • Set equality order-independent
  • List equality order-sensitive
  • Null elements deliberate policy ছাড়া avoid করা ভালো
  • Set in-memory uniqueness দেয়, distributed বা database uniqueness নয়
  • List sequence model করে
  • Set unique membership model করে
  • Collection choice domain meaning এবং required operations থেকে আসা উচিত

Next Lesson

পরবর্তী lesson:

Working with Map

আমরা শিখব:

  • Key-value relationships
  • HashMap
  • Unique keys
  • put(), get(), এবং remove()
  • Replacing existing values
  • containsKey() এবং containsValue()
  • Missing keys এবং null
  • getOrDefault()
  • Iterating keys, values, and entries
  • Key equality and hashCode()
  • Mutable key risks
  • Course code দিয়ে course lookup
  • Learner ID দিয়ে enrollment lookup