package com.googlecode.totallylazy.functions;
import com.googlecode.totallylazy.Either;
import com.googlecode.totallylazy.Memory;
import java.util.concurrent.Callable;
import static com.googlecode.totallylazy.Closeables.safeClose;
import static com.googlecode.totallylazy.Unchecked.cast;
public abstract class Lazy<T> implements Function0<T>, Memory {
private final Object lock = new Object();
private volatile Either<Exception, T> state;
protected abstract T get() throws Exception;
public static <T> Lazy<T> lazy(Callable<? extends T> callable) {
if(callable instanceof Lazy) return cast(callable);
return new Lazy<T>() {
@Override
protected T get() throws Exception {
return callable.call();
}
};
}
// Thread-safe double check idiom (Effective Java 2nd edition p.283)
public final T call() throws Exception {
if (state == null) {
synchronized (lock) {
if (state == null) {
try {
state = Either.right(get());
} catch (Exception e) {
state = Either.left(e);
}
}
}
}
if(state.isLeft()){
throw state.left();
}
return state.right();
}
public void forget() {
close();
}
@Override
public void close() {
synchronized (lock) {
if(state != null) {
safeClose(state.value());
state = null;
}
}
}
}