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 @@
|
||||
Review the attached Java class and convert it to a Java 21 record if it is a pure data carrier. Preserve all validation from the old constructor inside a compact constructor. Flag fields that prevent conversion (e.g. mutable state, inheritance) and explain why.
|
||||
@@ -0,0 +1 @@
|
||||
Refactor this Java code to use Java 21 pattern matching for switch. Introduce a sealed interface if the types form a closed hierarchy. Ensure the switch is exhaustive and remove all redundant casts and intermediate variables.
|
||||
@@ -0,0 +1 @@
|
||||
Find every usage of Executors.newFixedThreadPool and Executors.newCachedThreadPool in this project. Replace with Executors.newVirtualThreadPerTaskExecutor() where the tasks are I/O-bound. List any cases where platform threads should be kept (CPU-bound work, native frames on the stack, and on Java 21 to 23 also synchronized blocks that block, which pin the carrier thread until Java 24) and justify each decision.
|
||||
@@ -0,0 +1 @@
|
||||
Rewrite this code to use Java 21 sequenced collection APIs (getFirst, getLast, reversed) instead of list.get(0), list.get(list.size()-1), and manual reversal. Keep behaviour identical.
|
||||
@@ -0,0 +1 @@
|
||||
Identify ThreadLocal usages in this file. Propose a migration to Java 25 ScopedValue, showing before/after code and explaining why ScopedValue is safer under virtual threads and structured concurrency.
|
||||
@@ -0,0 +1 @@
|
||||
Refactor this CompletableFuture.allOf pipeline to use StructuredTaskScope. Note that StructuredTaskScope is still a preview API in Java 25, 26 and 27, so the build needs --enable-preview and the code must use the factory-method names of the JDK it targets (Joiner.anySuccessfulResultOrThrow() on 25, anySuccessfulOrThrow() on 26 and 27). Preserve error propagation semantics and show what happens on cancellation. Explain the difference from the original CompletableFuture approach.
|
||||
@@ -0,0 +1 @@
|
||||
Here is my pom.xml targeting Java 21. Update it to target Java 25. Bump Spring Boot to the latest 3.5.x or 4.x release (3.4.x is documented only up to Java 24), Hibernate to 7.x (which needs Jakarta Persistence 3.2), Lombok to 1.18.40 or later, JUnit to 6.x, and Mockito to its current 5.x release. List any dependency that does not have a Java 25 compatible version and suggest alternatives.
|
||||
@@ -0,0 +1 @@
|
||||
Scan this Java file for usages of SecurityManager, Thread.stop/suspend/resume, Object.finalize, sun.misc.Unsafe memory methods, System.loadLibrary and other JNI loading, and the old java.net.URL constructors. For each finding, say which Java release changed it (SecurityManager: cannot be installed since 24; Thread.suspend/resume: still compile on 21, gone by 23; Thread.stop: throws UnsupportedOperationException on 21 and 25, removed in 26; finalize: still runs, deprecated for removal; Unsafe memory access and JNI loading: run-time warnings from 24) and give a replacement with a before/after code snippet.
|
||||
@@ -0,0 +1 @@
|
||||
Review the attached Maven/Gradle build file and list every --enable-preview compiler and runtime argument. For each one, name the preview feature the code actually uses. Remove the flag only if that feature is final in Java 25 (scoped values, JEP 506, are final in 25; StructuredTaskScope is still a preview API in 25, 26 and 27, so a project that uses it must keep the flag). Explain each decision.
|
||||
@@ -0,0 +1 @@
|
||||
Apply these Java 25 idioms to this file: records for data carriers, pattern-matching switch for type checks, sequenced collection APIs (getFirst/getLast), and ScopedValue instead of ThreadLocal. Preserve behaviour exactly and add a comment for each change explaining why the new form is preferred.
|
||||
@@ -0,0 +1 @@
|
||||
Before I flip my executors to virtual threads on Java 25, audit this class for: ThreadLocal usage, JNI calls or native frames that stay on the stack while blocking (these still pin the carrier), synchronized blocks around I/O (harmless on Java 24 and later, pinning on 21 to 23), and any code that assumes a bounded thread pool. Report risks with line numbers and a severity (blocking/warning/low).
|
||||
@@ -0,0 +1 @@
|
||||
Act as a Java 25 upgrade reviewer. Given the attached project files, produce a prioritized checklist of upgrade tasks, group them by risk (blocking / warning / nice-to-have), and estimate effort in developer-hours per group.
|
||||
@@ -0,0 +1 @@
|
||||
Act as a Java 25 to Java 27 upgrade reviewer. Scan the attached project for: reflection that writes to final fields (Field.setAccessible followed by Field.set on a final field; Java 26 warns, JEP 500), StructuredTaskScope code that uses the 25 names (Joiner.anySuccessfulResultOrThrow became anySuccessfulOrThrow in 26, and Joiner gained a third type parameter in 27), the -XX:-ZGenerational flag (ignored with a warning on 24 and 25, rejected on 26 and 27), Thread.stop and java.applet (removed in 26), JOL or Unsafe code that assumes a 12-byte object header (compact headers are the default in 27), and container start scripts that rely on the JVM choosing SerialGC in a one-CPU container (G1 is the default everywhere in 27). For each finding give the file, the line, the release that changed it, and the fix.
|
||||
@@ -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,3 @@
|
||||
void main() {
|
||||
IO.println("compact source file: no class, no static, no String[] args");
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Is finalization "removed by default" in Java 25? JEP 421 deprecated it for removal in 18 and added
|
||||
* --finalization=disabled to test life without it. This allocates an object with a finalize() method, drops it,
|
||||
* asks for a GC, and reports whether the finalizer ran. Run by scripts/lanes.sh with and without the flag.
|
||||
* Chapter: docs/14-lanes-21-to-25.md
|
||||
*/
|
||||
public class FinalizerDefault {
|
||||
static volatile boolean finalized;
|
||||
|
||||
@SuppressWarnings({"removal", "deprecation"})
|
||||
static class Resource {
|
||||
@Override
|
||||
protected void finalize() {
|
||||
finalized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new Resource();
|
||||
for (int i = 0; i < 20 && !finalized; i++) {
|
||||
System.gc();
|
||||
Thread.sleep(50);
|
||||
}
|
||||
System.out.println("java.version = " + System.getProperty("java.version"));
|
||||
System.out.println("finalizer ran: " + finalized);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* The four Java 21 features from ankurm.com/java-21-to-25-lts-features (records, pattern-matching switch,
|
||||
* virtual threads, sequenced collections), exactly as the article shows them, compiled once with
|
||||
* --release 21 and then run unchanged on JDK 21, 25, 26 and 27. Scoped values and structured concurrency are
|
||||
* separate files because they are NOT final in 21. Chapter: docs/14-lanes-21-to-25.md
|
||||
*/
|
||||
public class HubExamples {
|
||||
|
||||
// 1. Records ------------------------------------------------------------------------------
|
||||
public record Customer(Long id, String email, String country) {
|
||||
public Customer {
|
||||
Objects.requireNonNull(email, "email must not be null");
|
||||
if (!email.contains("@")) throw new IllegalArgumentException("Invalid email");
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Pattern matching for switch ----------------------------------------------------------
|
||||
sealed interface Shape permits Circle, Square, Triangle {}
|
||||
record Circle(double r) implements Shape {}
|
||||
record Square(double side) implements Shape {}
|
||||
record Triangle(double base, double height) implements Shape {}
|
||||
|
||||
static double area(Shape s) {
|
||||
return switch (s) {
|
||||
case Circle(double r) -> Math.PI * r * r;
|
||||
case Square(double side) -> side * side;
|
||||
case Triangle(double b, double h) -> 0.5 * b * h;
|
||||
};
|
||||
}
|
||||
|
||||
static String classify(Shape s) {
|
||||
return switch (s) {
|
||||
case Circle c when c.r() > 100 -> "large circle";
|
||||
case Circle c -> "small circle";
|
||||
case Square sq -> "square";
|
||||
case Triangle t -> "triangle";
|
||||
};
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("java.version = " + System.getProperty("java.version"));
|
||||
|
||||
Customer c = new Customer(1L, "[email protected]", "IN");
|
||||
Check.that(c.email().equals("[email protected]"), "record accessor: c.email()");
|
||||
Check.that(c.toString().equals("Customer[id=1, [email protected], country=IN]"), "record toString: " + c);
|
||||
try {
|
||||
new Customer(2L, "not-an-email", "IN");
|
||||
Check.that(false, "compact constructor rejects an email without @");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
Check.that(true, "compact constructor rejects an email without @: " + expected.getMessage());
|
||||
}
|
||||
|
||||
Check.that(Math.abs(area(new Square(3)) - 9.0) < 1e-9, "area(Square(3)) == 9.0");
|
||||
Check.that(Math.abs(area(new Triangle(4, 5)) - 10.0) < 1e-9, "area(Triangle(4, 5)) == 10.0");
|
||||
Check.that(classify(new Circle(101)).equals("large circle"), "guard pattern: Circle(101) is a large circle");
|
||||
Check.that(classify(new Circle(1)).equals("small circle"), "guard pattern: Circle(1) is a small circle");
|
||||
|
||||
// 3. Virtual threads: 10,000 tasks that each block for 100 ms. Serial would take 1,000 s.
|
||||
AtomicInteger done = new AtomicInteger();
|
||||
long t0 = System.nanoTime();
|
||||
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
|
||||
IntStream.range(0, 10_000).forEach(i ->
|
||||
executor.submit(() -> {
|
||||
Thread.sleep(Duration.ofMillis(100));
|
||||
return done.incrementAndGet();
|
||||
}));
|
||||
}
|
||||
long ms = (System.nanoTime() - t0) / 1_000_000;
|
||||
Check.that(done.get() == 10_000, "all 10,000 virtual-thread tasks completed before close() returned");
|
||||
Check.that(ms < 30_000, "and it took seconds, not the 1,000 s a serial loop needs (exact time is machine dependent, not printed)");
|
||||
|
||||
Thread vt = Thread.ofVirtual().name("my-vthread").start(() -> { });
|
||||
vt.join();
|
||||
Check.that(vt.isVirtual() && vt.getName().equals("my-vthread"), "Thread.ofVirtual().name(..).start(..) gives a virtual thread");
|
||||
|
||||
// 4. Sequenced collections
|
||||
List<String> names = new ArrayList<>(List.of("alex", "brian", "chris"));
|
||||
String first = names.getFirst(); // alex
|
||||
String last = names.getLast(); // chris
|
||||
List<String> backwards = names.reversed(); // [chris, brian, alex]
|
||||
String snapshot = backwards.toString(); // written down before the list changes
|
||||
names.add("dana"); // reversed() is a view, so it sees this
|
||||
LinkedHashSet<Integer> nums = new LinkedHashSet<>(List.of(3, 1, 4, 1, 5));
|
||||
int firstNum = nums.getFirst(); // 3
|
||||
int lastNum = nums.getLast(); // 5
|
||||
|
||||
Check.that(first.equals("alex") && last.equals("chris"), "List.getFirst() / getLast()");
|
||||
Check.that(snapshot.equals("[chris, brian, alex]"), "List.reversed(): " + snapshot);
|
||||
Check.that(backwards.getFirst().equals("dana"), "reversed() is a view, not a copy: it sees the element added afterwards");
|
||||
Check.that(firstNum == 3 && lastNum == 5, "LinkedHashSet.getFirst() == 3, getLast() == 5");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* "JNI warnings on stderr by default": JEP 472 (Java 24). Loading a native library is a restricted operation.
|
||||
* The library is the JDK's own libnet, so no compiler or extra file is needed. Run with and without
|
||||
* --enable-native-access=ALL-UNNAMED by scripts/lanes.sh.
|
||||
* Chapter: docs/14-lanes-21-to-25.md
|
||||
*/
|
||||
public class JniWarning {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("java.version = " + System.getProperty("java.version"));
|
||||
System.loadLibrary("net");
|
||||
System.out.println("System.loadLibrary(\"net\") returned");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* The smallest class that needs Lombok's annotation processor: without the processor there is no getName().
|
||||
* Compiled by scripts/upgrade.sh with four Lombok versions on JDK 25, 26 and 27. Explained in docs/15-build-files.md.
|
||||
*/
|
||||
public class LombokProbe {
|
||||
@Getter private final String name = "ankur";
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("getName() = " + new LombokProbe().getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import org.mockito.Mockito;
|
||||
|
||||
/**
|
||||
* Creates one mock and stubs one call: the smallest thing that makes Mockito ask ByteBuddy to read and write class files.
|
||||
* Run by scripts/upgrade.sh against two Mockito versions on JDK 21 and 25. Explained in docs/15-build-files.md.
|
||||
*/
|
||||
public class MockitoProbe {
|
||||
interface Greeter { String greet(String name); }
|
||||
|
||||
public static void main(String[] args) {
|
||||
Greeter g = Mockito.mock(Greeter.class);
|
||||
Mockito.when(g.greet("x")).thenReturn("hi");
|
||||
System.out.println("mock says " + g.greet("x"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Virtual threads and synchronized: until JEP 491 (Java 24) a virtual thread that blocked inside a synchronized
|
||||
* block kept its carrier thread (was "pinned"). With ONE carrier, four virtual threads that each sleep 200 ms inside
|
||||
* synchronized on their own lock take about 800 ms if pinned (one at a time) and about 200 ms if not (all at once).
|
||||
* Run by scripts/lanes.sh with -Djdk.virtualThreadScheduler.parallelism=1 -Djdk.virtualThreadScheduler.maxPoolSize=1
|
||||
* Chapter: docs/14-lanes-21-to-25.md
|
||||
*/
|
||||
public class PinningDemo {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("java.version = " + System.getProperty("java.version"));
|
||||
List<Thread> threads = new ArrayList<>();
|
||||
long t0 = System.nanoTime();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Object lock = new Object();
|
||||
threads.add(Thread.ofVirtual().start(() -> {
|
||||
synchronized (lock) {
|
||||
try { Thread.sleep(200); } catch (InterruptedException ignored) { }
|
||||
}
|
||||
}));
|
||||
}
|
||||
for (Thread t : threads) t.join();
|
||||
long ms = (System.nanoTime() - t0) / 1_000_000;
|
||||
System.out.println("4 virtual threads, 1 carrier, sleep(200) inside synchronized: "
|
||||
+ (ms >= 700 ? "SERIALISED (pinned): about 4 x 200 ms" : "OVERLAPPED (not pinned): about 200 ms"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Uses one API that exists on Java 26 and later (String.equalsFoldCase) and not on Java 25.
|
||||
* Compiled by a newer javac with --release 25 (rejected) and with -source 25 -target 25 (accepted, then it
|
||||
* fails when it meets a Java 25 runtime). Explained in docs/15-build-files.md.
|
||||
*/
|
||||
public class ReleaseFlag {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("ABC".equalsFoldCase("abc"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Scoped values (JEP 506): final in Java 25, a preview API in 21. The code is the example from
|
||||
* ankurm.com/java-21-to-25-lts-features. Compiles WITHOUT --enable-preview on 25, 26 and 27; on 21 javac refuses.
|
||||
* Chapter: docs/14-lanes-21-to-25.md
|
||||
*/
|
||||
public class ScopedValueDemo {
|
||||
static final ScopedValue<String> CURRENT_USER = ScopedValue.newInstance();
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("java.version = " + System.getProperty("java.version"));
|
||||
ScopedValue.where(CURRENT_USER, "ankur").run(() -> {
|
||||
Check.that(CURRENT_USER.get().equals("ankur"), "inside the scope: CURRENT_USER.get() == ankur");
|
||||
callDeepMethod();
|
||||
});
|
||||
try {
|
||||
CURRENT_USER.get();
|
||||
Check.that(false, "outside the scope get() should throw");
|
||||
} catch (NoSuchElementException expected) {
|
||||
Check.that(true, "outside the scope: CURRENT_USER.get() throws NoSuchElementException");
|
||||
}
|
||||
}
|
||||
|
||||
static void callDeepMethod() {
|
||||
Check.that(CURRENT_USER.get().equals("ankur"), "a method that was never passed the value still sees it");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* "System.setSecurityManager() now throws UnsupportedOperationException": JEP 486 (Java 24) permanently disabled
|
||||
* the Security Manager. This calls it with a non-null manager and prints exactly what happens.
|
||||
* Chapter: docs/14-lanes-21-to-25.md
|
||||
*/
|
||||
public class SecurityManagerGone {
|
||||
@SuppressWarnings({"removal", "deprecation"})
|
||||
public static void main(String[] args) {
|
||||
System.out.println("java.version = " + System.getProperty("java.version"));
|
||||
try {
|
||||
System.setSecurityManager(new SecurityManager());
|
||||
System.out.println("setSecurityManager: accepted");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
System.out.println("setSecurityManager: UnsupportedOperationException: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import java.util.concurrent.StructuredTaskScope;
|
||||
|
||||
/**
|
||||
* The structured concurrency example from ankurm.com/java-21-to-25-lts-features. JEP 505 in Java 25 is the FIFTH
|
||||
* PREVIEW, not a final feature: without --enable-preview javac refuses, on 25, 26 and 27 alike.
|
||||
* Chapter: docs/14-lanes-21-to-25.md
|
||||
*/
|
||||
public class StructuredHub {
|
||||
record Dashboard(String user, String order) {}
|
||||
|
||||
static String fetchUser(int id) throws InterruptedException { Thread.sleep(20); return "user-" + id; }
|
||||
static String fetchOrder(int id) throws InterruptedException { Thread.sleep(30); return "order-for-" + id; }
|
||||
|
||||
static Dashboard fanOut(int userId) throws Exception {
|
||||
try (var scope = StructuredTaskScope.open()) {
|
||||
var user = scope.fork(() -> fetchUser(userId));
|
||||
var order = scope.fork(() -> fetchOrder(userId));
|
||||
scope.join();
|
||||
return new Dashboard(user.get(), order.get());
|
||||
}
|
||||
}
|
||||
|
||||
static String firstSuccess() throws Exception {
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulResultOrThrow())) {
|
||||
scope.fork(() -> { Thread.sleep(200); return "slow"; });
|
||||
scope.fork(() -> "fast");
|
||||
return scope.join();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("java.version = " + System.getProperty("java.version"));
|
||||
Dashboard d = fanOut(7);
|
||||
Check.that(d.equals(new Dashboard("user-7", "order-for-7")), "fan-out: both results joined: " + d);
|
||||
Check.that(firstSuccess().equals("fast"), "anySuccessfulResultOrThrow(): the first result wins and the slow subtask is cancelled");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import java.util.concurrent.StructuredTaskScope;
|
||||
|
||||
/**
|
||||
* The same "first result wins" example as StructuredHub, with the factory method under its Java 26 / 27 name:
|
||||
* anySuccessfulResultOrThrow() (25) became anySuccessfulOrThrow() (26 and 27). Still a preview API.
|
||||
* Chapter: docs/14-lanes-21-to-25.md
|
||||
*/
|
||||
public class StructuredHubNew {
|
||||
static String firstSuccess() throws Exception {
|
||||
try (var scope = StructuredTaskScope.open(StructuredTaskScope.Joiner.<String>anySuccessfulOrThrow())) {
|
||||
scope.fork(() -> { Thread.sleep(200); return "slow"; });
|
||||
scope.fork(() -> "fast");
|
||||
return scope.join();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("java.version = " + System.getProperty("java.version"));
|
||||
Check.that(firstSuccess().equals("fast"), "anySuccessfulOrThrow(): the first result wins");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Thread.stop() on 25: still compiles (with a deprecation-for-removal warning) but has thrown
|
||||
* UnsupportedOperationException since Java 20. It is REMOVED from the API in Java 26 (see recap26/src/broken/ThreadStopGone.java,
|
||||
* docs/output/73-removed-in-26.txt). Thread.suspend() and resume() are checked the same way.
|
||||
* Chapter: docs/14-lanes-21-to-25.md
|
||||
*/
|
||||
public class ThreadStopRuntime {
|
||||
@SuppressWarnings({"removal", "deprecation"})
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("java.version = " + System.getProperty("java.version"));
|
||||
Thread t = new Thread(() -> {
|
||||
try { Thread.sleep(1000); } catch (InterruptedException ignored) { }
|
||||
});
|
||||
t.start();
|
||||
try {
|
||||
t.stop();
|
||||
System.out.println("Thread.stop(): accepted");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
System.out.println("Thread.stop(): UnsupportedOperationException");
|
||||
}
|
||||
t.interrupt();
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Compile-only probe: do Thread.suspend() and Thread.resume() still exist? Compiled by scripts/lanes.sh with each JDK's own javac.
|
||||
* Chapter: docs/14-lanes-21-to-25.md
|
||||
*/
|
||||
public class ThreadSuspendGone {
|
||||
@SuppressWarnings({"removal", "deprecation"})
|
||||
static void probe(Thread t) {
|
||||
t.suspend();
|
||||
t.resume();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* "Unnamed patterns and unnamed classes are also final in 25" is only half true. Unnamed variables and patterns (the
|
||||
* underscore) were finalised in Java 22 (JEP 456). What became final in 25 is compact source files and instance main
|
||||
* methods (JEP 512), the successor to "unnamed classes". This file checks the underscore half.
|
||||
* Chapter: docs/14-lanes-21-to-25.md
|
||||
*/
|
||||
public class UnnamedVariables {
|
||||
record Point(int x, int y) {}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Object o = new Point(3, 4);
|
||||
if (o instanceof Point(int x, _)) {
|
||||
System.out.println("matched a Point, x = " + x + ", y ignored with _");
|
||||
}
|
||||
try {
|
||||
Integer.parseInt("nope");
|
||||
} catch (NumberFormatException _) {
|
||||
System.out.println("caught NumberFormatException without naming it");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import java.lang.reflect.Field;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* "sun.misc.Unsafe memory methods deprecated for removal": JEP 471 (23) deprecated them, JEP 498 (24) makes the first
|
||||
* call print a warning at run time. This allocates and frees 8 bytes off-heap and shows what the JVM says.
|
||||
* Chapter: docs/14-lanes-21-to-25.md
|
||||
*/
|
||||
public class UnsafeWarning {
|
||||
@SuppressWarnings("removal")
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("java.version = " + System.getProperty("java.version"));
|
||||
Field f = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
f.setAccessible(true);
|
||||
Unsafe u = (Unsafe) f.get(null);
|
||||
long addr = u.allocateMemory(8);
|
||||
u.putLong(addr, 42L);
|
||||
System.out.println("read back: " + u.getLong(addr));
|
||||
u.freeMemory(addr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Gradle (build.gradle.kts): ask for a Java 25 toolchain
|
||||
plugins {
|
||||
java
|
||||
application
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(25))
|
||||
}
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("demo.App")
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.ankurm.demos</groupId>
|
||||
<artifactId>upgrade-demo</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<properties>
|
||||
<!-- Maven (pom.xml): keep all three in step. source and target set the language level and the class-file version; release also limits the API you may call -->
|
||||
<maven.compiler.source>25</maven.compiler.source>
|
||||
<maven.compiler.target>25</maven.compiler.target>
|
||||
<maven.compiler.release>25</maven.compiler.release>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
rootProject.name = "upgrade-demo"
|
||||
@@ -0,0 +1,12 @@
|
||||
package demo;
|
||||
|
||||
/**
|
||||
* The smallest class that proves a build targets Java 25: it prints the Java version of the JVM it runs on.
|
||||
* Explained in docs/15-build-files.md. The build files next to it (pom.xml, build.gradle.kts) are the ones
|
||||
* quoted in the "Step 1" section of the upgrade guide.
|
||||
*/
|
||||
public class App {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("running on Java " + Runtime.version().feature());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user