Java 27 and 26: runnable demos and captured output for every JEP, plus version lanes

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B38FGKKam5SCGgwgduVAh3
This commit is contained in:
2026-09-21 15:08:50 +00:00
committed by Claude
co-authored by Claude Sonnet 5
commit f59c1de96d
152 changed files with 5049 additions and 0 deletions
+136
View File
@@ -0,0 +1,136 @@
#!/usr/bin/env bash
# The 21 -> 25 hub lane: every claim in ankurm.com/java-21-to-25-lts-features and /java-21-to-25-upgrade-guide-ai-prompts
# that can be checked on a JDK, checked on JDK 21, 25, 26 and 27.
# ./scripts/lanes.sh -> docs/output/80-*.txt ... 91-*.txt
set -uo pipefail
source "$(dirname "$0")/env.sh"
SRC="$ROOT/lanes/src"; B="$ROOT/build/lanes"; rm -rf "$B"; mkdir -p "$B"
jdk() { case "$1" in 21) echo "$JDK21";; 25) echo "$JDK25";; 26) echo "$JDK26";; 27) echo "$JDK27";; esac; }
scrub() { sed -i -E "s#$ROOT#<repo>#g; s#@[0-9a-f]{6,8}#@<hash>#g" "$@"; }
# javac with the JDK's own compiler; prints javac's words and the real exit code
jc() { local v="$1"; shift; local out rc; out="$("$(jdk "$v")/bin/javac" "$@" 2>&1)"; rc=$?
printf '%s\n' "$out" | grep -v -E '^(Note: |$)' | sed 's/^/ /'; echo " exit=$rc"; return $rc; }
# java with the JDK's own launcher
jr() { local v="$1"; shift; "$(jdk "$v")/bin/java" "$@" 2>&1 | sed 's/^/ /'; }
# JDK 23 and 24 are only used to pin down WHEN something changed; they run from the Corretto images
dj() { local v="$1"; shift; docker run --rm -v "$B:/b" "amazoncorretto:$v" "$@" 2>&1 | sed 's/^/ /'; }
djc() { local v="$1"; shift; local out rc; out="$(docker run --rm -v "$B:/b" -v "$SRC:/src:ro" "amazoncorretto:$v" javac "$@" 2>&1)"; rc=$?
printf '%s\n' "$out" | grep -v -E '^(Note: |$)' | sed 's/^/ /'; echo " exit=$rc"; return $rc; }
# ---------- 80: the four Java 21 features, compiled once with --release 21, run on 21, 25, 26, 27 ----------
{
echo "# One class file (javac 21 --release 21), four JVMs"
mkdir -p "$B/hub"; "$(jdk 21)/bin/javac" --release 21 -d "$B/hub" "$SRC/Check.java" "$SRC/HubExamples.java" 2>&1
for v in 21 25 26 27; do echo; echo "\$ java -cp hub HubExamples (JDK $v)"; jr $v -cp "$B/hub" HubExamples; done
} > "$OUT/80-hub-examples.txt"
# ---------- 81: scoped values, final in 25 ----------
{
echo "# ScopedValue (JEP 506). Preview API in 21, final in 25."
echo; echo "\$ javac ScopedValueDemo.java (JDK 21, no flag)"; jc 21 --release 21 -d "$B/sv21" "$SRC/Check.java" "$SRC/ScopedValueDemo.java"
for v in 25 26 27; do
echo; echo "\$ javac ScopedValueDemo.java (JDK $v, no flag)"; mkdir -p "$B/sv$v"
jc $v -d "$B/sv$v" "$SRC/Check.java" "$SRC/ScopedValueDemo.java" && { echo "\$ java ScopedValueDemo (JDK $v)"; jr $v -cp "$B/sv$v" ScopedValueDemo; }
done
} > "$OUT/81-scoped-values.txt"
# ---------- 82: structured concurrency, NOT final in 25 ----------
{
echo "# StructuredTaskScope (JEP 505 in 25). Fifth preview in 25, sixth in 26, seventh in 27."
for v in 25 26 27; do
echo; echo "\$ javac StructuredHub.java (JDK $v, no flag)"; jc $v -d "$B/st$v-nopreview" "$SRC/Check.java" "$SRC/StructuredHub.java"
echo "\$ javac --enable-preview --release $v StructuredHub.java (JDK $v)"; mkdir -p "$B/st$v"
jc $v --enable-preview --release $v -Xlint:-preview -d "$B/st$v" "$SRC/Check.java" "$SRC/StructuredHub.java" \
&& { echo "\$ java --enable-preview StructuredHub (JDK $v)"; jr $v --enable-preview -cp "$B/st$v" StructuredHub; }
done
for v in 26 27; do echo; echo "\$ javac --enable-preview --release $v StructuredHubNew.java (JDK $v)"; mkdir -p "$B/stn$v"
jc $v --enable-preview --release $v -Xlint:-preview -d "$B/stn$v" "$SRC/Check.java" "$SRC/StructuredHubNew.java" \
&& { echo "\$ java --enable-preview StructuredHubNew (JDK $v)"; jr $v --enable-preview -cp "$B/stn$v" StructuredHubNew; }
done
} > "$OUT/82-structured-not-final.txt"
# ---------- 89: the Joiner factory methods on 25, 26, 27 ----------
{
echo "# javap --module java.base -public 'java.util.concurrent.StructuredTaskScope\$Joiner', static factories only"
for v in 25 26 27; do echo; echo "== JDK $v"; "$(jdk $v)/bin/javap" --module java.base -public 'java.util.concurrent.StructuredTaskScope$Joiner' 2>&1 \
| grep -E '^ public static' | sed -E 's/java\.util\.concurrent\.//g; s/java\.util\.stream\.//g; s/java\.util\.function\.//g; s/java\.util\.//g; s/java\.lang\.//g'; done
} > "$OUT/89-joiner-api.txt"
# ---------- 83: finalization ----------
{
echo "# Is finalization removed by default in 25? (JEP 421 deprecated it for removal in 18)"
for v in 21 25 26 27; do mkdir -p "$B/fin$v"; "$(jdk $v)/bin/javac" -Xlint:-removal -d "$B/fin$v" "$SRC/FinalizerDefault.java" 2>&1 | grep -v -E '^(Note: |$)'
echo; echo "\$ java FinalizerDefault (JDK $v)"; jr $v -cp "$B/fin$v" FinalizerDefault
echo "\$ java --finalization=disabled FinalizerDefault (JDK $v)"; jr $v --finalization=disabled -cp "$B/fin$v" FinalizerDefault; done
} > "$OUT/83-finalization.txt"
# ---------- 84: security manager ----------
{
echo "# System.setSecurityManager(new SecurityManager())"
for v in 21 25; do mkdir -p "$B/sm$v"; "$(jdk $v)/bin/javac" -Xlint:-removal -d "$B/sm$v" "$SRC/SecurityManagerGone.java" 2>&1 | grep -v -E '^(Note: |$)'
echo; echo "\$ java SecurityManagerGone (JDK $v)"; jr $v -cp "$B/sm$v" SecurityManagerGone; done
} > "$OUT/84-security-manager.txt"
# ---------- 85: Thread.stop / suspend / resume ----------
{
echo "# Thread.stop(), suspend(), resume(): when did they actually go?"
for v in 21 25; do mkdir -p "$B/ts$v"; "$(jdk $v)/bin/javac" -Xlint:-removal -d "$B/ts$v" "$SRC/ThreadStopRuntime.java" 2>&1 | grep -v -E '^(Note: |$)'
echo; echo "\$ java ThreadStopRuntime (JDK $v)"; jr $v -cp "$B/ts$v" ThreadStopRuntime; done
for v in 21 25 26; do echo; echo "\$ javac ThreadSuspendGone.java (JDK $v)"; jc $v -d "$B/sus$v" "$SRC/ThreadSuspendGone.java"; done
for v in 23 24; do echo; echo "\$ javac ThreadSuspendGone.java (JDK $v, Corretto image)"; mkdir -p "$B/sus$v"; djc $v -d /b/sus$v /src/ThreadSuspendGone.java; done
} > "$OUT/85-thread-stop-suspend.txt"
# ---------- 86: Unsafe and JNI warnings ----------
{
echo "# sun.misc.Unsafe memory access (JEP 498) and JNI (JEP 472): what does the JVM say?"
for v in 21 25; do mkdir -p "$B/us$v"; "$(jdk $v)/bin/javac" -Xlint:-removal -d "$B/us$v" "$SRC/UnsafeWarning.java" >/dev/null 2>&1
echo; echo "\$ java UnsafeWarning (JDK $v)"; jr $v -cp "$B/us$v" UnsafeWarning; done
echo; echo "\$ java UnsafeWarning (JDK 24, Corretto image)"; dj 24 java -cp /b/us21 UnsafeWarning
for v in 21 25; do mkdir -p "$B/jni$v"; "$(jdk $v)/bin/javac" -d "$B/jni$v" "$SRC/JniWarning.java" 2>&1
echo; echo "\$ java JniWarning (JDK $v)"; jr $v -cp "$B/jni$v" JniWarning
echo "\$ java --enable-native-access=ALL-UNNAMED JniWarning (JDK $v)"; jr $v --enable-native-access=ALL-UNNAMED -cp "$B/jni$v" JniWarning; done
echo; echo "\$ java JniWarning (JDK 24, Corretto image)"; dj 24 java -cp /b/jni21 JniWarning
} > "$OUT/86-unsafe-and-jni.txt"
# ---------- 87: pinning ----------
{
echo "# 4 virtual threads on ONE carrier, each sleeping 200 ms inside synchronized (JEP 491, Java 24)"
for v in 21 25 26 27; do mkdir -p "$B/pin$v"; "$(jdk $v)/bin/javac" -d "$B/pin$v" "$SRC/PinningDemo.java" 2>&1
echo; echo "\$ java -Djdk.virtualThreadScheduler.parallelism=1 -Djdk.virtualThreadScheduler.maxPoolSize=1 PinningDemo (JDK $v)"
jr $v -Djdk.virtualThreadScheduler.parallelism=1 -Djdk.virtualThreadScheduler.maxPoolSize=1 -cp "$B/pin$v" PinningDemo; done
for v in 23 24; do echo; echo "\$ java -Djdk.virtualThreadScheduler.parallelism=1 -Djdk.virtualThreadScheduler.maxPoolSize=1 PinningDemo (JDK $v, Corretto image)"
dj $v java -Djdk.virtualThreadScheduler.parallelism=1 -Djdk.virtualThreadScheduler.maxPoolSize=1 -cp /b/pin21 PinningDemo; done
} > "$OUT/87-pinning.txt"
# ---------- 88: non-generational ZGC ----------
{
echo "# -XX:+UseZGC -XX:-ZGenerational -Xlog:gc+init -version : generational ZGC is the only ZGC from Java 24 (JEP 490)"
keep='Version:|Using|Generational|Ignoring|Unrecognized|obsolete|Error: Could'
for v in 21 25 26 27; do echo; echo "\$ java -XX:+UseZGC -XX:-ZGenerational -Xlog:gc+init -version (JDK $v)"
jr $v -XX:+UseZGC -XX:-ZGenerational -Xlog:gc+init -version | grep -E "$keep"; done
for v in 23 24; do echo; echo "\$ java -XX:+UseZGC -XX:-ZGenerational -Xlog:gc+init -version (JDK $v, Corretto image)"
dj $v java -XX:+UseZGC -XX:-ZGenerational -Xlog:gc+init -version | grep -E "$keep"; done
} > "$OUT/88-zgc-generational.txt"
# ---------- 90: unnamed variables and compact source files ----------
{
echo "# _ (unnamed variables and patterns) and compact source files with instance main()"
echo; echo "\$ javac UnnamedVariables.java (JDK 21, no flag)"; jc 21 -d "$B/un21" "$SRC/UnnamedVariables.java"
for v in 25; do echo; echo "\$ javac UnnamedVariables.java (JDK $v, no flag)"; mkdir -p "$B/un$v"
jc $v -d "$B/un$v" "$SRC/UnnamedVariables.java" && { echo "\$ java UnnamedVariables (JDK $v)"; jr $v -cp "$B/un$v" UnnamedVariables; }; done
echo; echo "\$ java CompactHello.java (JDK 21, no flag)"; jr 21 "$SRC/CompactHello.java"
echo; echo "\$ java CompactHello.java (JDK 25, no flag)"; jr 25 "$SRC/CompactHello.java"
} > "$OUT/90-unnamed-and-compact.txt"
# ---------- 91: JEP 500 on 27 (70-final-field-mutation.txt covers 25 and 26) ----------
{
echo "# Reflection writing to a final field on JDK 27: same behaviour as 26 (compare 70-final-field-mutation.txt)"
mkdir -p "$B/ffm27"; "$JDK27/bin/javac" -d "$B/ffm27" "$ROOT/recap26/src/FinalFieldMutation.java" 2>&1 | grep -v -E '^(Note: |$)'
echo; echo "=== JDK 27, defaults"; jr 27 -cp "$B/ffm27" FinalFieldMutation
echo; echo "=== JDK 27, --illegal-final-field-mutation=deny"; jr 27 --illegal-final-field-mutation=deny -cp "$B/ffm27" FinalFieldMutation
} > "$OUT/91-final-field-mutation-27.txt"
scrub "$OUT"/8[0-9]-*.txt "$OUT"/90-*.txt "$OUT"/91-*.txt
echo "wrote $OUT/80..91"