Monday, April 20, 2009

Fluent assertions, bonus questions

Alex Ruiz tipped me off to an update to FEST, a fluent assertion library. Thanks, Alex!

Bonus questions. Everyone know this idiom:

<K, V> V get(final K key) {
    final V value = concurrentMap.get(key);
    if (null != value) return value;
    concurrentMap.putIfAbsent(key, factoryMethodForV());
    return concurrentMap.get(key);
}

Easier question: How do you support valid null values for the concurrent map? (Hint: monads)

Harder question: Suppose factoryMethodForV() is expensive. How do you guarantee it is only ever called once for a given key?

UPDATE: Fixed some typos.

3 comments:

Anonymous said...

I'll take a shot at the harder of the two:

public static interface ValueFactory<K, V> {
 V create(K key);
}

public V get(final K key) {
 final ValueHolder<K, V> newValueHolder = new ValueHolder<K, V>(key, this.valueFactory);
 final ValueHolder<K, V> prevValueHolder = this.concurrentMap.putIfAbsent(key, newValueHolder);
 return prevValueHolder != null ? prevValueHolder.value() : newValueHolder.value();
}

private static class ValueHolder<K, V> {
 private final Object lock = new Object();
 private final K key;
 private final ValueFactory<K,V> valueFactory;

 private V value;

 private ValueHolder(final K key, final ValueFactory<K, V> valueFactory) {
  this.key = key;
  this.valueFactory = valueFactory;
 }

 private V value() {
  synchronized (this.lock) {
   if (this.value == null) {
    this.value = this.valueFactory.create(this.key);
   }

   return this.value;
  }
 }
}

Anonymous said...

I'll take a shot at the harder of the two:

public static interface ValueFactory<K, V> {
 V create(K key);
}

public V get(final K key) {
 final ValueHolder<K, V> newValueHolder = new ValueHolder<K, V>(key, this.valueFactory);
 final ValueHolder<K, V> prevValueHolder = this.concurrentMap.putIfAbsent(key, newValueHolder);
 return prevValueHolder != null ? prevValueHolder.value() : newValueHolder.value();
}

private static class ValueHolder<K, V> {
 private final Object lock = new Object();
 private final K key;
 private final ValueFactory<K,V> valueFactory;

 private V value;

 private ValueHolder(final K key, final ValueFactory<K, V> valueFactory) {
  this.key = key;
  this.valueFactory = valueFactory;
 }

 private V value() {
  synchronized (this.lock) {
   if (this.value == null) {
    this.value = this.valueFactory.create(this.key);
   }

   return this.value;
  }
 }
}

Brian Oxley said...

One of the best programmers at work left this comment. Thanks, you know who you are!