About Functions.forMap, default putIfAbsent and Set operations
Cleber Muramoto
cleber at nightcoders.com.br
Fri Jan 25 09:18:37 PST 2013
The current implementation of Functions.forMap reads:
public static <R, T> Function<T, R> forMap(Map<? super T, ? extends R> map)
{
Objects.requireNonNull(map);
return t -> {
if (map.containsKey(t)) {
return map.get(t);
} else {
throw new IllegalArgumentException("unmappable <T> : " + t);
}
};
}
Since usually maps will have non-null values mapped for keys, this method
usually should also perform a single map lookup:
public static <R, T> Function<T, R> forMap(Map<? super T, ? extends R> map)
{
Objects.requireNonNull(map);
return t -> {
R r = map.get(t);
if(r!=null || map.containsKey(t)){
return r;
}
throw new IllegalArgumentException("unmappable <T> : " + t);
};
}
I think I have seen patterns similar to the above in old builds in the
groupBy methods, and some are now present Map default methods.
Maybe
default V putIfAbsent(K key, V value) {
return containsKey(key) ? get(key) : put(key, value);
}
will perform slightly better as
default V putIfAbsent(K key, V value) {
V old = get(key);
return old!=null || containsKey(key) ? old : put(key, value);
}
in most cases. Most of ConcurrentMap default-method code is rewritten for
performance/correctness. Are there plans to do this for core java maps too?
As for my set operations wish list, I think they have been asked before,
but I'll insist anyway! :) It would be nice to have the defaults union,
intersection and difference. I know one can achieve them via retainAll,
etc, but it would be nice to perform them in a single step. Something like
public default Set<T> intersection(Set<T> other,Supplier<Set<T>>
viewSupplier){
Objects.requireNonNull(other);
Set<T> toLoop = size()<other.size()?this:other;
Set<T> toCheck = toLoop==this?other:this;
Set<T> target = viewSupplier.get();
for(T t: toLoop){
if(toCheck.contains(t)){
target.add(t);
}
}
return target;
}
And possibly immutable/copy-less views such as Guava's SetView:
public default Set<T> intersection(Set<T> other){
Objects.requireNonNull(other);
final Set<T> left=size()<right.size()?this:other;
final Set<T> right=left==this?other:right;
return new AbstractSet<T>(){
public boolean contains(T t){
return left.contains(t) && right.contains(t);
}
...
}
}
Regards!
Cleber
More information about the lambda-dev
mailing list