├── .gitignore
├── .idea
├── .gitignore
├── encodings.xml
├── misc.xml
└── vcs.xml
├── LICENSE
├── README.adoc
├── pom.xml
└── src
└── main
└── java
├── dev
└── simonverhoeven
│ └── java24demo
│ ├── finalized
│ ├── ClassFileAPI.java
│ ├── GathererOverview.java
│ ├── MemoryAccessMethodUsage.java
│ └── SynchronizeVTWithoutPinning.java
│ ├── incubator
│ └── vectors
│ │ └── VectorSample.java
│ └── preview
│ ├── KeyDerivedFunction.java
│ ├── ModuleImport.java
│ ├── PrimitiveTypes.java
│ ├── QuantRestModLatBasedDSA.java
│ ├── QuantRestModLatBasedKEM.java
│ ├── SimpleClass.java
│ ├── StructuredConcurrency.java
│ ├── Super.java
│ └── scopedvalues
│ ├── Greeter.java
│ └── Scoper.java
└── module-info.java
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | *.iws
12 | *.iml
13 | *.ipr
14 |
15 | ### Eclipse ###
16 | .apt_generated
17 | .classpath
18 | .factorypath
19 | .project
20 | .settings
21 | .springBeans
22 | .sts4-cache
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
37 | ### Mac OS ###
38 | .DS_Store
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Simon Verhoeven
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.adoc:
--------------------------------------------------------------------------------
1 | = Java 24
2 | :toc:
3 | :toc-placement:
4 | :toclevels: 3
5 |
6 | Java 24 will be released on the 18th of March 2025, and the full list of enhancements is now available tallying up to an astounding 24 changes. This certainly doesn't raise the expectations for release 25!
7 |
8 | Let us take a closer look at what's awaiting us!
9 |
10 | == Core
11 |
12 | The core Java library has once again been enriched with a multitude of new features, including several preview APIs, driving the language ever forward to ensure it can meet today's needs. As expected, some enhancements like the Vector API remain in incubation, while others, such as the Gatherer API, have now landed.
13 |
14 | Let's take a look at the exciting new features!
15 |
16 | === https://openjdk.org/jeps/472[JEP 472: Prepare to Restrict the Use of JNI]
17 |
18 | This JEP will ensure that warnings are issued in a consistent manner in case of JNI or FFM usage that goes against https://openjdk.org/jeps/8305968[integrity by default].
19 | These warnings and future restrictions can be selectively disabled by enabling those specific interfaces when needed.
20 |
21 | When using a native function we'll get a `WARNING` at startup unless we use the JVM `--enable-native-access` option to authorize it, or add the `Enable-Native-Access` manifest entry.
22 |
23 | Using native functions without authorization is illegal, hence the aptly called `--illegal-native-access` which allows us to control the JVM's behaviour, with the default being a warning.
24 |
25 | The options are:
26 |
27 | * warn (default): a warning will be emitted in the JVM logs
28 | * allow: use is authorized without restriction
29 | * deny: use is refused, an IllegalCallerException will be thrown
30 |
31 | Violating this will result in a warning being emitted by the JVM in the following form:
32 |
33 | `WARNING: A restricted method in java.lang.System has been called`
34 |
35 | === https://openjdk.org/jeps/484[JEP 484: Class-File API]
36 |
37 | This JEP which was initially a preview in 22 and 23 aims to provide a standard API for parsing, generating and transforming Java class files.
38 |
39 | It is geared towards helping developers handle the swifter release cadence, and thus class-file format changes. The API would evolve alongside the class file format, which would reduce the reliance of library and framework developers on third-party developers to update and test their class-file libraries. Frameworks and libraries making use the standard API will support class files from the latest JDK automatically.
40 |
41 | === https://openjdk.org/jeps/485[JEP 485: Stream Gatherers]
42 |
43 | This JEP enhances the Stream API with new intermediate operations to facilitate new data operations that previously weren't easily achievable. This will be handled by facilitating the creation of custom intermediate operations to manipulate the streams, rather than a lot of new methods of the specifically requested functions.
44 |
45 | We're already seeing some interesting libraries pop up with useful gatherers such as https://github.com/tginsberg/gatherers4j[Gatherers4j]
46 |
47 | I've already experimented quite a bit with API during the latest https://adventofcode.com/[Advent of Code], and it certainly made some challenges a lot easier..
48 |
49 | For more details the https://nipafx.dev/inside-java-newscast-57/[Inside Java newscast number 57] is certainly also worth a watch.
50 |
51 | === https://openjdk.org/jeps/487[JEP 487: Scoped values (Fourth Preview)]
52 |
53 | Scoped values are being introduced as a preview API for the fourth time.
54 | It will enable methods to share immutable data both within threads and with child threads, offering better efficiency and clarity than thread-local variables, especially when used with virtual threads and structured concurrency.
55 |
56 | The fourth iteration mostly remains the same, the only changes is the removal of `callWhere()` and `runWhere()` from https://cr.openjdk.org/~alanb/sv-20240517/java.base/java/lang/ScopedValue.html[ScopedValue] thus leaving us with a fluent API. After this change we can only use bound scopes values through the `call()` and `run()` methods from https://cr.openjdk.org/~alanb/sv-20240517/java.base/java/lang/ScopedValue.Carrier.html[ScopedValue.Carrier].
57 |
58 | === https://openjdk.org/jeps/489[JEP 489 Vector API (Ninth Incubator)]
59 |
60 | The ninth iteration API of an API for vector computations. It aims to be a way to express these in a manner that compiles reliably to optimal vector instructions on supported CPU architectures to achieve better performance than equivalent scalar computations.
61 |
62 | This iteration adds a new `Float16` which supports 16-bit variables in IEEE 754 binary16 format using the Vector API.
63 |
64 | The developers have confirmed that the API will remain in incubation until project Valhalla enters preview itself so that the API can leverage the expected performance and in-memory representation enhancements.
65 |
66 | === https://openjdk.org/jeps/498[JEP 498: Warn upon Use of Memory-Access Methods in sun.misc.Unsafe]
67 |
68 | A lot of low-level frameworks use the `Unsafe` class for faster memory access, however this class was always as an internal class and is officially unsupported and undocumented.
69 |
70 | In "recent" releases we've received alternative methods to achieve the same thing, and as communicated when they were deprecated in JDK23 are slowly being phased out.
71 |
72 | As of JDK 24 this will result in an `WARNING`, and in a future release the invocations will by default escalate to an exception.
73 |
74 | The better approaches are:
75 |
76 | ==== https://openjdk.org/jeps/193[JEP 193: Variable Handles]
77 |
78 | `VarHandle` landed in Java 9 and allows us a modern and type-safe way to handle variable access.
79 |
80 | ==== https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/foreign/package-summary.html[Foreign Function & Memory API]
81 |
82 | This API, also known as the FFM API landed in JDK 22 through https://openjdk.org/jeps/454[JEP 454] and allows us to safely interact with native memory and functions.
83 |
84 | === https://openjdk.org/jeps/499[JEP 499: Structured Concurrency (Fourth Preview)]
85 |
86 | This proposal aims to address some of the frequently encountered challenges in concurrent programming by introducing an API that treats groups of related tasks running in different threads as a single unit of work.
87 |
88 | The proposed approach, also known as structured concurrency will help us streamline error handling, cancellation, and observability, making concurrent code more reliable and easier to manage.
89 |
90 | The main target is promoting a style of concurrent programming that eliminates common risks such as thread leaks and cancellation delays, while also improving the observability of concurrent code. The API itself is centered around `StructuredTaskScope`, which allows us to define a clear hierarchy of tasks and subtasks, ensuring that all subtasks are completed or cancelled before the parent task exits. This enforces a structured flow of execution, similar to single-threaded code, where subtasks are confined to the lexical scope of their parent task. The API also provides built-in shutdown policies (e.g., `ShutdownOnFailure` and `ShutdownOnSuccess`) to handle common concurrency patterns, such as cancelling all subtasks if one fails or succeeds. We can also define our own shutdown policies.
91 |
92 | By reifying the task-subtask relationship at runtime, structured concurrency makes it easier for us to reason about and debug concurrent programs. It also integrates well with observability tools, such as thread dumps, which can now display the hierarchical structure of tasks and subtasks.
93 |
94 | This enhancement does not aim to replace existing concurrency constructs like `ExecutorService` or `Future`, but rather to complement them by offering a more structured and reliable alternative for managing concurrent tasks.
95 |
96 | JEP 499 builds on previous previews (JEP https://openjdk.org/jeps/428[428], https://openjdk.org/jeps/437[437], https://openjdk.org/jeps/453[453], https://openjdk.org/jeps/462[462], and https://openjdk.org/jeps/480[480]) and is designed to work seamlessly with virtual threads (https://openjdk.org/jeps/444[JEP 444]), which enables lightweight, high-throughput concurrency. There are no changes in this preview.
97 |
98 | For now, it'll remain in preview to gather further feedback, so please do try it out and share your feedback! It continues in https://openjdk.org/jeps/8340343[JEP Draft 8340343, Structured Concurrency (Fifth Preview)].
99 |
100 | == HotSpot
101 |
102 | Proper attention has been paid to make sure that the HotSpot remains efficient and maintainable by addressing such key challenges as the pinning issue plaguing Virtual threads, further garbage collection enhancements, and the deprecation and removal of several legacy sections.
103 |
104 | Let us take a look at what was changed.
105 |
106 | === https://openjdk.org/jeps/404[JEP 404: Generational Shenandoah (Experimental)]
107 |
108 | This aims to enhance the Shenandoah GC with an experimental generational mode, without impacting non-generational.
109 |
110 | With non-generational we mean that the heap was not split into multiple zones each containing objects of different ages. It's based upon the *Weak Generational Hypothesis* which stats that *most objects die young*. The collection of dead objects is very cheap, so if we separate the two we can target young objects to clean the heap more efficiently.
111 |
112 | The intent is to reduce the sustained memory footprint, and reduce resource consumption. Initially it'll only support X64 and AArch64, with more instruction sets being supported later.
113 |
114 | It was originally intended to land in JDK21. but it was dropped at that time due to identified risks (see for reference https://mail.openjdk.org/pipermail/jdk-dev/2023-June/007959.html[this jdk-dev mailing list entry]) to make sure than when it landed it would deliver the best possible result.
115 |
116 | We can enable it through the following JVM options: `-XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational`.
117 |
118 | === https://openjdk.org/jeps/450[JEP 450: Compact Object Headers (Experimental)]
119 |
120 | This enhancement was inspired by the experiments done in function of https://wiki.openjdk.org/display/lilliput[Project Lilliput] which found that many workloads have an average object size of 32 to 64 bytes.
121 |
122 | It proposes to reduce the object header size in the HotSpot JvM from between 96 and 128 bits down to 64 bits on 64-bit architectures. An eye is also being kept on it not introducing any major throughput or latency overhead. It is disabled by default given its experimental nature to avoid unintended consequences.
123 |
124 | === https://openjdk.org/jeps/479[JEP 479: Remove the Windows 32-bit x86 Port]
125 |
126 | As planned after the deprecation for removal in JDK 21 (JEP 449) the Windows 32 bit X86 bit source code and build support has been removed.
127 |
128 | === https://openjdk.org/jeps/483[JEP 483: Ahead-of-Time Class Loading & Linking]
129 |
130 | This feature aims to enhance Java application startup performance by monitoring an application during one run and creating a cache of preloaded and pre-linked classes for subsequent runs.
131 |
132 | It seeks to improve startup time by leveraging the typically consistent startup process of applications, without requiring changes to application code, command-line usage, or build tools.
133 |
134 | This approach provides a foundation for future improvements in startup and warmup time, with the current implementation focusing on caching classes loaded by built-in class loaders from the class path, module path, and JDK itself.
135 |
136 | One major differentiator from GraalVM which offers a similar functionality all JVM functionalities are preserved. Classes not present in the archive will be dynamically loaded by the JVM.
137 |
138 | At the moment this process involves three steps (there are plans to streamline the process of cache creation):
139 |
140 | . Performing a training run to record its AOT configuration (into a file called `app.aotconf`) => `java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf \
141 | -cp app.jar dev.simonverhoeven.DemoApp`
142 | . Use the configuration to create a cache (into a file called `app.aot`) => `java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf \
143 | -XX:AOTCache=app.aot -cp app.jar`
144 | . Running our application with the cache (note that in case it can't be used the JVM will issue a warning, and then continue) => `java -XX:AOTCache=app.aot -cp app.jar dev.simonverhoeven.DemoApp`
145 |
146 | On my local machine, Spring PetClinic startup with AOT cache took 2.7 seconds versus 4.6 without.
147 |
148 | === https://openjdk.org/jeps/475[JEP 475: Late Barrier Expansion for G1]
149 |
150 | Simplifies the G1 Garbage Collection barrier implementation, which stores information about the application memory access by moving the expansion of the expansion thereof to later in the C2 JIT's compilation pipeline.
151 |
152 | This makes the G1 barriers more comprehensible, and reduces the C2 execution time when using the G1 collector. Additionally, it guarantees the preservation of the C2 invariants while preserving the quality of C2 generated code.
153 |
154 | === https://openjdk.org/jeps/490[JEP 490: ZGC: Remove the Non-Generational Mode]
155 |
156 | The non-generational mode of the Z Garbage Collector (ZGC) will be removed to reduce the current maintenance cost of supporting two different modes as to speed up the development of new features.
157 |
158 | === https://openjdk.org/jeps/491[JEP 491: Synchronize Virtual Threads without Pinning]
159 |
160 | To provide some context for this JEP: Virtual Threads are lightweight threads managed by the JVM, designed to have minimal overhead compared to traditional platform threads. They are particularly well-suited for I/O-bound or highly concurrent applications, as they enable efficient scaling without the resource constraints associated with platform threads. When executed, virtual threads are mounted onto platform threads (also called carrier threads), with the JVM handling scheduling and context switching. This abstraction simplifies concurrent programming by reducing the need for complex thread-pooling or asynchronous programming constructs. Virtual threads were introduced as part of https://openjdk.org/projects/loom/[Project Loom] and formalized in https://openjdk.org/jeps/444[JEP 444].
161 |
162 | An issue up until now was that Java synchronization didn't unmount the platform thread, thus the platform thread was *pinned* to the virtual thread which negatively impacted the scalability of virtual threads.
163 | For example, if too many threads are pinned to the platform threads available to the JVM we can run into starvation, or even deadlock issues.
164 |
165 | This JEP aims to resolve this issue by making it possible for Virtual Threads that block in such cases to release their underlying platform threads. This will almost fully eliminate cases of VT being pinned to platform threads and resolve one of the most frequently encountered performance issue when adapting them.
166 |
167 | Netflix also shared an interesting writeup on this issue on their TechBlog called https://netflixtechblog.com/java-21-virtual-threads-dude-wheres-my-lock-3052540e231d[Java 21 Virtual Threads - Dude, Where’s My Lock?].
168 |
169 | === https://openjdk.org/jeps/501[JEP 501: Deprecate the 32-bit x86 Port for Removal]
170 |
171 | The final remaining 32-bit x86 port which is the one for Linux is being deprecated, and thus all downstream ones. After the 32-bit x86 port is removed, the only way to run Java programs on 32-bit x86 processors will be the architecture-agnostic https://openjdk.org/projects/zero/[Zero] port of the JDK.
172 |
173 | == Language specification
174 |
175 | The Java language continues to evolve with various enhancements to make it more flexible, expressive and convenient to use. There are enhancements for people of all skill levels geared towards making sure it can meet today's and tomorrow's needs.
176 |
177 | Let's take a look at the latest preview features, including updates to pattern matching, flexible constructors, and simplified module imports, and how they've evolved based on community feedback.
178 |
179 | === https://openjdk.org/jeps/488[JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview)]
180 |
181 | This JEP first introduced as 455 returns without any changes. It aims to enhance pattern matching by allowing primitives in all pattern contexts, and allowing one to use them with instanceof and switch as well.
182 |
183 | === https://openjdk.org/jeps/492[JEP 492: Flexible Constructor Bodies (Third Preview)]
184 |
185 | This proposed Java language feature allows statements before explicit constructor invocations, enabling more natural field initialization. As a preview feature in JDK 22 and 23, it introduces two constructor phases: a prologue and epilogue respectively to help developers place initialization logic more intuitively while preserving existing instantiation safeguards. This proposal has not changed compared to the second preview.
186 |
187 | === https://openjdk.org/jeps/494[JEP 494: Module Import Declarations (Second Preview)]
188 |
189 | This will allow us to easily import all packages exported by a module, this facilitates the reuse of modular libraries without requiring the importing code to be within a module itself. It will also allow beginners to more easily use third-party libraries and core Java classes without needing to know their exact location within the package hierarchy.
190 |
191 | Compared to the first revision there are two additions:
192 |
193 | * the restriction that no module is able to declare a transitive dependency on the `java.base` module has been lifted, and the `java.se module` now transitively requires the `java.base` module
194 | * type-import-on-demand declarations are now allowed to shadow module import declarations.
195 |
196 | For example: `import module java.base;`.
197 |
198 | === https://openjdk.org/jeps/495[JEP 495: Simple Source Files and Instance Main Methods (Fourth Preview)]
199 |
200 | This preview which hasn't changed from it's previous iteration where it was known as `implicitly Declared Classes and Instance Main Methods,` would enable simplified programs by allowing them to be defined in an implicit class and an instance method `void main()`.
201 |
202 | == Security
203 |
204 | Java's security continues to evolve with enhancements such as quantum-resistant algorithms and the removal of outdated features.
205 | These changes help ensure that Java remains a secure and future-proof platform. Not only are today's security needs tackled, but the language is also preparing for tomorrow's challenges such as the rise of quantum computing.
206 |
207 | Let's dive into the key security updates!
208 |
209 | === https://openjdk.org/jeps/478[JEP 478: Key Derivation Function API (Preview)]
210 |
211 | This proposal aims to introduce an API to derive additional keys from a secret key and other data through cryptographic algorithms as Key Derivation Functions (KDFs).
212 | KDF is part of the cryptographic standard https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/pkcs11-spec-v3.1-os.html[PKCS #11], and are one of the key elements needed to implement Hybrid Public Key Encryption (HPKE). HPKE is a post-quantum cryptographic algorithm designed to be resistant to quantum computers.
213 |
214 | === https://openjdk.org/jeps/486[JEP 486: Permanently Disable the Security Manager]
215 |
216 | The Security Manager, deprecated in Java 17, has now been permanently disabled in JDK 24 and is slated for complete removal in a future release. Originally designed to secure untrusted code (e.g., applets), the Security Manager provided a set of checks for actions like thread creation and file access. However, it was complex to maintain and had a significant performance footprint when enabled. Its removal has led to the deletion of over 14,000 lines of code, simplifying the JDK.
217 |
218 | Opinions on the removal are divided. While most developers are unaffected, some platforms—particularly those with plugin systems like Kafka Connect, Elasticsearch, and Kestra—face challenges. These systems rely on executing untrusted code, and the Security Manager provided a built-in mechanism for enforcing security policies. Without it, developers must now implement alternatives such as sandboxing (e.g., Docker, GraalVM) or custom access controls using Java agents.
219 |
220 | While modern security needs are better addressed by tools like containers and OS-level sandboxing, the transition away from the Security Manager requires effort and may not fully replicate its functionality for all use cases.
221 |
222 | An interesting read on this topic is also: https://stuartmarks.wordpress.com/2024/12/12/detoxifying-the-jdk-source-code/[Stuart Marks - Detoxifying the JDK Source Code].
223 |
224 | === https://openjdk.org/jeps/496[JEP 496: Quantum-Resistant Module-Lattice-Based Key Encapsulation Mechanism]
225 |
226 | JEP 496 introduces an implementation of the key encapsulation mechanism based on a quantum-resistant algorithm Module-Lattice (ML-KEM).These are used to secure symmetric keys over unsecured communication channels using public key cryptography.
227 |
228 | Module-Lattice-Based Key Encapsulation Mechanism (ML-KEM), is a quantum-resistant algorithm standardized by NIST in https://csrc.nist.gov/pubs/fips/203/final[FIPS 203], to secure symmetric keys over unsecured channels using public key cryptography. It is designed to withstand attacks from future quantum computers, which could break current algorithms like RSA and Diffie-Hellman using https://www.wikiwand.com/en/articles/Shor's_algorithm[Shor's algorithm]. While quantum computers capable of such attacks are still far off (requiring thousands of Qubits, compared to today's ~64 Qubit systems), the transition to quantum-resistant algorithms is urgent to protect against "harvest now, decrypt later" threats.
229 |
230 | This proposal integrates ML-KEM into Java's security APIs, thus providing implementations for:
231 |
232 | * `KeyPairGenerator`
233 | * `KEM`
234 | * `KeyFactory`
235 |
236 | And supporting three parameter sets:
237 |
238 | * `ML-KEM-512`
239 | * `ML-KEM-768`
240 | * `ML-KEM-1024`
241 |
242 | It also facilitates key generation and certificate signing via the keytool command.
243 |
244 | This integration directly into the JDK enables a smooth adoption of quantum-resistant cryptography across all supported platforms, which will help future-proofing our applications against quantum computing threats. This aligns with https://www.nist.gov/[NIST]'s recommendation to transition to post-quantum algorithms within the next decade.
245 |
246 | === https://openjdk.org/jeps/497[JEP 497: Quantum-Resistant Module-Lattice-Based Digital Signature Algorithm]
247 |
248 | JEP 497 introduces the Module-Lattice-Based Digital Signature Algorithm (ML-DSA), a quantum-resistant algorithm standardized by NIST in https://csrc.nist.gov/pubs/fips/204/final[FIPS 204], to enhance the security of Java applications. It is designed to withstand attacks from future quantum computers, which could break current algorithms like RSA and Diffie-Hellman using https://www.wikiwand.com/en/articles/Shor's_algorithm[Shor's algorithm]. While quantum computers capable of such attacks are still far off (requiring thousands of Qubits, compared to today's ~64 Qubit systems), the transition to quantum-resistant algorithms is urgent to protect against "harvest now, decrypt later" threats.
249 |
250 | This proposal integrates ML-DSA into Java's security APIs, thus providing implementations for:
251 |
252 | * `KeyPairGenerator`
253 | * `KEM`
254 | * `KeyFactory`
255 |
256 | And supporting three parameter sets:
257 |
258 | * `ML-DSA-44`
259 | * `ML-DSA-65`
260 | * `ML-DSA-87`
261 |
262 | This integration directly into the JDK enables a smooth adoption of quantum-resistant cryptography across all supported platforms, which will help future-proofing our applications against quantum computing threats. This aligns with https://www.nist.gov/[NIST]'s recommendation to transition to post-quantum algorithms within the next decade.
263 |
264 | == Tools
265 |
266 | The tooling ecosystem is evolving to better meet today's deployment and image creation needs, helping developers address the demands of modern development workflows.
267 |
268 | === https://openjdk.org/jeps/493[JEP 493: Linking Run-Time Images without JMODs]
269 |
270 | This enhancement reduces the JDK's size by roughly 25% by enabling the `jlink` tool to create custom run-time images without relying on the JDK's JMOD files. *Note:* Since this feature is not enabled by default, and not all vendors may choose to implement this feature the JDK needs to be built with the `--enable-linkable-runtime` option, the resulting JDK omits JMOD files, and `jlink` can extract modules directly from the run-time image itself. This capability is particularly advantageous in cloud environments, where smaller container images improve deployment efficiency.
271 |
272 | The `jlink` tool in such a JDK can consume modules from the run-time image, modular JARs, or JMOD files, preferring the latter if available. For example, creating a run-time image with only `java.base` and `java.xml` works as usual:
273 |
274 | [source,bash]
275 | ----
276 | $ jlink --add-modules java.xml --output image
277 | $ image/bin/java --list-modules
278 | java.base@24
279 | java.xml@24
280 | ----
281 |
282 | The resulting image is about 60% smaller than a full JDK run-time image. For more complex cases, such as linking an application module (`app`) and its dependency (`lib`), the process remains straightforward:
283 |
284 | [source,bash]
285 | ----
286 | $ jlink --module-path mlib --add-modules app --output app
287 | ----
288 |
289 | However, there are some restrictions: `jlink` cannot create images containing itself (`jdk.jlink`), fails if user-editable configuration files (e.g., `java.security`) are modified, and does not support cross-linking or `--patch-module`.
290 |
291 | == General
292 |
293 | Beyond the major enhancement proposals, Java 24 includes a variety of smaller updates, removals, and deprecations that further improve the language.
294 |
295 | Some examples:
296 |
297 | Additions:
298 |
299 | * Unicode 16 support which enables better handling of modern text and emojis
300 | * New Java Flight Recorder events to further enhance observability
301 | * New MXBean to Monitor and Manage Virtual Thread Scheduler complementing the enhancements from project Loom
302 | * Support for including security properties files so security properties can more easily be managed in a centralized manner
303 |
304 | Removals:
305 |
306 | * Linux Desktop GTK2 Support as all Linux distributions supported by JDK 24 provide GTK3 support
307 | * JDK1.1 Compatible Behavior for "EST", "MST", and "HST" Time Zones, the appropriate zone IDs listed in https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/time/ZoneId.html#SHORT_IDS[ZoneId.SHORT_IDS] should be used
308 |
309 | Deprecations:
310 |
311 | * jstatd tool to further reduce dependencies on Remote Method Invocation, the monitoring of local VMs using the Attach API isn't impacted
312 | * debugd subcommand of the jhsdb tool as this remote debug server is not widely used, nor documented and dependencies on Remote Method Invocation are being reduced as much as possible
313 | * jrunscript tool as this tool is no longer functional given the removal of the JavaScript engine in Java 15 as part of https://openjdk.org/jeps/372[JEP 372]
314 |
315 | Issues:
316 |
317 | * Undefined type variables no longer resulting in null, but rather throwing a `TypeNotPresentException`
318 | * Single-line leading `///` dangling comments will no longer trigger a warning
319 |
320 | As always, I recommend checking out the https://jdk.java.net/24/release-notes[release notes]
321 |
322 | == Thoughts
323 |
324 | Once again, an impressive list of enhancements has been delivered, and significant progress has been made on long-running projects like Loom.
325 |
326 | We're seeing some powerful new features such as Stream Gatherers which open up new possibilities for data processing, AOT class loading which may significantly reduce startup times for our applications, and quantum-resistant algorithms which help ensure Java remains secure in the face of future threats.
327 |
328 | Java 24 offers improvements for both newcomers and seasoned developers, underscoring the language's enduring relevance. The strong focus on security addresses today's critical challenges, while reductions in resource consumption help lower Java's ecological footprint and increase the cost-effectiveness for cloud and enterprise environments.
329 |
330 | Given what we've seen in this release, and what's already in the works for Java 25 I'm certainly optimistic about the future!
331 |
332 | You can find the latest version of this article, and code examples in my https://github.com/SimonVerhoeven/java24-demo[java24-demo] repository.
333 |
334 | == Lookahead
335 |
336 | General availability of Java 25 is planned for September 2025, and while at the time of writing there are no JEPs targeted at it yet, we can already make some guesses based upon the submitted candidates and drafts.
337 |
338 | Some of the ones I hope and expect to see land are:
339 |
340 | * https://openjdk.org/jeps/495[JEP-495: Simple Source Files and Instance Main Methods (Fourth Preview)] - which would make the language more accessible to new developers.
341 |
342 | * https://openjdk.org/jeps/502[JEP-502: Stable Values (Preview)] - which would bring us immutable value holders that are at most initialized once as it would help us move towards deferred immutability through `StableValue` and `StableSupplier`.
343 |
344 | * https://openjdk.org/jeps/8340343[JEP draft 8340343: Structured Concurrency (Fifth Preview)] - structured concurrency has received quite a bit of feedback so far, so I hope to see it land, but we'll have to see. It will certainly help out when writing multithreaded applications, and it'll be nice to see https://openjdk.org/projects/loom/[project Loom] progress.
345 |
346 | * https://openjdk.org/jeps/8326035[JEP draft 8326035: CDS Object Streaming] - proposes to add an object archiving mechanism for Class-Data Sharing (CDS) in the Z Garbage Collector (ZGC) since it'll enhance the usage of the AOT cache from https://openjdk.org/projects/leyden/[project Leyden]
347 |
348 | * https://openjdk.org/jeps/8300911[JEP draft 8300911: PEM API (Preview)] - introduces an easy-to-use API for encoding and decoding Privacy-Enhanced Mail (PEM) format as it helps underscore Java's commitment to enabling highly secure applications and address one of the pain points expressed in the https://mail.openjdk.org/pipermail/security-dev/2022-April/029757.html[ Java Cryptographic Extensions Survey] in April 2022.
349 |
350 | While some of these are still in draft form and subject to change they do already give us a nice glance at what the architects are looking into.
351 | Furthermore, these changes help highlight Java's roadmap and continuous evolution.
352 | If you're as excited as I am about all these changes, and want to provide feedback I highly recommend trying out the https://jdk.java.net/25/[preview builds]!
353 |
354 | == Resources
355 |
356 | Some useful resources to dive deeper into the Java ecosystem, and stay up-to-date are:
357 |
358 | * https://jdk.java.net/24/release-notes[The release notes] - The official source for all changes, including new features, bug fixes, and deprecations
359 | * https://javaalmanac.io/jdk/24/[The Java version almanac] - A great resource with details on distributions, and API differences between various releases
360 | * https://foojay.io/[Foojay] - A magnificent Java community offering articles, tutorials, and discussions on the latest in the Java ecosystem
361 | * https://sdkman.io/[SDKman!] - a great tool to manage the installation of various tools and languages
362 | * https://inside.java/[Inside Java] - News updates by Java team members at Oracle
363 | * https://www.jcp.org/[Java Community Process] - the place where people can propose, discuss, and approve new features through a Java Specification Request (JSR)
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | 4.0.0
6 |
7 | dev.simonverhoeven
8 | java24-demo
9 | 1.0-SNAPSHOT
10 |
11 | java24-demo
12 | Java 24
13 |
14 |
15 | UTF-8
16 | 24
17 | 24
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | org.apache.maven.plugins
31 | maven-compiler-plugin
32 |
33 | 24
34 | 24
35 | --enable-preview
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/finalized/ClassFileAPI.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.finalized;
2 |
3 | import java.lang.classfile.ClassModel;
4 | import java.lang.classfile.MethodModel;
5 | import java.lang.classfile.ClassFile;
6 | import java.nio.file.Files;
7 | import java.nio.file.Path;
8 | import java.util.Objects;
9 |
10 |
11 | /// JEP 484 - Class file API
12 |
13 | public class ClassFileAPI {
14 |
15 | public static void main() throws Exception {
16 | final var stream = ClassFileAPI.class.getClassLoader().getResource("dev/simonverhoeven/java24demo/finalized/ClassFileAPI.class");
17 | final var classFilePath = Path.of(Objects.requireNonNull(stream).toURI());
18 | final var classBytes = Files.readAllBytes(classFilePath);
19 | final var classFile = ClassFile.of();
20 | final var classModel = classFile.parse(classBytes);
21 |
22 | listAllMethods(classModel);
23 |
24 | final var newClassModel = classModelWithoutMeaning(classFile, classModel);
25 | listAllMethods(newClassModel);
26 | }
27 |
28 | private static ClassModel classModelWithoutMeaning(ClassFile classFile, ClassModel classModel) {
29 | byte[] newBytes = classFile.build(classModel.thisClass().asSymbol(),
30 | classBuilder -> {
31 | for (final var element : classModel) {
32 | if (!(element instanceof MethodModel mm
33 | && mm.methodName().stringValue().startsWith("meaning"))) {
34 | classBuilder.with(element);
35 | }
36 | }
37 | });
38 | return classFile.parse(newBytes);
39 | }
40 |
41 | private static void listAllMethods(ClassModel classModel) {
42 | final var methods = classModel.methods();
43 |
44 | System.out.println("Methods:");
45 | methods.forEach(method -> System.out.println(method.methodName()));
46 | System.out.println("====================");
47 | }
48 |
49 | private String meaningOfLife() {
50 | return "42";
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/finalized/GathererOverview.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.finalized;
2 |
3 | import java.util.List;
4 | import java.util.concurrent.atomic.AtomicInteger;
5 | import java.util.concurrent.atomic.AtomicReference;
6 | import java.util.function.BiConsumer;
7 | import java.util.function.BinaryOperator;
8 | import java.util.function.Predicate;
9 | import java.util.function.Supplier;
10 | import java.util.stream.Gatherer;
11 | import java.util.stream.Gatherers;
12 | import java.util.stream.IntStream;
13 |
14 | /// JEP 485 - Gatherers
15 |
16 | public class GathererOverview {
17 | public static Gatherer.Integrator passthroughIntegrator() {
18 | return (_, element, downstream) -> {
19 | downstream.push(element);
20 | return true;
21 | };
22 | }
23 |
24 | public static Gatherer.Integrator filter(Predicate super T> filter) {
25 | return (_, element, downstream) -> {
26 | if (filter.test(element))
27 | downstream.push(element);
28 | return true;
29 | };
30 | }
31 |
32 | public static Gatherer limit(int numberOfElements) {
33 | Supplier initializer = AtomicInteger::new;
34 | Gatherer.Integrator integrator =
35 | (state, element, downstream) -> {
36 | var currentIndex = state.getAndIncrement();
37 | if (currentIndex < numberOfElements) {
38 | downstream.push(element);
39 | }
40 | return currentIndex + 1 < numberOfElements;
41 | };
42 | return Gatherer.ofSequential(initializer, integrator);
43 | }
44 |
45 | // finisher
46 | // receives states after stream element processing & downstream, potentially emits further elements downstream dependent on the status
47 | public static BiConsumer, Gatherer.Downstream>> finisher() {
48 | return (state, downstream) -> {
49 | if (!state.isEmpty()) {
50 | downstream.push(List.copyOf(state));
51 | }
52 | };
53 | }
54 |
55 | // combiner
56 | // Needed when using a stateful gatherer in parallel. It combines 2 statuses during the join phase of parallel stream processing.
57 | public static BinaryOperator> lowestNumberCombiner() {
58 | return (firstState, secondState) -> {
59 | final var firstElement = firstState.get();
60 | final var secondElement = secondState.get();
61 |
62 | if (secondElement == null) {
63 | return firstState;
64 | } else if (firstElement == null) {
65 | return secondState;
66 | } else {
67 | return firstElement > secondElement ? secondState : firstState;
68 | }
69 | };
70 | }
71 |
72 | public static Gatherer, Integer> lowestGatherer() {
73 | return Gatherer.of(
74 | // Initializer
75 | AtomicReference::new,
76 | // Gatherer
77 | (state, element, _) -> {
78 | Integer lowest = state.get();
79 | if (lowest == null || element <= lowest) {
80 | state.set(element);
81 | }
82 | return true;
83 | },
84 | // Combiner
85 | lowestNumberCombiner(),
86 | // Finisher
87 | (state, downstream) -> {
88 | Integer lowest = state.get();
89 | if (lowest != null) {
90 | downstream.push(lowest);
91 | }
92 | });
93 | }
94 |
95 | public static void main() {
96 | final var foldResult = IntStream.range(1, 10).boxed()
97 | .gather(
98 | Gatherers.fold(() -> "0", (string, number) -> string + "-" + number)
99 | )
100 | .findFirst();
101 |
102 | System.out.println("Folded: " + foldResult.orElse("empty"));
103 |
104 | final var squareResult = IntStream.range(1, 10).boxed()
105 | .gather(
106 | Gatherers.mapConcurrent(5, number -> number*number)
107 | )
108 | .toList();
109 |
110 | System.out.println("Map concurrent: " + squareResult);
111 |
112 | final var scanResult = IntStream.range(1, 10).boxed()
113 | .gather(
114 | Gatherers.scan(() -> 0, Integer::sum)
115 | )
116 | .toList();
117 |
118 | System.out.println("Prefix scan - incremental reduction: " + scanResult);
119 |
120 | final var windowFixedResult = IntStream.range(1, 10).boxed()
121 | .gather(Gatherers.windowFixed(2))
122 | .toList();
123 |
124 | System.out.println("Window fixed: " + windowFixedResult);
125 |
126 | final var windowSlidingResult = IntStream.range(1, 10).boxed()
127 | .gather(Gatherers.windowSliding(3))
128 | .toList();
129 |
130 | System.out.println("Window sliding: " + windowSlidingResult);
131 |
132 | final var customLimit = IntStream.range(1, 10).boxed()
133 | .gather(
134 | limit(3)
135 | ).toList();
136 |
137 | System.out.println("Custom limit: " + customLimit);
138 |
139 | final var passthrough = IntStream.range(1, 10).boxed()
140 | .gather(
141 | Gatherer.of(passthroughIntegrator())
142 | ).toList();
143 |
144 | System.out.println("Passthrough: " + passthrough);
145 |
146 | final var evenFilter = IntStream.range(1, 10).boxed()
147 | .gather(
148 | Gatherer.of(filter(i -> i%2 == 0))
149 | ).toList();
150 |
151 | System.out.println("Even filter: " + evenFilter);
152 |
153 | final var lowestResult = List.of(1,2,3,4,5,6,7,8,9,10).parallelStream().gather(lowestGatherer()).findFirst();
154 | System.out.println("Using finisher and combiner result: " + lowestResult.orElseThrow(IllegalStateException::new));
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/finalized/MemoryAccessMethodUsage.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.finalized;
2 |
3 | // JEP 498: Warn upon Use of Memory-Access Methods in sun.misc.Unsafe
4 |
5 | import sun.misc.Unsafe;
6 |
7 | public class MemoryAccessMethodUsage {
8 |
9 | public static void main() throws NoSuchFieldException, IllegalAccessException {
10 | final var unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
11 | unsafeField.setAccessible(true);
12 | final var unsafe = (Unsafe) unsafeField.get(null);
13 | unsafe.allocateMemory(1024);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/finalized/SynchronizeVTWithoutPinning.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.finalized;
2 |
3 | import java.io.IOException;
4 | import java.net.Socket;
5 |
6 |
7 | /// JEP 491: Synchronize Virtual Threads without Pinning
8 |
9 | public class SynchronizeVTWithoutPinning {
10 |
11 | synchronized byte[] getDataFromGivenSocket(Socket socket) throws IOException {
12 | final var buffer = new byte[1024];
13 | final var read = socket.getInputStream().read(buffer); // We could potentially get blocked here
14 | // ...
15 |
16 | return new byte[1024];
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/incubator/vectors/VectorSample.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.incubator.vectors;
2 |
3 | import jdk.incubator.vector.IntVector;
4 | import jdk.incubator.vector.VectorMask;
5 | import jdk.incubator.vector.VectorSpecies;
6 |
7 | import java.util.Arrays;
8 |
9 | // JEP 489 Vector API - Ninth incubation
10 |
11 | /*
12 | Samples: https://github.com/openjdk/jdk/tree/master/test/micro/org/openjdk/bench/jdk/incubator/vector
13 | */
14 |
15 |
16 | public class VectorSample {
17 | public static void main() {
18 | int[] result = new int[5];
19 | final var vector1 = new int[]{1, 2, 3, 4, 5};
20 | final var vector2 = new int[]{100, 200, 300, 400, 500};
21 |
22 | scalarAddition(vector1, vector2, result);
23 | System.out.println(Arrays.toString(result));
24 | vectorAddition(vector1, vector2, result);
25 | System.out.println(Arrays.toString(result));
26 | vectorAdditionWithoutSIMDSupport(vector1, vector2, result);
27 | System.out.println(Arrays.toString(result));
28 | }
29 |
30 | public static void scalarAddition(int[] a, int[] b, int[] result) {
31 | for (int i = 0; i < a.length; i++) {
32 | result[i] = a[i] + b[i];
33 | }
34 | }
35 |
36 | public static void vectorAddition(int[] vector1, int[] vector2, int[] result) {
37 | final VectorSpecies species = IntVector.SPECIES_PREFERRED;
38 | for (int index = 0; index < vector1.length; index += species.length()) {
39 | VectorMask mask = species.indexInRange(index, vector1.length);
40 | IntVector v1 = IntVector.fromArray(species, vector1, index, mask);
41 | IntVector v2 = IntVector.fromArray(species, vector2, index, mask);
42 | IntVector vc = v1.add(v2, mask);
43 | vc.intoArray(result, index, mask);
44 | }
45 | }
46 |
47 | public static void vectorAdditionWithoutSIMDSupport(int[] vector1, int[] vector2, int[] result) {
48 | final VectorSpecies species = IntVector.SPECIES_PREFERRED;
49 | int index = 0;
50 | for (;index < species.loopBound(vector1.length); index += species.length()) {
51 | IntVector v1 = IntVector.fromArray(species, vector1, index);
52 | IntVector v2 = IntVector.fromArray(species, vector2, index);
53 | IntVector vc = v1.add(v2);
54 | vc.intoArray(result, index);
55 | }
56 |
57 | // Handle remaining elements
58 | for (int index2 = index; index2 < vector1.length; index2++) {
59 | result[index2] = vector1[index2] + vector2[index2];
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/preview/KeyDerivedFunction.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.preview;
2 |
3 | import javax.crypto.KDF;
4 | import javax.crypto.SecretKey;
5 | import javax.crypto.spec.HKDFParameterSpec;
6 | import java.security.InvalidAlgorithmParameterException;
7 | import java.security.NoSuchAlgorithmException;
8 | import java.security.spec.AlgorithmParameterSpec;
9 |
10 | /// JEP 478: Key Derivation Function API (Preview)
11 |
12 | public class KeyDerivedFunction {
13 |
14 | public SecretKey generateDerivedKey(SecretKey secretKey, byte[] salt, byte[] information) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
15 | KDF hkdf = KDF.getInstance("HKDF-SHA256");
16 |
17 | AlgorithmParameterSpec params =
18 | HKDFParameterSpec.ofExtract()
19 | .addIKM(secretKey)
20 | .addSalt(salt).thenExpand(information, 32);
21 |
22 | return hkdf.deriveKey("AES", params);
23 | }
24 |
25 | public Object generateEntropicData(AlgorithmParameterSpec parameterSpec) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
26 | KDF hkdf = KDF.getInstance("HKDF-SHA256");
27 | return hkdf.deriveData(parameterSpec);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/preview/ModuleImport.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.preview;
2 |
3 | import static java.lang.System.out;
4 | import module java.base;
5 |
6 | /// JEP 494: Module Import Declarations (Second Preview)
7 |
8 | public class ModuleImport {
9 |
10 | public static void main(String[] args) {
11 | List elements = List.of("One", "two", "THREE");
12 | elements.stream().map(String::toUpperCase).forEach(out::println);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/preview/PrimitiveTypes.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.preview;
2 |
3 | import java.security.SecureRandom;
4 |
5 | /// JEP 488 - Primitive Types in Patterns, instanceof, and switch (Second Preview)
6 |
7 | public class PrimitiveTypes {
8 | record ExamResults(int score){}
9 |
10 | // primitives are now supported pattern matching,
11 | // boolean, float, double and long are now also supported in switches
12 | public String determineGrade(ExamResults examResults) {
13 | return switch (examResults.score) {
14 | case int i when i >= 90 -> "A";
15 | case int i when i >= 80 -> "B";
16 | case int i when i >= 70 -> "C";
17 | case int i when i >= 60 -> "D";
18 | case int i when i >= 50 -> "E";
19 | case int i -> "Failed with a score of " + examResults.score;
20 | };
21 | }
22 |
23 | // We can now pattern match using primitive types, which makes switching to type patterns easier as well
24 | public void patterns() {
25 | int number = new SecureRandom().nextInt();
26 |
27 | if (number instanceof int num) {
28 | System.out.println(num);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/preview/QuantRestModLatBasedDSA.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.preview;
2 |
3 | import javax.crypto.DecapsulateException;
4 | import java.nio.charset.StandardCharsets;
5 | import java.security.InvalidAlgorithmParameterException;
6 | import java.security.InvalidKeyException;
7 | import java.security.KeyPair;
8 | import java.security.KeyPairGenerator;
9 | import java.security.NoSuchAlgorithmException;
10 | import java.security.Signature;
11 | import java.security.SignatureException;
12 | import java.security.spec.NamedParameterSpec;
13 |
14 | /// JEP 496: Quantum-Resistant Module-Lattice-Based Digital Signature Algorithm
15 |
16 | public class QuantRestModLatBasedDSA {
17 |
18 | public static void main() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, DecapsulateException, SignatureException {
19 | final var keyPairGenerator = KeyPairGenerator.getInstance("ML-DSA");
20 | keyPairGenerator.initialize(NamedParameterSpec.ML_DSA_87);
21 | final var keyPair = keyPairGenerator.generateKeyPair();
22 |
23 | final var messageBytes = "demo".getBytes(StandardCharsets.UTF_8);
24 |
25 | final var signature = createSignature(messageBytes, keyPair);
26 |
27 | final var verified = verifyMessage(keyPair, messageBytes, signature);
28 |
29 | System.out.println(verified);
30 | }
31 |
32 | private static byte[] createSignature(byte[] messageBytes, KeyPair keyPair) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
33 | final var dsaSigner = Signature.getInstance("ML-DSA");
34 | dsaSigner.initSign(keyPair.getPrivate());
35 | dsaSigner.update(messageBytes);
36 | return dsaSigner.sign();
37 | }
38 |
39 | private static boolean verifyMessage(KeyPair keyPair, byte[] messageBytes, byte[] signature) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
40 | final var signatureVerifier = Signature.getInstance("ML-DSA");
41 | signatureVerifier.initVerify(keyPair.getPublic());
42 | signatureVerifier.update(messageBytes);
43 | return signatureVerifier.verify(signature);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/preview/QuantRestModLatBasedKEM.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.preview;
2 |
3 | import java.security.InvalidAlgorithmParameterException;
4 | import java.security.InvalidKeyException;
5 | import java.security.KeyPairGenerator;
6 | import java.security.NoSuchAlgorithmException;
7 | import java.security.spec.NamedParameterSpec;
8 | import javax.crypto.DecapsulateException;
9 | import javax.crypto.KEM;
10 |
11 | /// JEP 496: Quantum-Resistant Module-Lattice-Based Key Encapsulation Mechanism
12 |
13 | public class QuantRestModLatBasedKEM {
14 |
15 | public static void main() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, DecapsulateException {
16 | final var keyPairGenerator = KeyPairGenerator.getInstance("ML-KEM");
17 | keyPairGenerator.initialize(NamedParameterSpec.ML_KEM_1024);
18 | final var keyPair = keyPairGenerator.generateKeyPair();
19 |
20 | final var kem = KEM.getInstance("ML-KEM");
21 | final var encapsulator = kem.newEncapsulator(keyPair.getPublic());
22 | final var encapsulated = encapsulator.encapsulate();
23 | final var message = encapsulated.encapsulation(); // Message to send to the receiver
24 | final var secretKeySender = encapsulated.key(); //
25 |
26 | final var decapsulator = kem.newDecapsulator(keyPair.getPrivate());
27 | // Recovers the secret key from the KEM sent by the sender
28 | final var secretKeyReceiver = decapsulator.decapsulate(message);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/preview/SimpleClass.java:
--------------------------------------------------------------------------------
1 | void main() {
2 | System.out.println("JEP 495: Simple Source Files and Instance Main Methods (Fourth Preview)");
3 | }
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/preview/StructuredConcurrency.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.preview;
2 |
3 | import java.util.concurrent.StructuredTaskScope;
4 | import java.util.function.Supplier;
5 |
6 | /// JEP 499: Structured Concurrency (Fourth Preview)
7 |
8 | public class StructuredConcurrency {
9 |
10 | public GarderobeSelectionInput composeGarderobeSelectionInput(String userId) {
11 | try (final var scope = new StructuredTaskScope.ShutdownOnFailure()) {
12 | Supplier personTask =
13 | scope.fork(() -> findPerson(userId));
14 | Supplier weatherTask =
15 | scope.fork(this::fetchWeather);
16 | Supplier activityTask =
17 | scope.fork(() -> findActivity(userId));
18 | scope.join();
19 |
20 | final var person = personTask.get();
21 | final var weather = weatherTask.get();
22 | final var activity = activityTask.get();
23 |
24 | return new GarderobeSelectionInput(person, weather, activity);
25 |
26 | } catch (InterruptedException e) {
27 | throw new RuntimeException(e);
28 | }
29 | }
30 |
31 | Person findPerson(String id) throws InterruptedException {
32 | Thread.sleep(2000L);
33 | return null;}
34 | Weather fetchWeather() throws InterruptedException {
35 | Thread.sleep(5000L);
36 | return null;}
37 | Activity findActivity(String id) throws InterruptedException {
38 | Thread.sleep(3000L);
39 | return null;
40 | }
41 |
42 | class Person {}
43 | class Weather {}
44 | class Activity {}
45 | public record GarderobeSelectionInput(Person person, Weather weather, Activity activity){}
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/preview/Super.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.preview;
2 |
3 | /// JEP 982 - Flexible Constructor Bodies (Third Preview)
4 | public class Super extends Life{
5 | private static final int MEANING_OF_LIFE = 42;
6 |
7 | public Super(int meaningOfLife) {
8 | if (MEANING_OF_LIFE != meaningOfLife) {
9 | throw new IllegalArgumentException("Please read Hitchhiker's guide to the galaxy");
10 | }
11 | super(meaningOfLife);
12 | }
13 |
14 | public Super() {
15 | var meaningOfLife = MEANING_OF_LIFE;
16 | this(meaningOfLife);
17 | }
18 |
19 | void main() {
20 | new Super();
21 | }
22 | }
23 |
24 | class Life {
25 | int meaningOfLife;
26 |
27 | public Life(int meaningOfLife) {
28 | this.meaningOfLife = meaningOfLife;
29 | }
30 | }
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/preview/scopedvalues/Greeter.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.preview.scopedvalues;
2 |
3 | public class Greeter {
4 | public static void greet() {
5 | System.out.println("Hello");
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/dev/simonverhoeven/java24demo/preview/scopedvalues/Scoper.java:
--------------------------------------------------------------------------------
1 | package dev.simonverhoeven.java24demo.preview.scopedvalues;
2 |
3 | // JEP 487 - Scoped Values (Fourth preview)
4 |
5 | public class Scoper {
6 | public final static ScopedValue NAME = ScopedValue.newInstance();
7 |
8 | public static void main() {
9 | ScopedValue.where(NAME, "Continuum Consulting NV").run(() -> Greeter.greet());
10 | ScopedValue.where(NAME, "BEJUG").run(() -> Greeter.greet());
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/module-info.java:
--------------------------------------------------------------------------------
1 | module java24demo {
2 | requires jdk.incubator.vector;
3 | requires jdk.unsupported;
4 | }
--------------------------------------------------------------------------------