2

I have a final ConcurrentMap in Java and want to filter it's elements without creating a new one.

Question is: can I reference collection (people) from inside the lambda?

final ConcurrentMap<String, String> people = new ConcurrentHashMap<>();
people.put("Sam", "developer");
people.put("Kate", "tester");

people.forEach((name, role) -> {
    if (name.length() > 3)
        people.remove(name);
});
izy
  • 1,085
  • 14
  • 18

2 Answers2

3

.keySet(), .values(), and .entrySet() return live views of a map's keys, values and entries respectively. You can remove elements from those collections and the corresponding entries will be removed from the map:

people.keySet().removeIf(name -> name.length() > 3);
Misha
  • 27,433
  • 6
  • 62
  • 78
3

This has sort of been discussed just recently, for example here.

The documentation states that CHM provide weakly consistent traversal, as opposed to fail-fast traversal; as seen here What this means:

they may proceed concurrently with other operations

they are guaranteed to traverse elements as they existed upon construction exactly once, and may (but are not guaranteed to) reflect any modifications subsequent to construction.

Generally CHM operations that change it's structure are thread-safe, but what you want to achieve is still discouraged by the Stream documentation. This is called interference and should be avoided. If you change that structure with an simple HashMap you will get ConcurrentModificationException since you are modifying the source while traversing it. Unless you have a compelling reason not to discard your previous map, you should just filter the values you are interested in and collect those.

You can also see how you can get un-expected results when you add to a CMH from the link above.

Community
  • 1
  • 1
Eugene
  • 117,005
  • 15
  • 201
  • 306