私は(小)にリストされた任意の要素を除去しなければならない方法有するSet<K> keysToRemove
いくつか(潜在的に大きい)からのMap<K,V> from
。しかしremoveAll()
、私はマップのかもしれないので、実際に削除されたすべてのキーを返却する必要があるか、除去する必要のキーが含まれていない可能性があるため、行いません。
古い学校のコードは単純です:
public Set<K> removeEntries(Map<K, V> from) {
Set<K> fromKeys = from.keySet();
Set<K> removedKeys = new HashSet<>();
for (K keyToRemove : keysToRemove) {
if (fromKeys.contains(keyToRemove)) {
fromKeys.remove(keyToRemove);
removedKeys.add(keyToRemove);
}
}
return removedKeys;
}
同じ、ストリームを使って書かれました。
Set<K> fromKeys = from.keySet();
return keysToRemove.stream()
.filter(fromKeys::contains)
.map(k -> {
fromKeys.remove(k);
return k;
})
.collect(Collectors.toSet());
私は、もう少し簡潔なことがわかり、私はまた、ラムダがあまりに不格好なことがわかります。
少ない不器用な方法で同じ結果を達成するためにどのように任意の提案ですか?
「古い学校コードは」むしろする必要があります
public Set<K> removeEntries(Map<K, ?> from) {
Set<K> fromKeys = from.keySet(), removedKeys = new HashSet<>(keysToRemove);
removedKeys.retainAll(fromKeys);
fromKeys.removeAll(removedKeys);
return removedKeys;
}
あなたがその言っているのでkeysToRemove
かなり小さい、おそらくオーバーヘッドコピーすることは重要ではありません。それ以外の場合は、ループを使用していますが、ハッシュのルックアップを2回行いません。
public Set<K> removeEntries(Map<K, ?> from) {
Set<K> fromKeys = from.keySet();
Set<K> removedKeys = new HashSet<>();
for(K keyToRemove : keysToRemove)
if(fromKeys.remove(keyToRemove)) removedKeys.add(keyToRemove);
return removedKeys;
}
あなたはストリームとして同じロジックを表現することができます
public Set<K> removeEntries(Map<K, ?> from) {
return keysToRemove.stream()
.filter(from.keySet()::remove)
.collect(Collectors.toSet());
}
これはステートフルフィルタであるので、しかし、それは非常に落胆しています。クリーナーバリアントは次のようになります
public Set<K> removeEntries(Map<K, ?> from) {
Set<K> result = keysToRemove.stream()
.filter(from.keySet()::contains)
.collect(Collectors.toSet());
from.keySet().removeAll(result);
return result;
}
そしてあなたは「Streamyに」使用率を最大化したい場合は、交換することが可能from.keySet().removeAll(result);
でfrom.keySet().removeIf(result::contains)
、それは大きなマップを反復処理、またはとされるように、高価な静かである、result.forEach(from.keySet()::remove)
という欠点を持っていないが、それでも、読みやすくはないんれ、よりremoveAll
。
すべてのすべてで、「古い学校のコードは、」より良いものを超えています。