Generics, Collections, and Core Data Structures
Practice and Assessment
আপনি একটি free preview lesson দেখছেন।
Project Overview
এই final project-এ আমরা একটি simplified LiveKlass learning platform model তৈরি করব।
Systemটি support করবে:
- Unique course codes
- Registration-order course catalog
- Course-এর ordered lessons
- Duplicate lesson prevention
- Course lookup by code
- Unique learner enrollments
- Learner অনুযায়ী enrolled courses
- Course অনুযায়ী enrollment counting
- Defensive copying
- Immutable collection snapshots
এই project-এ Module 4-এর core concepts একসঙ্গে ব্যবহার করা হবে:
Generics
List
Set
Map
ArrayList
HashSet
HashMap
LinkedHashMap
Iteration
Filtering
Counting
Grouping
Collection ownership
Defensive copying
Project Requirements
Course Catalog Rules
- Course code unique হতে হবে
- Course registration order preserve করতে হবে
- Course code দিয়ে direct lookup support করতে হবে
- Duplicate course registration existing course replace করবে না
Suitable structure:
LinkedHashMap<CourseCode, Course>
Course Rules
- Course title required
- Lessons ordered হবে
- Duplicate lesson ID allowed নয়
- Maximum 50 lessons
- Published course-এর lesson structure change করা যাবে না
- Empty course publish করা যাবে না
- Internal lesson list direct expose করা যাবে না
Suitable structure:
ArrayList<Lesson>
Enrollment Rules
- Learner ID positive হতে হবে
- Same learner একই course-এ দুইবার enroll করতে পারবে না
- One learner multiple courses-এ enroll করতে পারবে
- Missing learner-এর জন্য empty set return করতে হবে
- Internal nested collections expose করা যাবে না
Suitable structure:
Map<Long, Set<CourseCode>>
Project Structure
src/main/java/io/liveklass/
├── Main.java
├── catalog/
│ └── CourseCatalog.java
├── course/
│ ├── Course.java
│ ├── CourseCode.java
│ └── Lesson.java
└── enrollment/
└── EnrollmentRegistry.java
Part 1: Create CourseCode
Path:
src/main/java/io/liveklass/course/CourseCode.java
package io.liveklass.course;
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;
}
}
Why CourseCode Is a Value Object
These inputs:
java-oop
JAVA-OOP
Java-Oop
সব normalize হয়ে:
JAVA-OOP
হয়।
equals() এবং hashCode() implement করা হয়েছে, কারণ CourseCode:
Mapkey হিসেবে ব্যবহৃত হবেSetelement হিসেবে ব্যবহৃত হবে- Logical value equality require করে
Fields immutable হওয়ায় hash-based collection lookup stable থাকে।
Part 2: Create Lesson
Path:
src/main/java/io/liveklass/course/Lesson.java
package io.liveklass.course;
public final class Lesson {
private final long id;
private final String title;
public Lesson(
long id,
String title
) {
if (id <= 0) {
throw new IllegalArgumentException(
"Lesson ID must be positive."
);
}
if (
title == null
|| title.isBlank()
) {
throw new IllegalArgumentException(
"Lesson title is required."
);
}
this.id = id;
this.title = title.strip();
}
public Lesson rename(
String newTitle
) {
return new Lesson(
id,
newTitle
);
}
public long getId() {
return id;
}
public String getTitle() {
return title;
}
@Override
public String toString() {
return id
+ ": "
+ title;
}
}
Why Lesson Is Immutable
Lesson object-এর fields:
private final long id;
private final String title;
Direct mutation নেই।
Rename করলে new object তৈরি হয়:
lesson.rename(
"New Title"
);
এতে course-এর collection ownership stronger হয়।
Caller কোনো retrieved Lesson object direct mutate করতে পারে না।
Part 3: Create Course
Path:
src/main/java/io/liveklass/course/Course.java
package io.liveklass.course;
import java.util.ArrayList;
import java.util.List;
public final class Course {
private static final int MAX_LESSON_COUNT =
50;
private final CourseCode code;
private final String title;
private final List<Lesson> lessons;
private boolean published;
public Course(
CourseCode code,
String title
) {
if (code == null) {
throw new IllegalArgumentException(
"Course code is required."
);
}
if (
title == null
|| title.isBlank()
) {
throw new IllegalArgumentException(
"Course title is required."
);
}
this.code = code;
this.title = title.strip();
this.lessons =
new ArrayList<>();
this.published = false;
}
public boolean addLesson(
Lesson lesson
) {
if (published) {
return false;
}
if (lesson == null) {
return false;
}
if (
lessons.size()
>= MAX_LESSON_COUNT
) {
return false;
}
if (
containsLessonId(
lesson.getId()
)
) {
return false;
}
lessons.add(
lesson
);
return true;
}
public boolean addLessonAt(
int index,
Lesson lesson
) {
if (published) {
return false;
}
if (lesson == null) {
return false;
}
if (
index < 0
|| index > lessons.size()
) {
return false;
}
if (
lessons.size()
>= MAX_LESSON_COUNT
) {
return false;
}
if (
containsLessonId(
lesson.getId()
)
) {
return false;
}
lessons.add(
index,
lesson
);
return true;
}
public boolean removeLesson(
long lessonId
) {
if (published) {
return false;
}
int index =
findLessonIndex(
lessonId
);
if (index < 0) {
return false;
}
lessons.remove(
index
);
return true;
}
public boolean renameLesson(
long lessonId,
String newTitle
) {
if (published) {
return false;
}
if (
newTitle == null
|| newTitle.isBlank()
) {
return false;
}
int index =
findLessonIndex(
lessonId
);
if (index < 0) {
return false;
}
Lesson lesson =
lessons.get(
index
);
lessons.set(
index,
lesson.rename(
newTitle
)
);
return true;
}
public boolean moveLesson(
long lessonId,
int targetIndex
) {
if (published) {
return false;
}
if (
targetIndex < 0
|| targetIndex >= lessons.size()
) {
return false;
}
int currentIndex =
findLessonIndex(
lessonId
);
if (
currentIndex < 0
|| currentIndex == targetIndex
) {
return false;
}
Lesson lesson =
lessons.remove(
currentIndex
);
lessons.add(
targetIndex,
lesson
);
return true;
}
public Lesson findLessonById(
long lessonId
) {
int index =
findLessonIndex(
lessonId
);
if (index < 0) {
return null;
}
return lessons.get(
index
);
}
public boolean publish() {
if (published) {
return false;
}
if (lessons.isEmpty()) {
return false;
}
published = true;
return true;
}
public List<Lesson> getLessons() {
return List.copyOf(
lessons
);
}
public CourseCode getCode() {
return code;
}
public String getTitle() {
return title;
}
public int getLessonCount() {
return lessons.size();
}
public boolean isPublished() {
return published;
}
private boolean containsLessonId(
long lessonId
) {
return findLessonIndex(
lessonId
) >= 0;
}
private int findLessonIndex(
long lessonId
) {
for (
int index = 0;
index < lessons.size();
index++
) {
Lesson lesson =
lessons.get(
index
);
if (
lesson.getId()
== lessonId
) {
return index;
}
}
return -1;
}
@Override
public String toString() {
return code
+ " — "
+ title;
}
}
Course Design Review
Why Use ArrayList?
Lessons:
- Ordered
- Reorderable
- Index-based display useful
- Usually small collection
So:
ArrayList<Lesson>
is appropriate।
Why Not Use Set<Lesson>?
Duplicate lesson ID forbidden হলেও lesson order equally important।
Set only uniqueness solve করত।
Course requires:
Order + unique ID
তাই List এবং explicit duplicate validation ব্যবহার করা হয়েছে।
Why Return List.copyOf()?
Weak:
return lessons;
Callerকে internal mutable list দিত।
Caller করতে পারত:
course.getLessons()
.clear();
List.copyOf() structural mutation prevent করে।
Part 4: Create CourseCatalog
Path:
src/main/java/io/liveklass/catalog/CourseCatalog.java
package io.liveklass.catalog;
import io.liveklass.course.Course;
import io.liveklass.course.CourseCode;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public final class CourseCatalog {
private final Map<CourseCode, Course> coursesByCode;
public CourseCatalog() {
this.coursesByCode =
new LinkedHashMap<>();
}
public boolean register(
Course course
) {
if (course == null) {
return false;
}
Course existing =
coursesByCode.putIfAbsent(
course.getCode(),
course
);
return existing == null;
}
public Course findByCode(
CourseCode code
) {
if (code == null) {
return null;
}
return coursesByCode.get(
code
);
}
public boolean contains(
CourseCode code
) {
if (code == null) {
return false;
}
return coursesByCode.containsKey(
code
);
}
public boolean remove(
CourseCode code
) {
if (code == null) {
return false;
}
return coursesByCode.remove(
code
) != null;
}
public List<Course> getCourses() {
return List.copyOf(
coursesByCode.values()
);
}
public int getCourseCount() {
return coursesByCode.size();
}
public void printCourses() {
int position =
1;
for (
Map.Entry<CourseCode, Course> entry
: coursesByCode.entrySet()
) {
System.out.println(
position
+ ". "
+ entry.getKey()
+ " — "
+ entry.getValue()
.getTitle()
);
position++;
}
}
}
Catalog Design Review
Why Use LinkedHashMap?
Requirements:
Unique course code
Direct code lookup
Registration order
LinkedHashMap তিনটি requirement এক structure-এ solve করে।
Why Use putIfAbsent()?
Weak:
coursesByCode.put(
course.getCode(),
course
);
Duplicate course code existing course replace করত।
putIfAbsent() existing registration preserve করে।
Why Return a List<Course>?
Catalog-এর public read operation registration-order sequence communicate করে।
getCourses()
callerকে internal map mutation expose করে না।
Part 5: Create EnrollmentRegistry
Path:
src/main/java/io/liveklass/enrollment/EnrollmentRegistry.java
package io.liveklass.enrollment;
import io.liveklass.course.CourseCode;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public final class EnrollmentRegistry {
private final Map<Long, Set<CourseCode>>
courseCodesByLearner;
public EnrollmentRegistry() {
this.courseCodesByLearner =
new HashMap<>();
}
public boolean enroll(
long learnerId,
CourseCode courseCode
) {
if (learnerId <= 0) {
return false;
}
if (courseCode == null) {
return false;
}
Set<CourseCode> courseCodes =
courseCodesByLearner.get(
learnerId
);
if (courseCodes == null) {
courseCodes =
new HashSet<>();
courseCodesByLearner.put(
learnerId,
courseCodes
);
}
return courseCodes.add(
courseCode
);
}
public boolean isEnrolled(
long learnerId,
CourseCode courseCode
) {
if (
learnerId <= 0
|| courseCode == null
) {
return false;
}
Set<CourseCode> courseCodes =
courseCodesByLearner.get(
learnerId
);
return courseCodes != null
&& courseCodes.contains(
courseCode
);
}
public boolean cancel(
long learnerId,
CourseCode courseCode
) {
if (
learnerId <= 0
|| courseCode == null
) {
return false;
}
Set<CourseCode> courseCodes =
courseCodesByLearner.get(
learnerId
);
if (courseCodes == null) {
return false;
}
boolean removed =
courseCodes.remove(
courseCode
);
if (courseCodes.isEmpty()) {
courseCodesByLearner.remove(
learnerId
);
}
return removed;
}
public Set<CourseCode> findCourseCodes(
long learnerId
) {
Set<CourseCode> courseCodes =
courseCodesByLearner.get(
learnerId
);
if (courseCodes == null) {
return Set.of();
}
return Set.copyOf(
courseCodes
);
}
public Map<CourseCode, Integer>
countEnrollmentsByCourse() {
Map<CourseCode, Integer> counts =
new HashMap<>();
for (
Set<CourseCode> courseCodes
: courseCodesByLearner.values()
) {
for (
CourseCode courseCode
: courseCodes
) {
int currentCount =
counts.getOrDefault(
courseCode,
0
);
counts.put(
courseCode,
currentCount + 1
);
}
}
return Map.copyOf(
counts
);
}
public Map<Long, Set<CourseCode>> getSnapshot() {
Map<Long, Set<CourseCode>> copy =
new HashMap<>();
for (
Map.Entry<Long, Set<CourseCode>> entry
: courseCodesByLearner.entrySet()
) {
copy.put(
entry.getKey(),
Set.copyOf(
entry.getValue()
)
);
}
return Map.copyOf(
copy
);
}
public int getLearnerCount() {
return courseCodesByLearner.size();
}
}
Enrollment Design Review
Why Use Map<Long, Set<CourseCode>>?
Relationship:
Learner ID → Unique enrolled course codes
Map provides learner lookup।
Set prevents duplicate enrollment।
Why Remove Empty Learner Entries?
After final cancellation:
courseCodes.isEmpty()
Current model means:
No enrollments → No learner entry
This keeps map state compact এবং clear।
Why Copy Both Map and Inner Sets?
This is not enough:
return Map.copyOf(
courseCodesByLearner
);
Outer map immutable হলেও inner sets mutable থাকতে পারত।
Therefore:
Set.copyOf(...)
প্রতিটি inner set-এর জন্যও করা হয়েছে।
Part 6: Build the Application
Path:
src/main/java/io/liveklass/Main.java
package io.liveklass;
import io.liveklass.catalog.CourseCatalog;
import io.liveklass.course.Course;
import io.liveklass.course.CourseCode;
import io.liveklass.course.Lesson;
import io.liveklass.enrollment.EnrollmentRegistry;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Main {
public static void main(
String[] args
) {
Course javaCourse =
createJavaCourse();
Course backendCourse =
createBackendCourse();
CourseCatalog catalog =
new CourseCatalog();
boolean javaRegistered =
catalog.register(
javaCourse
);
boolean backendRegistered =
catalog.register(
backendCourse
);
boolean duplicateRegistered =
catalog.register(
new Course(
new CourseCode(
"java-oop"
),
"Duplicate Java Course"
)
);
System.out.println(
"Java registered: "
+ javaRegistered
);
System.out.println(
"Backend registered: "
+ backendRegistered
);
System.out.println(
"Duplicate registered: "
+ duplicateRegistered
);
System.out.println();
System.out.println(
"Course catalog:"
);
catalog.printCourses();
Course found =
catalog.findByCode(
new CourseCode(
"JAVA-OOP"
)
);
System.out.println();
System.out.println(
"Found course: "
+ found
);
demonstrateEnrollments(
javaCourse,
backendCourse
);
}
private static Course createJavaCourse() {
Course course =
new Course(
new CourseCode(
"JAVA-OOP"
),
"Java and OOP Foundation"
);
course.addLesson(
new Lesson(
101L,
"Introduction to Generics"
)
);
course.addLesson(
new Lesson(
102L,
"Working with List"
)
);
course.addLesson(
new Lesson(
103L,
"Working with Set"
)
);
course.addLesson(
new Lesson(
104L,
"Working with Map"
)
);
course.moveLesson(
104L,
2
);
course.publish();
return course;
}
private static Course createBackendCourse() {
Course course =
new Course(
new CourseCode(
"BACKEND"
),
"Backend Development"
);
course.addLesson(
new Lesson(
201L,
"HTTP Fundamentals"
)
);
course.addLesson(
new Lesson(
202L,
"REST API Design"
)
);
course.publish();
return course;
}
private static void demonstrateEnrollments(
Course javaCourse,
Course backendCourse
) {
EnrollmentRegistry registry =
new EnrollmentRegistry();
boolean firstEnrollment =
registry.enroll(
1001L,
javaCourse.getCode()
);
boolean duplicateEnrollment =
registry.enroll(
1001L,
javaCourse.getCode()
);
registry.enroll(
1001L,
backendCourse.getCode()
);
registry.enroll(
1002L,
javaCourse.getCode()
);
System.out.println();
System.out.println(
"First enrollment: "
+ firstEnrollment
);
System.out.println(
"Duplicate enrollment: "
+ duplicateEnrollment
);
Set<CourseCode> learnerCourses =
registry.findCourseCodes(
1001L
);
System.out.println(
"Learner 1001 courses: "
+ learnerCourses
);
Map<CourseCode, Integer> counts =
registry
.countEnrollmentsByCourse();
System.out.println(
"Enrollment counts: "
+ counts
);
boolean cancelled =
registry.cancel(
1001L,
backendCourse.getCode()
);
System.out.println(
"Backend enrollment cancelled: "
+ cancelled
);
System.out.println(
"Learner 1001 courses after cancellation: "
+ registry.findCourseCodes(
1001L
)
);
printJavaLessons(
javaCourse
);
}
private static void printJavaLessons(
Course javaCourse
) {
List<Lesson> lessons =
javaCourse.getLessons();
System.out.println();
System.out.println(
"Java course lessons:"
);
for (
int index = 0;
index < lessons.size();
index++
) {
System.out.println(
(index + 1)
+ ". "
+ lessons.get(
index
).getTitle()
);
}
}
}
Expected Output
HashMap এবং HashSet-based values-এর printed order vary করতে পারে।
Java registered: true
Backend registered: true
Duplicate registered: false
Course catalog:
1. JAVA-OOP — Java and OOP Foundation
2. BACKEND — Backend Development
Found course: JAVA-OOP — Java and OOP Foundation
First enrollment: true
Duplicate enrollment: false
Learner 1001 courses: [JAVA-OOP, BACKEND]
Enrollment counts: {JAVA-OOP=2, BACKEND=1}
Backend enrollment cancelled: true
Learner 1001 courses after cancellation: [JAVA-OOP]
Java course lessons:
1. Introduction to Generics
2. Working with List
3. Working with Map
4. Working with Set
Compile and Run
Project root থেকে:
javac -d out \
$(find src/main/java -name "*.java")
Run:
java -cp out io.liveklass.Main
Integrated Collection Review
Where Is List Used?
List<Lesson>
Reason:
Lesson order matters
Reordering supported
Index-based display useful
Where Is Set Used?
Set<CourseCode>
Reason:
Same learner cannot enroll in the same course twice
Where Is Map Used?
Catalog:
Map<CourseCode, Course>
Reason:
Course code দিয়ে direct lookup
Enrollment registry:
Map<Long, Set<CourseCode>>
Reason:
Learner ID দিয়ে enrolled course set lookup
Where Is LinkedHashMap Used?
CourseCatalog
কারণ registration order preserve করতে হবে।
Where Is HashMap Used?
Enrollment registry-তে learner order meaningful নয়।
HashMap<Long, Set<CourseCode>>
appropriate।
Where Is Defensive Copying Used?
List.copyOf(...)
Set.copyOf(...)
Map.copyOf(...)
These prevent callers from changing internal collection structures।
Part 7: Required Extension Tasks
Extension 1: Add Course Removal Protection
Catalog থেকে published course remove করা যাবে না।
Modify:
boolean remove(
CourseCode code
)
Extension 2: Add Lesson Batch Insertion
Create:
boolean addLessons(
List<Lesson> lessons
)
Rules:
- Validate all lessons first
- No null
- No duplicate IDs
- Maximum 50 lessons
- No partial addition
- Published course reject করবে
Extension 3: Find Most Popular Course
Add:
CourseCode findMostPopularCourse()
to EnrollmentRegistry।
Use:
countEnrollmentsByCourse()
Handle empty registry।
Extension 4: Find Learners by Course
Add:
Set<Long> findLearnerIds(
CourseCode courseCode
)
Return immutable set।
Extension 5: Preserve Enrollment Order
Current learner course set:
HashSet<CourseCode>
Change it so enrollment order preserve হয়।
Choose an appropriate implementation।
Extension 6: Group Courses by Lesson Count
Create:
Map<Integer, List<Course>>
Example:
2 lessons → Backend Development
4 lessons → Java and OOP Foundation
Protect outer map and inner lists।
Part 8: Collection Choice Assessment
Choose the best collection type and implementation।
Question 1
Ordered course modules that can be manually reordered।
Question 2
Unique completed lesson IDs where order is irrelevant।
Question 3
Course code to course lookup preserving registration order।
Question 4
Unique tags preserving instructor-selected order।
Question 5
Country code to country sorted by code।
Question 6
Learner activity history where repeated actions are meaningful।
Collection Choice Answers
Answer 1
ArrayList<Module>
Order and manual reordering matter।
Answer 2
HashSet<Long>
Unique membership matters; order does not।
Answer 3
LinkedHashMap<CourseCode, Course>
Unique lookup key and insertion order both matter।
Answer 4
LinkedHashSet<String>
Uniqueness and insertion order matter।
Answer 5
TreeMap<String, Country>
Key lookup and sorted key order matter।
Answer 6
ArrayList<Activity>
Sequence and repeated events matter।
Part 9: Predict the Result
Question 1
Map<String, Integer> values =
new LinkedHashMap<>();
values.put(
"A",
1
);
values.put(
"B",
2
);
values.put(
"A",
3
);
System.out.println(
values.size()
);
System.out.println(
values
);
Answer
1?
Incorrect.
Actual size:
2
Result:
{A=3, B=2}
Existing key replacement does not create another key।
Its original insertion position remains unchanged।
Question 2
Set<String> values =
new HashSet<>();
System.out.println(
values.add(
"JAVA"
)
);
System.out.println(
values.add(
"JAVA"
)
);
Answer
true
false
Question 3
List<String> values =
List.of(
"A",
"B"
);
values.add(
"C"
);
Answer
Runtime-এ:
UnsupportedOperationException
Question 4
CourseCode first =
new CourseCode(
"java"
);
CourseCode second =
new CourseCode(
"JAVA"
);
System.out.println(
first.equals(
second
)
);
Answer
true
Both normalize to the same value।
Question 5
Set<CourseCode> courses =
registry.findCourseCodes(
9999L
);
System.out.println(
courses.isEmpty()
);
Answer
true
Missing learner returns an empty set।
Part 10: Find the Design Problem
Problem 1
public List<Lesson> getLessons() {
return lessons;
}
Issue
Internal mutable list leaks।
Caller domain rules bypass করতে পারে।
Better
return List.copyOf(
lessons
);
Problem 2
List<Course> courses =
new ArrayList<>();
Every request searches by unique course code।
Issue
Repeated linear search।
Better
Map<CourseCode, Course>
Problem 3
Set<Lesson> lessons =
new HashSet<>();
Lessons must remain in curriculum order।
Issue
HashSet order guarantee করে না।
Better
List<Lesson>
with duplicate ID validation।
Problem 4
Map<Long, List<CourseCode>>
Same learner-course enrollment must be unique।
Issue
List duplicates allow করে।
Better
Map<Long, Set<CourseCode>>
Problem 5
Map<MutableCourseCode, Course>
MutableCourseCode.value changes after insertion।
Issue
Hash lookup may fail।
Better
Use immutable key।
Part 11: Concept Assessment
Determine True or False.
Question 1
List preserves sequence.
Question 2
Set provides index-based access.
Question 3
A Map allows multiple equal keys.
Question 4
Different map keys may point to the same value.
Question 5
HashMap guarantees insertion order.
Question 6
LinkedHashMap preserves insertion order.
Question 7
List.copyOf() deep-copies every element.
Question 8
Set.add() can indicate whether a duplicate was rejected.
Question 9
Equal hash-based keys must have equal hash codes.
Question 10
An immutable outer map automatically makes inner sets immutable.
Question 11
A list can still be correct when duplicate IDs are manually rejected.
Question 12
Object-level validation replaces database uniqueness constraints.
Concept Assessment Answers
1. True
2. False
3. False
4. True
5. False
6. True
7. False
8. True
9. True
10. False
11. True
12. False
Part 12: Final Independent Challenge
Build a simplified learning platform without copying the reference implementation।
Required classes:
CourseCode
Lesson
Course
CourseCatalog
EnrollmentRegistry
Required behavior:
- Course code normalized and value-based
- Course lessons ordered
- Duplicate lesson IDs rejected
- Course code lookup supported
- Registration order preserved
- Duplicate enrollment rejected
- Learner courses returned as immutable set
- Enrollment count by course calculated
- Internal mutable collections not exposed
- Empty results returned instead of null collections
Evaluation Rubric
Score each area:
0 = Missing or incorrect
1 = Partially correct
2 = Correct and intentional
| Area | Score |
|---|---|
| Generic types used safely | /2 |
Appropriate List usage | /2 |
Appropriate Set usage | /2 |
Appropriate Map usage | /2 |
| Ordering requirement preserved | /2 |
| Duplicate course prevention | /2 |
| Duplicate lesson prevention | /2 |
| Duplicate enrollment prevention | /2 |
| Custom key equality correct | /2 |
| Hash key immutable | /2 |
| Defensive copying used | /2 |
| Nested collections protected | /2 |
| Empty collections returned | /2 |
| Search and iteration readable | /2 |
| Domain methods control mutation | /2 |
Maximum:
30
Interpretation:
26–30 → Strong understanding
21–25 → Good foundation
15–20 → Review collection design
Below 15 → Rebuild the project
Module Completion Checklist
Before completing Module 4, verify that you can:
- Explain generic type safety
- Distinguish type parameter and type argument
- Use wrapper types with generics
- Explain generic invariance
- Create and modify an
ArrayList - Use index safely
- Distinguish mutable and immutable lists
- Use
HashSet - Explain
equals()andhashCode() - Avoid mutable hash keys
- Use
HashMap - Use
LinkedHashMap - Use
putIfAbsent() - Iterate keys, values, and entries
- Search, filter, transform, and aggregate
- Count values using a map
- Group values into nested collections
- Remove safely during iteration
- Defensively copy constructor inputs
- Return immutable snapshots
- Protect nested collections
- Choose collections based on order, uniqueness, and lookup
Module Summary
এই module-এ আমরা শিখেছি:
- Generics compile-time type safety provide করে
- Raw types type information হারায়
- Generic classes এবং methods reusable type relationships model করে
- Primitive types-এর জন্য wrapper classes প্রয়োজন
- Generic types invariant
Listordered sequence model করেArrayListcommon mutable list implementation- List index
0থেকে শুরু হয় List.of()immutable list তৈরি করেList.copyOf()immutable structural snapshot তৈরি করেSetunique membership model করেHashSetorder guarantee করে নাLinkedHashSetinsertion order preserve করেTreeSetsorted unique values রাখে- Hash-based structures
equals()এবংhashCode()-এর ওপর depend করে - Mutable equality state dangerous
Mapkey-value lookup model করেHashMapcommon key lookup implementationLinkedHashMapinsertion order preserve করেTreeMapkeys sorted রাখেput()existing key replace করেputIfAbsent()duplicate replacement prevent করেgetOrDefault()counting simplify করে- Enhanced
for, index loop, এবংIteratordifferent needs serve করে - Iteration-এর সময় direct structural removal unsafe হতে পারে
- Filtering selected values তৈরি করে
- Transformation valuesকে new representation-এ convert করে
- Aggregation total, count, average, minimum, এবং maximum তৈরি করে
- Maps frequency counting এবং grouping-এর জন্য useful
- Nested collection structures carefully protect করতে হয়
- Classes internal collections own এবং control করতে পারে
- Defensive copying aliasing prevent করে
- Immutable snapshots mutable state leakage prevent করে
- Collection choice order, uniqueness, lookup, and scale থেকে আসা উচিত
- Domain clarity premature optimization-এর চেয়ে বেশি important
List,Set, এবংMapcompeting নয়; different relationships model করে
Module Complete
আপনি এখন Java collections শুধু syntax হিসেবে নয়, domain modeling tool হিসেবে ব্যবহার করতে প্রস্তুত।
Collection নির্বাচন করার আগে তিনটি প্রশ্ন করুন:
Does order matter?
Are duplicates meaningful?
Is lookup by a key the main operation?
এই প্রশ্নগুলোর উত্তর সাধারণত আপনাকে List, Set, এবং Map-এর মধ্যে সঠিক starting choice-এর দিকে নিয়ে যাবে।