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:
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"); }
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user