Bob
Bob

Reputation: 1211

Short method to remove specific entries from hashmap

I was looking for a short and easy readable method to remove entries from a hashmap. Specifically, this is my method:

Map<String, HashMap<String, Long>> kitcooldowns = new HashMap<String, HashMap<String, Long>>();


// METHOD TO REMOVE EXPIRED COOLDOWNS FROM HASHMAP

final long currentime = System.currentTimeMillis();
final HashMap<String, HashMap<String, Long>> tmp = new HashMap<String, HashMap<String,Long>>();
for (final Entry<String, HashMap<String, Long>> kits : kitcooldowns.entrySet()) {
    final HashMap<String, Long> newitems = new HashMap<String, Long>();
    for (final Entry<String, Long> item : kits.getValue().entrySet()) {
        if (item.getValue() + getCooldownTime(item.getKey()) > currentime) {
            newitems.put(item.getKey(), item.getValue());
        }
    }
    if (newitems.isEmpty() == false) tmp.put(kits.getKey(), newitems);
}

kitcooldowns = tmp;


private long getCooldownTime(final String type) {
    switch (type) {
    case "CooldownX":
        return 3600000;
    case "CooldownY":
        return 1800000;
    default:
        return 0L;
    }
}

To simplify this, this is the main structure:

MAP<NAME OF PLAYER, MAP<TYPE OF COOLDOWN, TIME WHEN USED>>

If the specific cooldown has expired, the player gets removed from the Hashmap. Now, this looks like a messy solution to me and I am sure there is a better one.

EDIT: My Question is, if there is a efficient and clean method (like iterator) with Java 8, which has tons of new one-line solutions for most of the long methods.

Upvotes: 1

Views: 179

Answers (2)

Bob
Bob

Reputation: 1211

You can simply use this Java one-liner:

    final long currentime = System.currentTimeMillis();
    kitcooldowns.entrySet().removeIf(entry -> entry.getValue().entrySet()
    .removeIf(entry2 -> entry2.getValue() + getCooldownTime(entry2.getKey()) 
    < currentime) && entry.getValue().isEmpty());

Upvotes: 0

Matt Ball
Matt Ball

Reputation: 359846

No need to create a separate map. You can use Iterator#remove() if you iterate over the map's entrySet() or values().

for (Iterator<Entry<String, Long>> iter = kitcooldowns.entrySet().iterator(); iter.hasNext();) {
  Entry<String, Long> entry = iter.next();
  if (entry.getValue() + getCooldownTime(entry.getKey()) > currentime) {
    iter.remove();
  }
}

OP wants to know:

Isn't there any one-line solution with Java 8?

Sure, but I strongly caution you against writing everything as a one-liner just because you can. Remember that code exists to be read by future devs, not to be written as concisely as possible. Furthermore, the code that uses Iterator#remove() will use less memory, because it doesn't have to make a copy of the map. Code that uses less memory can end up being faster, too, because less memory usage leads to less GC (which costs CPU time) and fewer CPU cache misses.

That said:

kitcooldowns = kitcooldowns.entrySet().stream()
  .filter(entry -> entry.getValue() + getCooldownTime(entry.getKey()) <= currentime)
  .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

Upvotes: 1

Related Questions