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
+11
View File
@@ -0,0 +1,11 @@
import java.time.*;
import java.util.*;
import java.util.stream.*;
public class AotApp {
public static void main(String[] a) {
long t0 = System.nanoTime();
var m = IntStream.range(0, 2000).boxed().collect(Collectors.groupingBy(i -> i % 7, TreeMap::new, Collectors.summingInt(i -> i)));
String s = String.format("%s %s %s", m, LocalDate.of(2026, 9, 21).getDayOfWeek(), Duration.ofSeconds(90));
System.out.println(s.length() > 10 ? "ok" : "no");
}
}
+44
View File
@@ -0,0 +1,44 @@
import java.lang.management.ManagementFactory;
import java.net.http.HttpClient;
import java.nio.ByteOrder;
import java.util.List;
import java.util.UUID;
/**
* Public API that first appeared in Java 26 and needs no --enable-preview. Each call is asserted, so the
* run is the proof. The list was produced by diffing javap dumps of 25 and 26 (docs/output/50-*).
* Chapter: docs/11-recap-26.md
*/
public class Api26 {
public static void main(String[] args) throws Exception {
// String: Unicode case-folding comparisons, no more toLowerCase(Locale.ROOT) allocations
Check.that("STRASSE".equalsFoldCase("straße"), "\"STRASSE\".equalsFoldCase(\"stra\" + sharp s + \"e\") is true (full case folding)");
Check.that(!"STRASSE".equalsIgnoreCase("straße"), "equalsIgnoreCase says false for the same pair (simple folding only)");
Check.that("apple".compareToFoldCase("BANANA") < 0, "\"apple\".compareToFoldCase(\"BANANA\") < 0");
List<String> names = new java.util.ArrayList<>(List.of("b", "A", "c", "B"));
names.sort(String.UNICODE_CASEFOLD_ORDER);
Check.that(names.get(0).equalsFoldCase("a") && names.get(2).equalsFoldCase("b"), "sorted with String.UNICODE_CASEFOLD_ORDER: " + names);
// UUID: a v7-shaped UUID for a given instant
UUID u = UUID.ofEpochMillis(1_700_000_000_000L);
Check.that(u.version() == 7, "UUID.ofEpochMillis(..).version() == 7");
Check.that(u.toString().startsWith("018bcfe5-6800"), "the first 48 bits are the timestamp: " + u.toString().substring(0, 13) + "-...");
// Process is AutoCloseable now
try (Process p = new ProcessBuilder("true").start()) {
Check.that(p.waitFor() == 0, "try-with-resources on Process (implements Closeable in 26)");
}
// MemoryMXBean: cumulative CPU time spent in GC
long gcCpu = ManagementFactory.getMemoryMXBean().getTotalGcCpuTime();
Check.that(gcCpu >= 0, "MemoryMXBean.getTotalGcCpuTime() exists and is non-negative");
// ByteOrder became an enum
Check.that(ByteOrder.BIG_ENDIAN instanceof Enum<?>, "ByteOrder is an enum: " + java.util.Arrays.toString(ByteOrder.values()));
// HTTP/3 in the client API
HttpClient c = HttpClient.newBuilder().version(HttpClient.Version.HTTP_3).build();
Check.that(c.version() == HttpClient.Version.HTTP_3, "HttpClient.Version.HTTP_3 exists and is accepted by the builder");
Check.that(Character.UnicodeBlock.SIDETIC != null, "Character.UnicodeBlock.SIDETIC exists (Unicode 17)");
}
}
+15
View File
@@ -0,0 +1,15 @@
/**
* Tiny assertion helper so every demo is self-checking: a claim that stops being true turns the
* run red instead of quietly printing something different. Passing checks are echoed, so the
* transcript shows exactly what was verified.
*/
final class Check {
private Check() {}
static void that(boolean condition, String claim) {
if (!condition) {
throw new AssertionError("CHECK FAILED: " + claim);
}
System.out.println("CHECK ok : " + claim);
}
}
+33
View File
@@ -0,0 +1,33 @@
import java.lang.reflect.Field;
/**
* JEP 500 (Java 26): "Prepare to Make Final Mean Final". Deep reflection on a final field
* (Field.setAccessible(true) followed by Field.setInt) used to work silently. On 26 it works but
* warns once; a future release will deny it unless you opt in.
*
* The same file is run five ways by scripts/recap26.sh; the transcript is docs/output/70-final-field-mutation.txt.
* Chapter: docs/11-recap-26.md
*/
public class FinalFieldMutation {
static class Config {
private final int port = 8080;
int port() { return port; }
}
public static void main(String[] args) throws Exception {
Config c = new Config();
Field f = Config.class.getDeclaredField("port");
f.setAccessible(true);
try {
f.setInt(c, 9090);
} catch (IllegalAccessException e) {
System.out.println("setInt refused : " + e.getMessage());
return;
}
// The field reads 9090 but port() still says 8080: 'final int port = 8080' is a constant variable, so javac
// copied the literal 8080 into port() at compile time. Nothing you write to the field can reach that copy.
// That silent disagreement is the reason the platform wants this to stop, not a hypothetical.
System.out.println("field reads : " + f.getInt(c));
System.out.println("port() returns : " + c.port());
}
}
+53
View File
@@ -0,0 +1,53 @@
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
import java.io.FileInputStream;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpOption;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
/**
* JEP 517 (Java 26): HTTP/3 for the HTTP Client API. The sandbox cannot reach a real HTTP/3 server (no UDP egress),
* so this shows the half that is checkable everywhere: a client that PREFERS HTTP/3 talking to a server that does not
* speak it (the JDK's own HttpsServer, HTTP/1.1) quietly falls back, and says so in response.version().
* args: keystore path, password
* Chapter: docs/11-recap-26.md
*/
public class Http3Fallback {
public static void main(String[] args) throws Exception {
KeyStore ks = KeyStore.getInstance("PKCS12");
try (var in = new FileInputStream(args[0])) { ks.load(in, args[1].toCharArray()); }
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, args[1].toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks);
SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
HttpsServer server = HttpsServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
server.setHttpsConfigurator(new HttpsConfigurator(ctx));
server.createContext("/", ex -> { byte[] b = "hello".getBytes(); ex.sendResponseHeaders(200, b.length); ex.getResponseBody().write(b); ex.close(); });
server.start();
int port = server.getAddress().getPort();
try (HttpClient client = HttpClient.newBuilder().sslContext(ctx).version(HttpClient.Version.HTTP_3).build()) {
HttpRequest req = HttpRequest.newBuilder(URI.create("https://localhost:" + port + "/")).GET().build();
HttpResponse<String> r = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println("client asked for : " + client.version());
System.out.println("server answered : " + r.version() + " " + r.statusCode() + " " + r.body());
HttpRequest strict = HttpRequest.newBuilder(URI.create("https://localhost:" + port + "/")).GET()
.setOption(HttpOption.H3_DISCOVERY, HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY).build();
try {
client.send(strict, HttpResponse.BodyHandlers.ofString());
System.out.println("HTTP_3_URI_ONLY : unexpectedly succeeded");
} catch (Exception e) {
System.out.println("HTTP_3_URI_ONLY : " + e.getClass().getName() + ": " + e.getMessage());
}
} finally {
server.stop(0);
}
}
}
+7
View File
@@ -0,0 +1,7 @@
// JEP 504 (Java 26) removed java.applet.*, javax.swing.JApplet and the AppletInitializer overload in java.beans.
// On 25 this compiles with deprecation warnings. On 26 it does not compile.
import java.applet.Applet;
public class AppletGone extends Applet {
@Override public void init() { System.out.println("applet init"); }
}
+7
View File
@@ -0,0 +1,7 @@
// Thread.stop() has thrown UnsupportedOperationException since 20. In 26 the method itself is gone.
public class ThreadStopGone {
public static void main(String[] args) {
Thread t = new Thread(() -> {});
t.stop();
}
}