Skip to Content
Course content

43: List, Set, and Map Overview

Click on the "Edit" button in the top corner of the screen to edit your slide content.

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 ArrayList to a HashSet to 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 returns false if 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;
    }
}
Rating
0 0

There are no comments for now.

to be the first to leave a comment.