Skip to content

Commit 8293867

Browse files
feat: Added Lazy
1 parent 017145f commit 8293867

1 file changed

Lines changed: 84 additions & 0 deletions

File tree

src/main/java/gentle/Lazy.java

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package gentle;
2+
3+
import lombok.AccessLevel;
4+
import lombok.NonNull;
5+
import lombok.RequiredArgsConstructor;
6+
7+
import java.util.concurrent.atomic.AtomicReference;
8+
import java.util.function.Supplier;
9+
10+
/**
11+
* Represents a lazily-initialized value.
12+
* <p>
13+
* A {@code Lazy} wraps a {@link Supplier} that is only executed once — the first
14+
* time {@link #get()} is called. The computed value is cached and returned
15+
* for all subsequent calls.
16+
*
17+
* <p>This is useful for:
18+
* <ul>
19+
* <li>Expensive computations that should be deferred until needed</li>
20+
* <li>Implementing on-demand initialization</li>
21+
* <li>Avoiding unnecessary work in object construction</li>
22+
* </ul>
23+
*
24+
* <p>Example:
25+
* <pre>{@code
26+
* Lazy<Config> config = Lazy.of(() -> loadConfigFromDisk());
27+
*
28+
* // The configuration will only be loaded here, the first time get() is called:
29+
* Config c = config.get();
30+
* }</pre>
31+
*
32+
* <p><strong>Thread Safety:</strong><br>
33+
* This implementation is thread-safe. The supplier may be executed more than once
34+
* in race conditions, but the stored value is guaranteed to be the final one set.
35+
*
36+
* @param <T> the type of the lazily-computed value
37+
*/
38+
@RequiredArgsConstructor (access = AccessLevel.PRIVATE)
39+
public final class Lazy<T> {
40+
41+
/**
42+
* Internal marker object indicating that no value has been computed yet.
43+
*/
44+
private static final Object UNSET = new Object();
45+
46+
@NonNull
47+
private final Supplier<T> supplier;
48+
49+
/**
50+
* Stores either {@link #UNSET} or the computed value.
51+
*/
52+
private final AtomicReference<Object> ref = new AtomicReference<>(UNSET);
53+
54+
/**
55+
* Creates a new lazy value backed by the given supplier.
56+
* <p>
57+
* The supplier is <em>not</em> executed until {@link #get()} is called.
58+
*
59+
* @param supplier the computation to defer
60+
* @param <T> the type of the eventual value
61+
* @return a new {@code Lazy} instance
62+
*/
63+
public static <T> Lazy<T> of(@NonNull Supplier<T> supplier) {
64+
return new Lazy<>(supplier);
65+
}
66+
67+
/**
68+
* Returns the computed value, computing it on first access.
69+
* <p>
70+
* If multiple threads call {@link #get()} simultaneously, the supplier
71+
* may be invoked multiple times, but the first stored result is the
72+
* one consistently returned afterward.
73+
*
74+
* @return the value, computing it lazily if needed
75+
*/
76+
@SuppressWarnings("unchecked")
77+
public T get() {
78+
var v = ref.get();
79+
if (v != UNSET) return (T) v;
80+
T computed = supplier.get();
81+
ref.compareAndSet(UNSET, computed);
82+
return computed;
83+
}
84+
}

0 commit comments

Comments
 (0)