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