Basics, failure semantics on 26 vs 27, lazy collections, API across 25/26/27, preview-flag traps and a JMH read-path benchmark (jars fetched and sha1-checked, not committed). Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01TF9JWFvJSNm6HVzswzZU5a
36 lines
1.5 KiB
Java
36 lines
1.5 KiB
Java
// The three classic ways to hold a value that is expensive to build. Plain Java, no preview features.
|
|
public class OldWays {
|
|
static class Expensive {
|
|
final String how;
|
|
Expensive(String how) { this.how = how; System.out.println(" [init] building Expensive via " + how); }
|
|
}
|
|
|
|
// 1. Eager: built when OldWays is initialised, which is before main runs, whether or not anyone uses it.
|
|
static final Expensive EAGER = new Expensive("eager static final");
|
|
|
|
// 2. Holder idiom: the JVM initialises Holder the first time it is touched, and does so exactly once.
|
|
static class Holder { static final Expensive VALUE = new Expensive("holder idiom"); }
|
|
static Expensive holder() { return Holder.VALUE; }
|
|
|
|
// 3. Double-checked locking: correct only because the field is volatile.
|
|
private static volatile Expensive dcl;
|
|
static Expensive doubleChecked() {
|
|
Expensive local = dcl;
|
|
if (local == null) {
|
|
synchronized (OldWays.class) {
|
|
local = dcl;
|
|
if (local == null) dcl = local = new Expensive("double-checked locking");
|
|
}
|
|
}
|
|
return local;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
System.out.println("main starts (the eager value already exists)");
|
|
System.out.println("first holder() call:"); holder();
|
|
System.out.println("second holder() call:"); holder();
|
|
System.out.println("first doubleChecked() call:"); doubleChecked();
|
|
System.out.println("second doubleChecked() call:"); doubleChecked();
|
|
}
|
|
}
|