Files
Claude 814c32b5ce Add lazy-constants module: LazyConstant (JEP 531) against the holder idiom and double-checked locking
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
2026-09-24 12:27:27 +00:00

63 lines
4.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# Lazy Constants (JEP 531, third preview in JDK 27) against the holder idiom and double-checked locking.
# Regenerates every file in output/. JDK25=/path JDK26=/path JDK27=/path [JDK21=/path] ./run.sh
set -uo pipefail
unset JAVA_TOOL_OPTIONS
HERE="$(cd "$(dirname "$0")" && pwd)"
JDK25="${JDK25:-/opt/jdks/jdk-25.0.4.1+1}"; JDK26="${JDK26:-/opt/jdks/jdk-26.0.2.1+1}"; JDK27="${JDK27:-/opt/jdks/jdk27}"; JDK21="${JDK21:-}"
OUT="$HERE/output"; mkdir -p "$OUT"; B="$(mktemp -d)"; trap 'rm -rf "$B"' EXIT
cd "$HERE"
t() { "$1/bin/java" -version 2>&1 | sed -n 2p | sed 's/.*(build \(.*\))/\1/'; }
rel() { case "$1" in "$JDK25") echo 25;; "$JDK26") echo 26;; "$JDK27") echo 27;; *) echo 21;; esac; }
mk() { mktemp -d -p "$B"; }
# plain compile + run
cr() { local jdk="$1" src="$2" cls="$3" o; o="$(mk)"
echo "\$ javac $src && java $cls ($(t "$jdk"))"
"$jdk/bin/javac" -d "$o" "$src" 2>&1 && "$jdk/bin/java" -cp "$o" "$cls" 2>&1; }
# preview compile + run
crp() { local jdk="$1" src="$2" cls="$3" o r; o="$(mk)"; r="$(rel "$jdk")"
echo "\$ javac --enable-preview --release $r $src && java --enable-preview $cls ($(t "$jdk"))"
"$jdk/bin/javac" --enable-preview --release "$r" -d "$o" "$src" 2>&1 | grep -v '^Note:'
"$jdk/bin/java" --enable-preview -cp "$o" "$cls" 2>&1; }
# preview compile only
cop() { local jdk="$1" src="$2" o r; o="$(mk)"; r="$(rel "$jdk")"
echo "\$ javac --enable-preview --release $r $src ($(t "$jdk"))"
"$jdk/bin/javac" --enable-preview --release "$r" -d "$o" "$src" 2>&1 | grep -v '^Note:'; echo "exit=${PIPESTATUS[0]}"; }
# compile only, no flags
co() { local jdk="$1" src="$2" o; o="$(mk)"
echo "\$ javac $src ($(t "$jdk"))"
"$jdk/bin/javac" -d "$o" "$src" 2>&1 | grep -v '^Note:'; echo "exit=${PIPESTATUS[0]}"; }
all3() { local fn="$1"; shift; [ -n "$JDK21" ] && { "$fn" "$JDK21" "$@"; echo; }; "$fn" "$JDK25" "$@"; echo; "$fn" "$JDK27" "$@"; }
# 01 - the classic idioms: when does each one build the value?
{ all3 cr src/OldWays.java OldWays; } > "$OUT/01-old-ways.txt"
# 02 - LazyConstant basics on 27
{ crp "$JDK27" src/Basics.java Basics; echo; crp "$JDK27" src/ToStringStates.java ToStringStates; echo; crp "$JDK27" src/Service.java Service; } > "$OUT/02-basics.txt"
# 03 - failure semantics changed between 26 and 27
{ crp "$JDK26" src/Failures.java Failures; echo; crp "$JDK27" src/Failures.java Failures; } > "$OUT/03-failures.txt"
# 04 - lazy collections
{ crp "$JDK27" src/LazyCollections.java LazyCollections; echo; cop "$JDK26" src/LazyCollections.java; } > "$OUT/04-collections.txt"
# 05 - the API across 25, 26 and 27
api() { local jdk="$1" cls="$2"; echo "\$ javap $cls ($(t "$jdk"))"; "$jdk/bin/javap" "$cls" 2>&1; }
{ api "$JDK25" java.lang.StableValue; echo; api "$JDK26" java.lang.LazyConstant; echo; api "$JDK27" java.lang.LazyConstant; echo
for j in "$JDK26" "$JDK27"; do for c in List Map Set; do echo "\$ javap java.util.$c | grep ofLazy ($(t "$j"))"; "$j/bin/javap" java.util.$c 2>&1 | grep ofLazy; done; echo; done
crp "$JDK25" src/StableValue25.java StableValue25; echo
cop "$JDK26" broken/StillStable.java; echo; cop "$JDK27" broken/StillStable.java; echo
cop "$JDK26" broken/RemovedApi.java; echo; cop "$JDK27" broken/RemovedApi.java; echo
cop "$JDK27" broken/ReassignInSupplier.java; } > "$OUT/05-api-across-releases.txt"
# 06 - preview flags and class files
{ co "$JDK27" broken/NoPreviewFlag.java; echo
o="$(mk)"; "$JDK27/bin/javac" --enable-preview --release 27 -d "$o" src/Basics.java 2>&1 | grep -v '^Note:'
echo "\$ javap -v Basics | grep 'major\|minor' (27+35, compiled with --enable-preview --release 27)"; "$JDK27/bin/javap" -v -cp "$o" Basics | grep 'major\|minor'; echo
echo "\$ java Basics (27+35, without --enable-preview)"; "$JDK27/bin/java" -cp "$o" Basics 2>&1 | head -2; echo
echo "\$ java --enable-preview Basics ($(t "$JDK26"), class file built by 27)"; "$JDK26/bin/java" --enable-preview -cp "$o" Basics 2>&1 | head -2; } > "$OUT/06-preview-flags.txt"
# 07 - JMH read-path benchmark (about 3 minutes; needs jmh/fetch.sh first; set RUN_JMH=0 to skip)
if [ "${RUN_JMH:-1}" = 1 ] && [ -f jmh/lib/jmh-core-1.37.jar ]; then JDK27="$JDK27" jmh/run-jmh.sh > /dev/null; else echo "skipped 07-jmh.txt"; fi
echo done