JEP 186: Collection Literals
Peter Levart
peter.levart at gmail.com
Sat Jan 18 03:16:30 PST 2014
On 01/16/2014 12:43 AM, Remi Forax wrote:
> We can also use the Builder Pattern of Ruby now that we have a lambda syntax
> new ArrayList<>(builder -> builder.add(1).add(2).add(3));
>
> Rémi
This one is interesting, because it shows what can be achieved with
lambdas today. It enables expressions that evaluate into singleton
objects (like non-capturing lambdas). If the lambda body is
non-capturing, it evaluates into constant singleton in current
implementation. So objects produced with such lambdas can be cached
(using lambda object as a weak key). Here's a sample test that exercises
that:
public class Test {
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
List<Double> list = immutableList(b -> b._(3.14)._(0.33333));
System.out.println(list + " : " +
System.identityHashCode(list));
}
System.out.println();
for (int i = 0; i < 3; i++) {
double x = i;
List<Double> list = immutableList(b ->
b._(3.14)._(0.33333)._(x));
System.out.println(list + " : " +
System.identityHashCode(list));
}
System.out.println();
for (int i = 0; i < 3; i++) {
Map<String, Integer> map = immutableMap(b -> b._("aa",
1)._("bb", 2)._("cc", 3));
System.out.println(map + " : " + System.identityHashCode(map));
}
System.out.println();
for (int i = 0; i < 3; i++) {
int x = i;
Map<String, Integer> map = immutableMap(b -> b._("aa",
1)._("bb", 2)._("cc", x));
System.out.println(map + " : " + System.identityHashCode(map));
}
}
}
which prints:
[3.14, 0.33333] : 1706377736
[3.14, 0.33333] : 1706377736
[3.14, 0.33333] : 1706377736
[3.14, 0.33333, 0.0] : 868693306
[3.14, 0.33333, 1.0] : 989110044
[3.14, 0.33333, 2.0] : 321001045
{aa=1, bb=2, cc=3} : 1044036744
{aa=1, bb=2, cc=3} : 1044036744
{aa=1, bb=2, cc=3} : 1044036744
{aa=1, bb=2, cc=0} : 1915318863
{aa=1, bb=2, cc=1} : 295530567
{aa=1, bb=2, cc=2} : 1324119927
Regards, Peter
P.S. Here's what I used to compile above test:
public interface Builder<T> extends Consumer<T> {
default Builder<T> _(T t) {
accept(t);
return this;
}
}
public interface BiBuilder<T, U> extends BiConsumer<T, U> {
default BiBuilder<T, U> _(T t, U u) {
accept(t, u);
return this;
}
}
public class Collections2 {
public static <T> ArrayList<T> arrayList(Consumer<Builder<T>>
producer) {
ArrayList<T> list = new ArrayList<>();
producer.accept(list::add);
return list;
}
// cache of immutable lists per producer
private static final Map<Consumer<? extends Builder<?>>, List<?>>
INTERNED_IMMUTABLE_LISTS = new WeakHashMap<>();
public static <T> List<T> immutableList(Consumer<Builder<T>>
producer) {
synchronized (INTERNED_IMMUTABLE_LISTS) {
// check if already interned
@SuppressWarnings("unchecked")
List<T> list = (List<T>)
INTERNED_IMMUTABLE_LISTS.get(producer);
if (list != null) return list;
}
// count elements produced
final int[] count = new int[1];
producer.accept(t -> count[0]++);
// construct new list
ArrayList<T> aList = new ArrayList<>(count[0]);
producer.accept(aList::add);
synchronized (INTERNED_IMMUTABLE_LISTS) {
// recheck (highly unlikely)
@SuppressWarnings("unchecked")
List<T> list = (List<T>)
INTERNED_IMMUTABLE_LISTS.get(producer);
if (list != null) return list;
// put it into cache and return
list = Collections.unmodifiableList(aList);
INTERNED_IMMUTABLE_LISTS.put(producer, list);
return list;
}
}
public static <K, V> HashMap<K, V> hashMap(Consumer<BiBuilder<K,
V>> producer) {
HashMap<K, V> map = new HashMap<>();
producer.accept(map::put);
return map;
}
// cache of immutable maps per producer
private static final Map<Consumer<? extends BiBuilder<?, ?>>,
Map<?, ?>> INTERNED_IMMUTABLE_MAPS = new WeakHashMap<>();
public static <K, V> Map<K, V> immutableMap(Consumer<BiBuilder<K,
V>> producer) {
synchronized (INTERNED_IMMUTABLE_MAPS) {
// check if already interned
@SuppressWarnings("unchecked")
Map<K, V> map = (Map<K, V>)
INTERNED_IMMUTABLE_MAPS.get(producer);
if (map != null) return map;
}
// count elements produced
final int[] count = new int[1];
producer.accept((k, v) -> count[0]++);
// construct new map
HashMap<K, V> hMap = new HashMap<>(count[0] * 4 / 3);
producer.accept(hMap::put);
synchronized (INTERNED_IMMUTABLE_MAPS) {
// recheck (highly unlikely)
@SuppressWarnings("unchecked")
Map<K, V> map = (Map<K, V>)
INTERNED_IMMUTABLE_MAPS.get(producer);
if (map != null) return map;
// put it into cache and return
map = Collections.unmodifiableMap(hMap);
INTERNED_IMMUTABLE_MAPS.put(producer, map);
return map;
}
}
}
More information about the lambda-dev
mailing list