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 14:47:46 +00:00
committed by Claude
co-authored by Claude Sonnet 5
commit da55954922
150 changed files with 4968 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
/**
* JEP 532, Primitive Types in Patterns, instanceof, and switch (fifth preview).
*
* <p>Until now patterns worked on reference types only. With this preview a pattern can name a
* primitive type, and the test is "can this value be converted to that type WITHOUT losing
* information?" Explained in docs/05-primitive-patterns.md. Compile and run with --enable-preview.
*/
public class PrimitivePatterns {
record Reading(int celsius) {}
public static void main(String[] args) {
exactness();
switchOnLong();
switchOnObject();
recordPattern();
}
/** instanceof with a primitive type asks: is this an EXACT conversion? */
static void exactness() {
System.out.println("--- instanceof <primitive>: an exact-conversion test, not a cast");
int small = 100, big = 300;
boolean a = small instanceof byte;
boolean b = big instanceof byte;
System.out.println("100 instanceof byte = " + a);
System.out.println("300 instanceof byte = " + b + " (a byte holds -128..127)");
Check.that(a && !b, "100 converts to byte exactly, 300 does not");
if (small instanceof byte narrow) {
System.out.println("binding: byte narrow = " + narrow);
}
int precise = 16_777_217; // 2^24 + 1: the first int a float cannot hold
boolean f1 = 16_777_216 instanceof float;
boolean f2 = precise instanceof float;
System.out.println("16_777_216 instanceof float = " + f1);
System.out.println("16_777_217 instanceof float = " + f2 + " (float has a 24-bit significand)");
Check.that(f1 && !f2, "int to float is exact up to 2^24 and lossy after");
}
/** switch over a long, with a primitive pattern and a guard. */
static String classify(long value) {
return switch (value) {
case 0L -> "zero";
case 1L -> "one";
case long v when v < 0 -> "negative (" + v + ")";
case long v -> "positive (" + v + ")";
};
}
static void switchOnLong() {
System.out.println("--- switch on a long, with pattern labels and a guard");
for (long v : new long[] {0, 1, -7, 9_000_000_000L}) {
System.out.println("classify(" + v + ") = " + classify(v));
}
Check.that(classify(0).equals("zero") && classify(-7).startsWith("negative"), "long switch dispatches on constants, then patterns");
}
/** switch over an Object: primitive patterns match the boxed types they correspond to. */
static String describe(Object o) {
return switch (o) {
case int i when i > 1000 -> "a large int " + i;
case int i -> "an int " + i;
case long l -> "a long " + l;
case double d -> "a double " + d;
case String s -> "a String of length " + s.length();
default -> "something else: " + o;
};
}
static void switchOnObject() {
System.out.println("--- switch on an Object: an Integer matches 'case int'");
Object[] samples = {7, 5000, 7L, 2.5, "hello", 'x'};
for (Object o : samples) {
System.out.println("describe(" + o.getClass().getSimpleName() + " " + o + ") = " + describe(o));
}
Check.that(describe(5000).equals("a large int 5000"), "an Integer 5000 matches case int with a guard");
}
/** Record patterns can now narrow a component: Reading.celsius is an int, the pattern asks for a byte. */
static void recordPattern() {
System.out.println("--- record pattern with a narrowing primitive component");
Object[] readings = {new Reading(36), new Reading(4_000)};
for (Object o : readings) {
String verdict = switch (o) {
case Reading(byte c) -> "fits in a byte: " + c;
case Reading(int c) -> "needs a full int: " + c;
default -> "not a reading";
};
System.out.println(o + " -> " + verdict);
}
Check.that(readings[0] instanceof Reading(byte _) && !(readings[1] instanceof Reading(byte _)),
"Reading(byte c) matches 36 but not 4000");
}
}