Slide 1

Slide 1 text

Learning modern Java the playful way Marit van Dijk, Piotr Przybył Devoxx Belgium 2026

Slide 2

Slide 2 text

$ who are we Piotr Przybył @piotrprz @piotrprz.bsky.social Senior Developer Advocate Docker Captain Marit van Dijk @MaritvanDijk77 @maritvandijk.bsky.social Senior Developer Advocate

Slide 3

Slide 3 text

$ who are you

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Agenda ● Various features from recent Java versions (not all of them, obviously) ● Demos (obviously)

Slide 6

Slide 6 text

● Performance (Shenandoah, Compact Object Headers) ● More concurrency goodies (Scoped Values, revamped Structured Concurrency) ● Better observability & profiling ● Stuff for newbies / prototyping ● And more

Slide 7

Slide 7 text

● More Amber (pattern matching, data-oriented programming) ● Loom maturing (Structured Concurrency, Scoped Values) ● Panama + Vector API progress (performance, native interop) ● Leyden groundwork (startup, footprint) ● Stronger security defaults ● And more

Slide 8

Slide 8 text

● Compact Object Headers ● G1 garbage collector is default everywhere ● Preview features

Slide 9

Slide 9 text

● Value Objects: the dawn ● Simple JSON API ● And more

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

Compact source files & Instance main methods Standard feature in Java 25 JEP 512 ▶

Slide 15

Slide 15 text

Compact source files & Instance main methods public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } } void main() { IO.println("Hello World!"); }

Slide 16

Slide 16 text

Compact source files & Instance main methods import static java.lang.IO.println; void main() { IO.println("Hello World!"); }

Slide 17

Slide 17 text

DEMO 2: Playing with Java 24

Slide 18

Slide 18 text

All these pictures are from pixabay.com Stunning royalty-free images & royalty-free stock

Slide 19

Slide 19 text

“an apple on books” Multimodal encoder

Slide 20

Slide 20 text

Preparation: Indexing Multimodal encoder POST elasticsearch/catalogue { "filename" : "apple.png", "embedding" : [0.12, -0.48, 0.0231, …], … }

Slide 21

Slide 21 text

Application: Searching “apple” Multimodal encoder POST ${elasticsearch}/catalogue/_search { “apple” } POST ${elasticsearch}/catalogue/_search { } RRF Results: 1. … 2. … 3. … 4. … ▶

Slide 22

Slide 22 text

Records Standard feature in Java 16 JEP 395 immutable transparent data carriers ▶

Slide 23

Slide 23 text

final class QueryWithVector { private final String query; private final List vector; record QueryWithVector(String query, List vector) { @Override public String toString() { return "QueryWithVector[" + "query=" + query + ", " + "vector=[" + vector.getFirst() + ", --., " + vector.getLast() + ']'; } QueryWithVector(String query, List vector) { this.query = query; this.vector = vector; } @Override public String toString() { return "QueryWithVector[" + "query=" + query + ", " + "vector=[" + vector.getFirst() + ", --., " + vector.getLast() + ']'; } public String getQuery() { return query; } public List getVector() { return vector; } @Override public boolean equals(Object obj) { if (obj -= this) return true; if (obj -= null -| obj.getClass() -= this.getClass()) return false; var that = (QueryWithVector) obj; return Objects.equals(this.query, that.query) -& Objects.equals(this.vector, that.vector); } @Override public int hashCode() { return Objects.hash(query, vector); } } }

Slide 24

Slide 24 text

Module imports Standard feature in Java 25 JEP 511 import all packages exported by a module with one statement ● import module M; ● with transitive dependencies ● in case of a clash - import class explicitly ▶

Slide 25

Slide 25 text

import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Scanner; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Function; import java.util.stream.Collectors; import module java.base;

Slide 26

Slide 26 text

Compact source files & Instance main methods Standard feature in Java 25 JEP 512 Also comes with simple IO ▶

Slide 27

Slide 27 text

Stream Gatherers Standard feature in Java 24 JEP 485

Slide 28

Slide 28 text

Stream Gatherers Stream.of(...) .gather(a) [.gather(b)] [.gather(c)] .collect(...); custom intermediate operations Stream Gatherers - Deep Dive with the Expert: https://youtu.be/v_5SKpfkI2U Gatherers: The API Your Stream Was Missing: https://youtu.be/oVdWfU_IObY Hunting with Stream Gatherers: https://youtu.be/rvW8tu1n5x4 Extending Functional Pipelines with Gatherers: https://www.youtube.com/live/dxVDiJsyu3Y ▶

Slide 29

Slide 29 text

Preview features --enable-preview JEP 12 ▶

Slide 30

Slide 30 text

Structured Concurrency 🧪 Preview in Java 27 JEP 533 ● ● ● better "idioms" for multi-threaded code synchronous way of thinking help eliminate thread leaks and cancellation delays

Slide 31

Slide 31 text

Structured Concurrency POST ${elasticsearch}/catalogue/_search { “apple” } POST ${elasticsearch}/catalogue/_search { RRF Results: 1. … 2. … 3. … 4. … } Task Subtask combine Results: 1. … Subtask ▶

