1. JAVA 25 AND BEYOND
A ROADMAP OF INNOVATIONS
ANA-MARIA MIHALCEANU
Senior developer advocate at Oracle
ammbra1508.bsky.social ammbra1508.mastodon.social
2. Project Summary Pain point “Obvious"
Competition
Amber Right-sizing language ceremony
“Java is too verbose"
“Java is hard to teach"
C#, Kotlin
Babylon Foreign programming model interop “Using GPUs is too hard" LinQ, Julia
Leyden Faster startup and warmup “Java starts up too slowly" Go
Loom Lightweight concurrency
“Threads are too expensive, don’t
scale"
Go, Elixir
Panama
Native code and memory interop
SIMD Vector support
“Using native libraries is too hard"
“Numeric loops are too slow"
Python, C
Valhalla Value types and specialized generics
“Cache misses are too expensive"
“Generics and primitives don’t mix"
C, C#
ZGC Sub-millisecond GC pauses “GC pauses are too long" C, Rust
3. Inclusive Development Experience
🔗”Paving the On Ramp
As a result, it is easy to forget about the “small" programs
Java has been historically
successful in “big" systems
And we all start small
But, we want Java
to be successful
for small applications too
• OOP concepts should not overwhelm your first (or any
small) program
• The “on ramp" should lead smoothly onto the highway
”Paving the On Ramp”
5. // HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
Launch via single file execution (since JDK 11)
java HelloWorld.java
Use jshell for fast prototyping Java code
Towards A Simplified Beginning
6. Paving The On Ramp
// HelloWorld.java
void main( ) {
IO.println("Hello, World!");
}
public class HelloWorld {
public static String[] args
}
JEP 512: Compact Source Files and Instance Main Methods
7. Effective Scripting with Java
// HelloWorld.java
void main() {
IO.println("Hello, World!");
}
JEP 512: Compact Source Files and Instance Main Methods
Class declaration no longer required
main is not necessarily public static
String[] args not declared if not used further
Auto-import of java.base packages
Simplified console I/O
8. Import All Packages Exported by a Module
import java.io.IOException;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
import module java.base;
JEP 511: Module Import Declarations
10. Agenda Prototype
• Add chores to do to.
• Delete a chore when is done.
• A chore can have either an URL or an image attached to it.
• The deadline for chore has to be greater than current date.
• The priority is deduced based on deadline.
11. Agenda Entity Modeling
Sealed types limit which subtypes can directly extend/implement them.
public sealed interface Todo permits TodoItem {}
public non-sealed class TodoItem implements Todo {}
public final class URLTodoItem extends TodoItem{}
public final class ImageTodoItem extends TodoItem{}
12. Inheritance and Constructor Chaining
public final class URLTodoItem extends TodoItem {
private String url;
public URLTodoItem(String title, String description, String url,
LocalDate createdOn, LocalDate deadline) {
super(title, description, createdOn, validate(createdOn, deadline));
this.url = url;
}
private static LocalDate validate(LocalDate createdOn, LocalDate deadline) {
if (deadline.isBefore(createdOn))
throw new IllegalArgumentException(”Deadline must not be before creation date");
return deadline;
}
}
Constructor chaining is enforced in subclass.
13. Statements before super(…)
public final class URLTodoItem extends TodoItem {
private String url;
public URLTodoItem(String title, String description, String url,
LocalDate createdOn, LocalDate deadline) {
if (deadline.isBefore(createdOn))
throw new IllegalArgumentException(”Deadline cannot be before creation date");
this.url = url;
super(title, description, createdOn, deadline);
}
}
Validate superclass constructor arguments
Prepare superclass constructor arguments
Share superclass constructor arguments
JEP 513: Flexible Constructor Bodies
14. Determine Emergency Based on Priority
private static Highlight findColor(TodoItem item) {
return switch (item.getPriority()) {
case long p when p < 0 -> Highlight.RED;
case 0L -> Highlight.YELLOW;
case 1L -> Highlight.BLUE;
case long _ -> Highlight.WHITE;
};
}
JEP 507: Primitive Types in Patterns, instanceof, and switch (Third Preview)
15. Primitive Type Patterns in Nested Context
public record Statistic(Highlight highlight, int count) {}
switch (statistic) {
case Statistic(Highlight h, byte b) when h == Highlight.RED && b < -10 -> …;
case Statistic(Highlight h, short s) when h == Highlight.YELLOW -> …;
case Statistic(Highlight h, int i) when h == Highlight.BLUE ->…;
case Statistic(Highlight h, int i) -> …;
}
JEP 507: Primitive Types in Patterns, instanceof, and switch (Third Preview)
16. So You Want to Know More…
• Finalizing the Java On-ramp - Inside Java Newscast #90
• Key Java Language Updates From 2020 to 2025
• Pattern Matching in Java: Better Code, Better APIs
• Where Is the Java Language Going?
19. Let’s Revisit Our Agenda
• Add chores to do to.
• Delete a chore when is done.
• A chore can have either an URL or an image attached to it.
• The deadline for chore has to be greater than current date.
• The priority is deduced based on deadline.
• Parse csv todo files when starting the application.
20. Structured Concurrency to the Rescue
try (var scope = StructuredTaskScope.<TodoFile>open()) {
var todoTask = scope.fork(() -> parseCSV(todoFilePath));
var urlTask = scope.fork(() -> parseCSV(urlFilePath));
var mixTask = scope.fork(() -> parseCSV(mixFilePath));
scope.join();
List<List<String>> result = new ArrayList<>();
result.addAll(todoTask.get().data());
result.addAll(urlTask.get().data());
result.addAll(mixTask.get().data());
}
JEP 505: Structured Concurrency (Fifth Preview)
22. Simplify Data Flow Reasoning
• No accidental mutation or leakage
• Bounded lifetime -> better memory and security
• Efficient across structured & virtual threads
public static ScopedValue<String> VALID_FILE = ScopedValue.newInstance();
ScopedValue.where(VALID_FILE, todoFilePath).run(this::processFiles);
JEP 506: Scoped Values
23. Benefits for High Scaling Applications
Higher throughput with fewer CPU
operations when having high number
concurrent requests.
When having blocking calls, virtual
threads will go in a waiting state until they
receive data.
24. So You Want to Know More…
• On Parallelism and Concurrency
• Java 20 - From ThreadLocal to ScopedValue with Loom Full Tutorial - JEP Café #16
• Project Loom and Virtual Threads: Next Phases
• Structured Concurrency Revamp in Java 25 - Inside Java Newscast #91
26. Simplified PEM API for Java Cryptography
• PEM is a textual format (RFC 7468) for cryptographic keys, certs, and CRLs.
-----BEGIN PUBLIC KEY-
---- Base64-encoded content...
-----END PUBLIC KEY-----
• Simple, intuitive API for converting between PEM and Java objects.
• The API supports PKCS#8, PKCS#8 v2.0, X.509.
JEP 470: PEM Encodings of Cryptographic Objects (Preview)
27. New Types in java.security
JEP 470: PEM Encodings of Cryptographic Objects (Preview)
Class / Interface Purpose
DEREncodable Marker for objects that can be PEM-encoded
PEMEncoder Converts DEREncodable → PEM
PEMDecoder Converts PEM → DEREncodable
PEMRecord Generic holder for unknown or custom PEM types
28. The New Key Derivation Function API
An API that enables the use of
KDFs in Key Encapsulation
Mechanism implementations.
It empowers you to benefit of
KDFs in cryptographic schemes
like Hybrid Public Key Encryption
(HPKE).
Offers flexibility for security
providers to implement KDF
algorithms in Java.
JEP 510: Key Derivation Function API
30. Deferred Immutability with Stable Values
• java.lang.experimental.StableValue<T> - an object that can be set once, on demand, then
behaves as an immutable constant.
• Thread-safe: orElseSet(supplier) (or supplier(…)) guarantees the supplier runs exactly once,
even under high contention.
• Split heavy start-up work by initialising components only when first used.
• Keep constant-folding & GC friendliness.
JEP 502: Stable Values (Preview)
31. Accelerating Java Startup
• The ahead-of-time (AOT) cache allows the JVM to preload, parse, and link classes during a training run.
• The AOT cache extends CDS by not only reading and parsing class files but also linking them. This
means classes are preloaded into memory in a fully usable state.
• For instance, a basic program using the Stream API can see its startup time cut from 0.031 seconds to
0.018 seconds—a 42% improvement.
• For more complex applications like Spring PetClinic, the startup time can drop from 4.486 seconds to
2.604 seconds.
JEP 483: Ahead-of-Time Class Loading & Linking
32. Create and Load the AOT Cache
1. Do a training run: launch the application with the JVM configured to record its class-loading behavior
java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf -cp app.jar org.example.App
2. The recorded data is used to generate the AOT cache file
java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf -XX:AOTCache=app.aot -cp app.jar
3. Shifts much of the class-loading work from runtime to an earlier point, significantly reducing startup time.
java -XX:AOTCache=app.aot -cp app.jar org.example.App
33. Faster Startup with Cached Method Profiles
• Extends JEP 483’s AOT cache: now stores classes and method profiles.
• Transfers method-execution profiles from a training run into an AOT cache.
• Peak perfomance much sooner.
• No code refactoring needed.
JEP 515: Ahead-of-Time Method Profiling
34. Simplify AOT Cache Creation
• Record and create AOT caches in a single step with -XX:AOTCacheOutput.
• -XX:AOTCacheOutput=app.aot triggers:
• A training run (AOTMode=record)
• Followed automatically by cache creation (AOTMode=create)
• JVM handles the temporary config file, cleaning it up afterward.
JEP 514: Ahead-of-Time Command-Line Ergonomics
35. Limitations and Workarounds
• User-Defined Class Loaders: classes loaded dynamically by custom loaders are excluded
from the cache.
Future updates might address this gap if they prove significant.
• Consistency Constraints: strict requirements for JDK versions and configurations can
complicate deployment pipelines.
Use tools like Docker to standardize environments can mitigate this issue.
• Exclusion of ZGC: the Z Garbage Collector is not yet supported.
Future updates will likely address this gap.
JEP 483: Ahead-of-Time Class Loading & Linking
36. Performance by Shrinking Object Headers
The HotSpot JVM introduces
a feature to reduce object
header sizes from 96-128 bits
to 64 bits on 64-bit
architectures.
It aims to reduce memory
footprints on real workloads,
while maintaining minimal
performance overheads.
In JDK 25 is a product feature enabled
via -XX:+UseCompactObjectHeaders
JEP 519: Compact Object Headers
37. So You Want to Know More…
• Episode 37 “Efficient Initialization Using Stable Values” with Per Minborg
• Stable Values in Java 25 - Inside Java Newscast #88
• A Sneak Peek at StableValue and SegmentMapper
• Ubuntu Ships Java, Spring, AOT
• Episode 36 “Ahead of Time Computation” with Dan Heidinga
• A Deep Dive into JVM Start-up
39. Enhanced Reliability of JFR Stack Sampling
• Low overhead event sampling for threads.
• Coordinates thread sampling with application logic.
• Improves data granularity and performance.
• Record the time it takes for a thread to reach a safepoint with jdk.SafepointLatency.
JEP 518: JFR Cooperative Sampling
40. Method Timing and Tracing
Low-overhead,
bytecode-
injected method
instrumentation.
New JFR events
jdk.MethodTiming and
jdk.MethodTrace.
Identify performance
bottlenecks and trace
method invocations.
Analyze slow
startup, resource
leaks, or code
regressions.
JEP 520: JFR Method Timing & Tracing
41. Experimental Linux-Only CPU-time Profiling
• New JFR event jdk.CPUTimeSample: samples stacks at fixed CPU-time intervals (vs. wall-clock).
java -XX:StartFlightRecording:jdk.CPUTimeSample#enabled=true,filename=rec.jfr
• Execution-time profiles highlight latency hotspots.
• CPU-time profiles expose throughput bottlenecks (e.g., compute-heavy methods hidden by I/O wait).
• Safer alternative to third-party profilers that hook into unsupported JVM internals.
JEP 509: JFR CPU-Time Profiling (Experimental)