Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
43: List, Set, and Map Overview
I've seen this play out a dozen times during code reviews with junior devs: a programmer treats the ArrayList as the Swiss Army knife of Java. It’s the first collection most of us learn, it's intuitive, and it just works for basic storage. But as your data grows, using a List for everything is a recipe for a performance nightmare. Let's look at a real scenario: building a simple user session manager for a web app.
The trap of using a List for everything
Imagine you're tracking active users. You might start by creating a List<User>. When a user logs in, you add them to the list. Now, imagine you need to check if a specific username is already logged in so you can prevent double-sessions. With a List, your code looks like this:
public boolean isUserLoggedIn(String username) {
for (User user : activeUsers) {
if (user.getUsername().equals(username)) {
return true;
}
}
return false;
}
This is what we call "linear time." If you have ten users, it's fast. If you have ten thousand, Java has to potentially check ten thousand objects every single time someone hits a page. It's an expensive way to ask a simple yes/no question. Plus, the List doesn't care about duplicates; if your logic fails elsewhere, you'll end up with the same user in that list five times, making your memory usage climb for no reason.
When uniqueness is the priority
If your primary goal is to ensure no duplicates exist and to check for existence quickly, you should be using a Set—specifically a HashSet. I usually tell my teammates to think of a Set as a mathematical set: it's just a bag of unique items. It doesn't have "indexes" like a List does (you can't ask for the "third element"), but it's incredibly fast at telling you if it contains something.
By switching List<User> to Set<User>, the contains() method stops looping through every element. Instead, it uses a hash code to jump straight to the memory location where that user should be. Whether you have ten users or ten million, the time it takes to check for a duplicate remains virtually the same. The trade-off? You lose the insertion order. If you need to know who logged in first, a HashSet won't help you, but for "Is this person here?", it's the only correct choice.
Solving the lookup problem with Maps
Now, let's say you don't just want to know if a user is logged in; you have a session token (a long random string) and you need to retrieve the User object associated with that token. You could use a List and loop through it again, but that's just repeating the same mistake. This is where the Map comes in.
A Map is essentially a dictionary. You provide a key (the token) and it gives you a value (the User). In our session manager, it looks like this:
Map<String, User> sessions = new HashMap<>();
sessions.put(sessionToken, user);
// Later, retrieving the user is instant
User user = sessions.get(sessionToken);
The beauty of the HashMap is that it combines the speed of a Set with the ability to associate data. You aren't searching for the user; you're using the token as a direct address to find them. If you find yourself writing a for loop just to find a specific object by its ID, stop. You shouldn't be using a List; you should be using a Map.
Choosing based on the cost
So, how do I decide which one to use in the heat of a project? I ask myself what the "expensive" operation is. If I need to maintain a specific sequence (like a history log or a queue), I stick with a List. If I need to guarantee that no two items are the same and I'm doing lots of "does this exist?" checks, I go with a Set. If I have a unique identifier and I need to retrieve a complex object instantly, I use a Map.
The biggest mistake is prioritizing the ease of adding data over the efficiency of retrieving it. Adding to a List is easy, but searching it is where your application will eventually crawl to a halt.
📋 Practical Task
Refactoring the Guest List Manager
You have been handed a piece of legacy code for a VIP event guest list. The current implementation uses an ArrayList to store guest names, but it's causing performance issues and allowing the same person to be added multiple times.
Your Task: Refactor the GuestManager class.
- Change the internal storage from an
ArrayListto aHashSetto ensure guests are unique and lookups are fast. - Implement a
checkGuest(String name)method that returns a boolean indicating if the guest is on the list. - Implement an
addGuest(String name)method that returnsfalseif the guest was already present (meaning they weren't added again).
// Start with this naive implementation
import java.util.*;
class GuestManager {
private List<String> guests = new ArrayList<>();
public void addGuest(String name) {
guests.add(name); // This allows duplicates!
}
public boolean checkGuest(String name) {
for (String g : guests) {
if (g.equals(name)) return true;
}
return false;
}
}There are no comments for now.