Slide 1

Slide 1 text

Learning modern Java the playful way Marit van Dijk, Piotr Przybył Devoxx PL MMXXV

Slide 2

Slide 2 text

$ who are we Piotr Przybył @piotrprz @piotrprz.bsky.social Senior Developer Advocate Marit van Dijk @MaritvanDijk77 @maritvandijk.bsky.social 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

CAVEAT AVDITORES A.K.A. Safe harbour statement: don't assume anything based on this presentation. Verify on your own. Errare humanum est.

Slide 7

Slide 7 text

How to stay up to date with Java ● Communities, conferences ● Your local JUG: https://dev.java/community/jugs/ and/or the VirtualJUG: https://www.meetup.com/virtualjug/ ● The JEPs: https://openjdk.org/jeps/0 ● Blogs, like: ○ 󰐤 JVM Bloggers: https://jvm-bloggers.com/ ○ IntelliJ IDEA: https://blog.jetbrains.com/idea/ ○ Software Garden: https://softwaregarden.dev/ ○ Inside Java: https://inside.java/ ● and many, many more

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

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

Simple / Compact source files & Instance main methods 🧪 Preview in Java 24 JEP 495 Standard feature in Java 25 JEP 512

Slide 15

Slide 15 text

Simple / Compact source files & Instance main methods public class HelloWorld { public static void main(String[] args) { System.out.println("Witaj Świecie!"); } }

Slide 16

Slide 16 text

Simple / Compact source files & Instance main methods public class HelloWorld { public static void main(String[] args) { System.out.println("Witaj Świecie!"); } }

Slide 17

Slide 17 text

Simple / Compact source files & Instance main methods public class HelloWorld { public static void main(String[] args) { System.out.println("Witaj Świecie!"); } } void main() { println("Witaj Świecie!"); }

Slide 18

Slide 18 text

Preview features --enable-preview JEP 12 ▶

Slide 19

Slide 19 text

DEMO 2: Playing with Java 24

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

“an apple on books” Multimodal encoder

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

final class QueryWithVector { private final String query; private final List vector; QueryWithVector(String query, List vector) { this.query = query; this.vector = vector; } @Override public String toString() { return "QueryWithVector[" + "query=" + query + ", " + "vector=" + vector + ']'; } 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); } } record QueryWithVector(String query, List vector) { @Override public String toString() { return "QueryWithVector[" + "query=" + query + ", " + "vector=" + vector + ']'; } }

Slide 26

Slide 26 text

Module imports 🧪 Preview in Java 24 JEP 494 Standard feature in Java 25 JEP 511 ▶

Slide 27

Slide 27 text

🧪 Preview in Java 24 JEP 495 Standard feature in Java 25 JEP 512 Simple / Compact source files & Instance main methods ▶ Also comes with simple IO

Slide 28

Slide 28 text

Stream Gatherers Standard feature in Java 24 JEP 485

Slide 29

Slide 29 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 30

Slide 30 text

Structured Concurrency 🧪 Preview in Java 24 JEP 499 🧪 Preview in Java 25 JEP 505

Slide 31

Slide 31 text

Structured Concurrency ● better "idioms" for multi-threaded code ● synchronous way of thinking ● help eliminate thread leaks and cancellation delays

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

static SearchResult executeSearch(QueryWithVector qwv, String indexName, ElasticsearchClient esClient) { try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { var knnSearch = scope.fork(() -> performKnnSearch(qwv.vector(), indexName, esClient)); var classicSearch = scope.fork(() -> performClassicSearch(qwv.query(), indexName, esClient)); scope.join(); scope.throwIfFailed(); var combined = combineUsingRRF(List.of(knnSearch.get(), classicSearch.get()), 60, TOP_K); return new SearchResult(qwv.query(), combined); } catch (Exception e) { throw new RuntimeException(); } } static SearchResult executeSearch(QueryWithVector qwv, String indexName, ElasticsearchClient esClient) { try (var scope = StructuredTaskScope.open()) { var knnSearch = scope.fork(() -> performKnnSearch(qwv.vector(), indexName, esClient)); var classicSearch = scope.fork(() -> performClassicSearch(qwv.query(), indexName, esClient)); scope.join(); var combined = combineUsingRRF(List.of(knnSearch.get(), classicSearch.get()), 60, TOP_K); return new SearchResult(qwv.query(), combined); } catch (Exception e) { throw new RuntimeException(); } } Java 24 Java 25

Slide 34

Slide 34 text

TL;DR: .open() with Joiner and Config, can (re)use thread pools, also platform ones Structured Concurrency: Java 24 vs 25 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 35

Slide 35 text

CompletableFuture has no future!

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 Markdown in Java Docs? Shut Up and Take My Comments! https://blog.jetbrains.com/idea/2025/04/markdown-in-java-docs-shut-up-and-take-my-comments/ ▶

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

Pattern matching 🧪 Preview in Java 24 JEP 488 🧪 Preview in Java 25 JEP 507 ● Allow primitive types in all pattern contexts ● Extend instanceof and switch to work with all primitive types ▶

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

Vector API (Panama) 🧫 Incubator in Java 24 JEP 489 🧫 Incubator in Java 25 JEP 508 ▶

Slide 43

Slide 43 text

● API to express vector computations ● Different performance characteristics ▶

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 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 -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Dlog4j2.formatMsgNoLookups=true -Djava.locale.providers=CLDR -Dorg.apache.lucene.vectorization.upperJavaFeatureVersion=24 -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 -Des.entitlements.enabled=true -XX:+EnableDynamicAgentLoading -Djdk.attach.allowAttachSelf=true --patch-module=java.base=lib/entitlement-bridge/elasticsearch-entitlement-bridge-9.0.0.jar --add-exports=java.base/org.elasticsearch.entitlement.bridge=org.elasticsearch.entitlement,java.lo gging,java.net.http,java.naming,jdk.net -XX:+UseG1GC -Djava.io.tmpdir=/tmp/elasticsearch-11578202498973800384 --add-modules=jdk.incubator.vector -Dorg.apache.lucene.store.defaultReadAdvice=normal -XX:+HeapDumpOnOutOfMemoryError -XX:+ExitOnOutOfMemoryError -XX:HeapDumpPath=data -XX:ErrorFile=logs/hs_err_pid%p.log -Xlog:gc*,gc+age=trace,safepoint:file=logs/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 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

How was it? bit.ly/LMJPW-DevoxxPL

Slide 51

Slide 51 text

The (QR) code & everything bit.ly/LMJPW-all

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

Thank you! Bedankt & Dziękuję Piotr Przybył @piotrprz @piotrprz.bsky.social Senior Developer Advocate Marit van Dijk @MaritvanDijk77 @maritvandijk.bsky.social Developer Advocate