LazyValue.java

package uk.org.lidalia.lang;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly;
import static uk.org.lidalia.lang.Exceptions.throwUnchecked;

/**
 * Wraps and exposes the lazily evaluated result of an expression passed as a Callable to the constructor.
 *
 * @param <T> the type of the value wrapped by this class
 */
public class LazyValue<T> implements Callable<T> {

    private final FutureTask<T> supplier;

    /**
     * @param supplier contains the expression (as a Callable) that will create the result; this will be evaluated once
     *                 and only once
     */
    public LazyValue(final Callable<T> supplier) {
        this.supplier = new FutureTask<>(supplier);
    }

    /**
     * @throws Exception thrown by the original caller, unwrapped
     * @return the result of the expression passed to the constructor; this is evaluated the first time this method is called,
     *         subsequent calls return the same result without re-evaluating it. Concurrent calls block until the first execution
     *         is complete.
     */
    @Override
    public T call() {
        supplier.run();
        try {
            return getUninterruptibly(supplier);
        } catch (ExecutionException e) {
            return throwUnchecked(e.getCause(), null);
        }
    }

    @Override
    public String toString() {
        if (supplier.isDone()) return call().toString();
        else return "not yet evaluated";
    }
}