Start learning free

LESSON 234 OF 671 · SETS

Removing From a HashSet and Looping Over It in Java

Lesson Read the full explanation

TL ; DR:

remove(x) takes x out of a set. A for-each loop visits every value once, in no fixed order.


HashSet<String> colors = new HashSet<>(List.of("red", "blue", "green"));

colors.remove("blue");

colors.remove("pink");          // not in it, nothing happens

for (String color : colors) {
    System.out.println(color);  // red and green, in any order
}


Full lesson:

s.remove(x) removes x from the set s. It returns true if x was there. If it wasn't, nothing happens and it returns false.

On a set, remove always takes the value. A set has no indexes. Careful with a List<Integer>, though. There, remove(2) removes the item at index 2.

for (String x : s) visits each value of the set once. The order isn't fixed. It may differ from the order you added the values in.

So loop over a set when the order doesn't matter. A total, a count and a check are fine.

Don't remove values from a set while you loop over it. Java stops with a ConcurrentModificationException. Remove first, then loop.


Your task

In a word game, the set found holds the words a player found. The words "qqq" and "zzz" aren't allowed. Remove both from found.

The player never found "zzz", so removing it changes nothing.

Then add up the points. A word scores one point per letter. Loop over found and add each word's length to score.

The code already prints how many words are left, and the points.

Expected output:

4 words
14 points
STEP 1 OF 3
    Ctrl + Enter to check

    JAVA · SETS

    Removing From Sets in Java, explained

    Removing a value

    s.remove(x) takes the value x out of the set s. It returns true if the value was there. If it wasn't, nothing happens: there is no error, and the method returns false.

    HashSet<Integer> nums = new HashSet<>(List.of(5, 2, 9));
    System.out.println(nums.remove(2));
    System.out.println(nums.remove(2));

    The first call finds the 2 and prints true. The second finds nothing and prints false.

    A trap with lists

    On a set, remove always takes the value, because a set has no indexes. A List<Integer> is different. For a list, remove(2) with an int argument removes the item at index 2, not the value 2. With List<Integer> list = new ArrayList<>(List.of(5, 2, 9)), calling list.remove(2) removes the 9 and leaves [5, 2]. Keep that in mind when you switch between the two.

    Looping over a set

    A for-each loop visits each value of a set once:

    HashSet<String> colors = new HashSet<>(List.of("red", "blue", "green"));
    colors.remove("blue");
    for (String color : colors) {
        System.out.println(color);
    }

    This prints red and green, in no promised order. It may differ from the order you added the values in. Loop over a set when the order doesn't matter: a total, a count or a check are all fine.

    Don't remove while looping

    If you remove values from a set inside a loop over that same set, Java stops with a ConcurrentModificationException. Remove first, then loop.

    The lesson's task

    In a word game, the set found holds the words a player found: cat, tree, sun, qqq and moon. The words "qqq" and "zzz" aren't allowed, so both must be removed. The player never found "zzz", so that removal changes nothing. Then each word scores one point per letter, and the loop adds up the lengths.

    found.remove("qqq");
    found.remove("zzz");
    System.out.println(found.size() + " words");
    
    int score = 0;
    for (String word : found) {
        score += word.length();
    }
    System.out.println(score + " points");

    Four words are left: cat, tree, sun and moon. Their lengths are 3, 4, 3 and 4. The output is:

    4 words
    14 points

    The total is the same whatever order the loop visits the words in, which is why a sum is a safe thing to compute from a set.

    The reason for removing first is that a loop over a set walks through it as it is at that moment. A removal in the middle changes the set under the loop, and Java reports that by throwing the exception on the loop's next step. If you need to drop some values based on a rule, collect them in a second collection during the loop and remove them after it, or remove them before you loop at all, as this task does.

    Common mistakes

    • Checking contains before every remove. It isn't needed: removing a missing value is harmless.
    • Printing the set to check the order. A set has no fixed order, so print sizes or totals instead.
    • Removing inside the loop that is reading the same set.

    Key takeaways

    • remove(x) deletes a value and returns whether it was there.
    • Removing a value that isn't in the set does nothing.
    • A for-each loop visits each value once, in no fixed order.
    • Finish removing before you start looping.
    Keep going with Java500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free