Slide 32

Slide 32 text

Structured Concurrency TL;DR: .open() with Joiner and Config, can (re)use thread pools, also platform ones try (var scope = StructuredTaskScope.open( StructuredTaskScope.Joiner.awaitAllSuccessfulOrThrow(), config -> config .withName("myStructuredConcurrency") .withTimeout(Duration.ofSeconds(5)) .withThreadFactory(myThreadFactory))) { var subtask1 = scope.fork(() -> action(--.)); var subtask2 = scope.fork(this-:anotherAction); scope.join(); combineResults(subtask1.get(), subtask2.get()); }

Slide 33

Slide 33 text

CompletableFuture has no future!

Slide 34

Slide 34 text

Lazy Constants 🧪 Preview in Java 27 JEP 531 ● ● ● Immutable Thread safe Lazily evaluated ▶

Slide 35

Slide 35 text

Lazy Constants static final LazyConstant OBJECT_MAPPER = LazyConstant.of(ObjectMapper-:new); -/ and later on OBJECT_MAPPER.get()--. OBJECT_MAPPER.orElse(--.) OBJECT_MAPPER.isInitialized()

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

Markdown Documentation Comments Standard feature in Java 23 JEP 467 ● ● ● ● Easier to read & write A dialect / variant of Markdown Old HTML javadoc still works Can still use @return, @param, @throws ▶

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

Stay up to date 1. 2. pom.xml / gradle.kts new idioms ▶

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

Compact Object Headers by Default Standard feature in Java 27 JEP 534 ● ● No need to do anything in Java 27 Reduce object headers from 96 bits down to 64 bits on 64-bit architectures ○ ○ ○ ● reduce heap size improve deployment density increase data locality Improve performance

Slide 42

Slide 42 text

final class Tiny {} int count = 10_000_000; var objects = new Tiny[count]; for (int i = 0; i < count; i-+) { objects[i] = new Tiny(); } ● Example: youtrack.jetbrains.com/issue/IJPL-212987 ▶

Slide 43

Slide 43 text

Vector API (Panama) 🧫 Incubator in Java 27 JEP 537 ▶

Slide 44

Slide 44 text

Incubator features: Vector --add-modules jdk.incubator.vector

Slide 45

Slide 45 text

● API to express vector computations ● Different performance characteristics ▶

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

$ docker exec -it es-local-dev /bin/sh -c "ps aux | cat" /usr/share/elasticsearch/jdk/bin/java -Des.networkaddress.cache.ttl=60 -Des.networkaddress.cache.negative.ttl=10 -XX:+AlwaysPreTouch -Xss1m -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djna.nosys=true -XX:-OmitStackTraceInFastThrow -Dio.netty.noUnsafe=true -Dio.netty.noKeySetOptimization=true -Dio.netty.recycler.maxCapacityPerThread=0 --add-opens=org.apache.lucene.core/org.apache.lucene.codecs.lucene99=org.elasticsearch.server --add-opens=org.apache.lucene.core/org.apache.lucene.codecs.hnsw=org.elasticsearch.server --add-opens=org.apache.lucene.core/org.apache.lucene.internal.vectorization=org.elasticsearch.server -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Dlog4j2.formatMsgNoLookups=true -Djava.locale.providers=CLDR -Dorg.apache.lucene.vectorization.upperJavaFeatureVersion=26 -Des.path.home=/usr/share/elasticsearch -Des.distribution.type=docker -Des.java.type=bundled JDK --enable-native-access=org.elasticsearch.nativeaccess,org.apache.lucene.core --enable-native-access=ALL-UNNAMED --illegal-native-access=deny -Des.cgroups.hierarchy.override=/ -XX:ReplayDataFile=logs/replay_pid%p.log -XX:+EnableDynamicAgentLoading -Djdk.attach.allowAttachSelf=true --patch-module=java.base=/usr/share/elasticsearch/lib/entitlement-bridge/elasticsearch-entitlement-bri dge-9.4.0.jar --add-exports=java.base/org.elasticsearch.entitlement.bridge=org.elasticsearch.entitlement,java.loggin g,java.net.http,java.naming,jdk.net,jdk.zipfs -XX:+UseG1GC -Djava.io.tmpdir=/tmp/elasticsearch-1825357143797079744 --add-modules=jdk.incubator.vector -Dorg.apache.lucene.store.defaultReadAdvice=normal -Dorg.apache.lucene.store.MMapDirectory.sharedArenaMaxPermits=1 -XX:+HeapDumpOnOutOfMemoryError -XX:+ExitOnOutOfMemoryError -XX:ErrorFile=hs_err_pid%p.log -Xlog:gc*,gc+age=trace,safepoint:file=gc.log:utctime,level,pid,tags:filecount=32,filesize=64m -Xms128m -Xmx2g -XX:MaxDirectMemorySize=1073741824 -XX:G1HeapRegionSize=4m -XX:InitiatingHeapOccupancyPercent=30 -XX:G1ReservePercent=15 --module-path /usr/share/elasticsearch/lib --add-modules=jdk.net --add-modules=jdk.management.agent --add-modules=ALL-MODULE-PATH -m org.elasticsearch.server/org.elasticsearch.bootstrap.Elasticsearch ▶

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

