Home > Software design >  Add size() to keySet() after retainAll on one line
Add size() to keySet() after retainAll on one line

Time:10-07

I'm experimenting with views. Is there a possibility to write the size() method on the second last line without useing lambdas?? As follows:

eintraege.retainAll(Arrays.asList(names)).size(); // Does not work


public static int countNames(Map<String, PhoneNumber> phoneBook,
                             String[] names) {
    Set<String> eintraege = phoneBook.keySet();
    eintraege.retainAll(Arrays.asList(names));  
    return eintraege.size();  // Works fine
}

CodePudding user response:

This code does not work fine.

retainAll will delete all the keys that aren't in names. .keySet() does not return a copy. It returns a different view. Deleting elements from what .keySet() returns deletes them from the original map!

Thus, this code will give the right answer... and will have corrupted your phonebook as well.

If you must use retainAll, you'd have to make a copy. No, there is no way to chain the size() call.

But, making a copy is silly here. You really just want to, well, count names. This code does not mangle the original phone book and is far faster:

int count = 0;
for (String n : names) if (phoneBook.containsKey(n)) count  ;
return count;

It also shows the folly of 'worrying about lines'. That code above is 3 lines and is plausibly readable as is. Certainly a ton of folks that do use lambdas would put the exact same 'semantic load' on a single line. But that is not a particularly commonly employed code style. At some point you're more 'measuring the efficacy of your code style' than actually measuring the complexity of your code. You also see extremes that serve no purpose and make code harder to read: A .stream().map() etc operation that does 18 different things, all piled on a single huge line, and some clown going: HA! See! shorter!

Keep the characteristics of your data structures in mind. list.contains(n) takes time that scales up with how large the list is. map.containsKey(n), or set.contains(n), that takes constant time (or in case of TreeMap, that takes time that scales with log2(n), but remember that log2(1_000_000) is still only a few tens of loops. log scaling is doable by computers even for humongous inputs.

Hence, the above code is relatively fast, but if you flip it around:

for (String n : phoneBook.keySet()) if (names.contains(n)) count  ;

that would grow to be very slow indeed, especially if names is large.

  • Related