Simple JSON API 🧫 Incubator in Java 28 JEP 540 ● ● Simple, standard API for parsing and generating JSON documents Not intended to replace established external JSON libraries ▶

Slide 51

Slide 51 text

Value Objects 🧪 Preview in Java 28 JEP 401 ● ● Immutable Lack object identity ▶

Slide 52

Slide 52 text

Virtual Threads Standard feature in Java 21 JEP 444 ● ● ● ● ● ● ● ● not reinvent the wheel, keep threads model carried by platform / OS threads under the hood cheap to start unmounting carrier threads when waiting, e.g. for IO always daemons, with normal prio allow thread-per-request nicely (with debugging, troubleshooting etc.) improve scalability for asynchronous style

Slide 53

Slide 53 text

Virtual Threads won't magically squeeze more juice from your CPU

Slide 54

Slide 54 text

More on Virtual Threads ● ● Butcher Virtual Threads like a pro! https://youtu.be/UduECeqVMMY Virtual Threads, Structured Concurrency and Scoped Values: Putting it all together: https://youtu.be/2L7zLdHeyY0

Slide 55

Slide 55 text

Synchronize Virtual Threads without Pinning Standard feature in Java 24 JEP 491 ● Release platform threads in synchronized blocks ▶

Slide 56

Slide 56 text

Scoped Values Standard feature in Java 25 JEP 506 ● ● ● ● work nicely with Structured Concurrency run(Runnable r) or call(Callable c) where(--.) can be nested with its own scope as long as you don't mutate the darn thing!

Slide 57

Slide 57 text

Scoped Values one-way immutable "ThreadLocals" + bounded lifetime (visible in code) = simplified reasoning and improved performance (ThreadLocal doesn't change and doesn't get deprecated, only having them for millions of Virtual Threads might be problematic)

Slide 58

Slide 58 text

Scoped Values ▶

Slide 59

Slide 59 text

Flexible Constructor Bodies Standard feature in Java 25 JEP 513 ● ● ● ● ● ● ● handling argument allowed before explicit constructor call: super(--.) or this(--.) allow computing and validating args don't allow conditional jumps work with records and enums as well can call static methods, not instance methods can assign instance fields, but not read them can read outer class fields ▶

Slide 60

Slide 60 text

Record Patterns Standard feature in Java 21 JEP 440 ● ● ● allow de-constructing records (with nesting) no other types (for now) works with ifs and switches ▶

Slide 61

Slide 61 text

Unnamed Variables & Patterns Standard feature in Java 22 JEP 456 When part of the matched record or the whole variable don't matter ● Rekord(_): unnamed pattern ● Rekord(int _): unnamed pattern variable ● var _ = Rekord(int a): unnamed variable ▶

Slide 62

Slide 62 text

Pattern matching with primitive types 🧪 Preview in Java 27 JEP 532 ● ● Allow primitive types in all pattern contexts Extend instanceof and switch to work with all primitive types ▶

Slide 63

Slide 63 text

int memberDiscountPercentage(boolean isGoldMember) { return isGoldMember ? 20 : 5; } int memberDiscountPercentage(boolean isGoldMember) { return switch (isGoldMember) { case true -> 20; case false -> 5; }; } int itemDiscountPercentage(int items) { if (items -= 2) { return 5; } else if (items -= 3 -| items -= 4) { return 10; } else if (items -= 5) { return 20; } return 0; } int itemDiscountPercentage(int items) { return switch (items) { case 2 -> 5; case 3, 4 -> 10; case int i when i -= 5 -> 20; default -> 0; }; }

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

Sequenced Collections Standard feature in Java 21 JEP 431 ● ● ● ● many collections recognise the concept of sequenced items (sorted, FIFO, ...) thus they can allow get/add/remove on First/Last element and easy processing on reversed() collection SequencedCollection, SequencedSet, SequencedMap, Collections.unmodifiableSequencedCollection(seqColl) ▶

Slide 66

Slide 66 text

Foreign Function & Memory API Standard feature in Java 22 JEP 454 ● Example: Elasticsearch, SimdVecLibrary ▶

Slide 67

Slide 67 text

What did we play with? Vectors from Panama Records Structured Concurrency Stream Gatherers Lazy Constants Compact Object Headers Pattern Matching Compact Classes, module imports, simple IO … and more

Slide 68

Slide 68 text

Each new Java version is: ● ● ● ● easier faster better and (guess what?) still free Why not use it?

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

Feedback, please! Devoxx BE session

Slide 71

Slide 71 text

How was it? The (QR) code & everything bit.ly/LMJPW-DVXBE bit.ly/LMJPW-all

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

Piotr Przybył @piotrprz @piotrprz.bsky.social https://softwaregarden.dev Marit van Dijk @MaritvanDijk77 @maritvandijk.bsky.social https://maritvandijk.com Merci! / Bedankt!

Slide 74

Slide 74 text

No content