From fea32723989ee1654e2d2320a2fb2f5c016f040f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Thu, 30 May 2024 18:23:36 +0000 Subject: [PATCH 1/5] Initial examples with Sealed --- README.md | 13 +++-- training/nbproject/project.properties | 0 .../jab/fp/others/FibonacciCalculator.java | 22 +++++++ .../java/info/jab/fp/sealed/AgeProblem.java | 10 ++++ .../info/jab/fp/sealed/AgeProblemExample.java | 20 +++++++ .../main/java/info/jab/fp/sealed/Either.java | 57 +++++++++++++++++++ .../info/jab/fp/sealed/EitherExample.java | 19 +++++++ .../java/info/jab/fp/sealed/EitherTest.java | 23 ++++++++ 8 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 training/nbproject/project.properties create mode 100644 training/src/main/java/info/jab/fp/others/FibonacciCalculator.java create mode 100644 training/src/main/java/info/jab/fp/sealed/AgeProblem.java create mode 100644 training/src/main/java/info/jab/fp/sealed/AgeProblemExample.java create mode 100644 training/src/main/java/info/jab/fp/sealed/Either.java create mode 100644 training/src/main/java/info/jab/fp/sealed/EitherExample.java create mode 100644 training/src/test/java/info/jab/fp/sealed/EitherTest.java diff --git a/README.md b/README.md index 0ab11ec..cebf50b 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,11 @@ sdk env install ## Functional programming features in Java - [x] Lambda Expressions (Functional interfaces, Functions, Supplier, Consumer & Predicates) -- [x] Optional +- [x] [Optional](https://openjdk.org/jeps/401) - [x] Stream API - [x] CompletableFuture & Structural Concurrency -- [ ] Immutable Lists -- [ ] Sealed Classes +- [x] Immutable Lists +- [x] Sealed Classes - [ ] Pattern Matching for Switch - [x] Records & Record Patterns @@ -75,4 +75,9 @@ you can review the performance results: - https://github.com/jabrena/latency-problems - https://github.com/forax/loom-fiber -- https://github.com/forax/we_are_all_to_gather \ No newline at end of file +- https://cr.openjdk.org/~vklang/Gatherers.html +- https://github.com/forax/we_are_all_to_gather +- https://www.infoq.com/articles/data-oriented-programming-java/ +- https://inside.java/2024/05/23/dop-v1-1-introduction/ +- https://inside.java/2024/05/27/dop-v1-1-immutable-transparent-data/ +- https://inside.java/2024/05/29/dop-v1-1-model-data/ diff --git a/training/nbproject/project.properties b/training/nbproject/project.properties new file mode 100644 index 0000000..e69de29 diff --git a/training/src/main/java/info/jab/fp/others/FibonacciCalculator.java b/training/src/main/java/info/jab/fp/others/FibonacciCalculator.java new file mode 100644 index 0000000..ff4fba7 --- /dev/null +++ b/training/src/main/java/info/jab/fp/others/FibonacciCalculator.java @@ -0,0 +1,22 @@ +package info.jab.fp.others; + +import java.util.function.Function; + +public class FibonacciCalculator { + public static void main(String[] args) { + // Define the recursive Fibonacci function using the Function interface + Function fib = new Function<>() { + @Override + public Integer apply(Integer n) { + if (n <= 1) return n; + // Recursive call using this function reference + return this.apply(n - 1) + this.apply(n - 2); + } + }; + + // Calculate Fibonacci numbers + int number = 10; // Example number + int result = fib.apply(number); + System.out.println("Fibonacci number for " + number + " is " + result); + } +} diff --git a/training/src/main/java/info/jab/fp/sealed/AgeProblem.java b/training/src/main/java/info/jab/fp/sealed/AgeProblem.java new file mode 100644 index 0000000..60ce41e --- /dev/null +++ b/training/src/main/java/info/jab/fp/sealed/AgeProblem.java @@ -0,0 +1,10 @@ +package info.jab.fp.sealed; + + +/* +// these are the potential problems +sealed interface AgeProblem { + InvalidAge AgeProblem + NotLegalAdult AgeProblem +} +*/ diff --git a/training/src/main/java/info/jab/fp/sealed/AgeProblemExample.java b/training/src/main/java/info/jab/fp/sealed/AgeProblemExample.java new file mode 100644 index 0000000..27953d3 --- /dev/null +++ b/training/src/main/java/info/jab/fp/sealed/AgeProblemExample.java @@ -0,0 +1,20 @@ +package info.jab.fp.sealed; + +public class AgeProblemExample { + + record Age(Integer age) {} + + /* + // validation returns either problems or the constructed value + public Either validAdult(Integer age) { + if (age < 0) { + //return AgeProblem.InvalidAge.left(); + } else if (age < 18) { + //return AgeProblem.NotLegalAdult.left(); + } else { + return Age(age).right(); + } + } + */ + +} diff --git a/training/src/main/java/info/jab/fp/sealed/Either.java b/training/src/main/java/info/jab/fp/sealed/Either.java new file mode 100644 index 0000000..384f299 --- /dev/null +++ b/training/src/main/java/info/jab/fp/sealed/Either.java @@ -0,0 +1,57 @@ +package info.jab.fp.sealed; + +// Either.java +public sealed interface Either permits Either.Left, Either.Right { + + T fold(java.util.function.Function leftMapper, + java.util.function.Function rightMapper); + + boolean isLeft(); + boolean isRight(); + + static Either left(L value) { + return new Left<>(value); + } + + static Either right(R value) { + return new Right<>(value); + } + + record Left(L value) implements Either { + + @Override + public T fold(java.util.function.Function leftMapper, + java.util.function.Function rightMapper) { + return leftMapper.apply(value); + } + + @Override + public boolean isLeft() { + return true; + } + + @Override + public boolean isRight() { + return false; + } + } + + record Right(R value) implements Either { + + @Override + public T fold(java.util.function.Function leftMapper, + java.util.function.Function rightMapper) { + return rightMapper.apply(value); + } + + @Override + public boolean isLeft() { + return false; + } + + @Override + public boolean isRight() { + return true; + } + } +} diff --git a/training/src/main/java/info/jab/fp/sealed/EitherExample.java b/training/src/main/java/info/jab/fp/sealed/EitherExample.java new file mode 100644 index 0000000..a3fa41e --- /dev/null +++ b/training/src/main/java/info/jab/fp/sealed/EitherExample.java @@ -0,0 +1,19 @@ +package info.jab.fp.sealed; + +import java.util.function.Function; + +public class EitherExample { + public static void main(String[] args) { + Either success = Either.right(42); + Either failure = Either.left("Error occurred"); + + Function, String> resultMapper = either -> + either.fold( + error -> "Failed with error: " + error, + value -> "Success with value: " + value + ); + + System.out.println(resultMapper.apply(success)); // Output: Success with value: 42 + System.out.println(resultMapper.apply(failure)); // Output: Failed with error: Error occurred + } +} diff --git a/training/src/test/java/info/jab/fp/sealed/EitherTest.java b/training/src/test/java/info/jab/fp/sealed/EitherTest.java new file mode 100644 index 0000000..116926e --- /dev/null +++ b/training/src/test/java/info/jab/fp/sealed/EitherTest.java @@ -0,0 +1,23 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/UnitTests/JUnit5TestClass.java to edit this template + */ + +package info.jab.fp.sealed; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class EitherTest { + + @BeforeAll + public static void setUpClass() { + } + + @Test + public void testFold() { + Either success = Either.right(42); + Either failure = Either.left("Error occurred"); + } + +} \ No newline at end of file From 599c0aef220c5e4f73a768bbdc13a8917da7bb0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Thu, 30 May 2024 18:24:52 +0000 Subject: [PATCH 2/5] Initial examples with Sealed --- training/nbproject/project.properties | 0 training/src/test/java/info/jab/fp/sealed/EitherTest.java | 5 ----- 2 files changed, 5 deletions(-) delete mode 100644 training/nbproject/project.properties diff --git a/training/nbproject/project.properties b/training/nbproject/project.properties deleted file mode 100644 index e69de29..0000000 diff --git a/training/src/test/java/info/jab/fp/sealed/EitherTest.java b/training/src/test/java/info/jab/fp/sealed/EitherTest.java index 116926e..da57ef8 100644 --- a/training/src/test/java/info/jab/fp/sealed/EitherTest.java +++ b/training/src/test/java/info/jab/fp/sealed/EitherTest.java @@ -1,8 +1,3 @@ -/* - * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license - * Click nbfs://nbhost/SystemFileSystem/Templates/UnitTests/JUnit5TestClass.java to edit this template - */ - package info.jab.fp.sealed; import org.junit.jupiter.api.BeforeAll; From a1d9ee4ee5eda26073397504f159144549ec4fcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Thu, 30 May 2024 18:26:59 +0000 Subject: [PATCH 3/5] Initial examples with Sealed --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cebf50b..1513053 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ sdk env install ## Functional programming features in Java -- [x] Lambda Expressions (Functional interfaces, Functions, Supplier, Consumer & Predicates) +- [x] [Lambda Expressions](https://openjdk.org/jeps/126) (Functional interfaces, Functions, Supplier, Consumer & Predicates) - [x] [Optional](https://openjdk.org/jeps/401) - [x] Stream API - [x] CompletableFuture & Structural Concurrency From ddb000bcf61b7275de9b590b7909b748a9417246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Fri, 31 May 2024 15:07:20 +0000 Subject: [PATCH 4/5] Better sealed example --- README.md | 6 +- .../java/info/jab/fp/sealed/AgeProblem.java | 10 ---- .../info/jab/fp/sealed/AgeProblemExample.java | 40 +++++++++---- .../java/info/jab/fp/sealed/EnumExample.java | 18 ++++++ .../jab/fp/sealed/AgeProblemExampleTest.java | 60 +++++++++++++++++++ .../java/info/jab/fp/sealed/EitherTest.java | 5 -- 6 files changed, 111 insertions(+), 28 deletions(-) delete mode 100644 training/src/main/java/info/jab/fp/sealed/AgeProblem.java create mode 100644 training/src/main/java/info/jab/fp/sealed/EnumExample.java create mode 100644 training/src/test/java/info/jab/fp/sealed/AgeProblemExampleTest.java diff --git a/README.md b/README.md index 1513053..0ed2ff0 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ A repository to review the main concepts about Functional Programming with Java. sdk env install ./mvnw clean test -DexcludedGroups=performance,endtoend ./mvnw clean test -DexcludedGroups=performance,endtoend -pl training -./mvnw clean test -DexcludedGroups=performance,endtoend -Dtest=LoomExamplesTest -pl training +./mvnw clean test -DexcludedGroups=performance,endtoend -Dtest=AgeProblemExampleTest -pl training ./mvnw clean test -Dgroups=performance ./mvnw clean test -Dgroups=endtoend @@ -31,8 +31,8 @@ sdk env install - [x] Stream API - [x] CompletableFuture & Structural Concurrency - [x] Immutable Lists -- [x] Sealed Classes -- [ ] Pattern Matching for Switch +- [x] [Sealed Classes](https://openjdk.org/jeps/409) +- [x] Pattern Matching for Switch - [x] Records & Record Patterns ## Functional programming timeline in Java diff --git a/training/src/main/java/info/jab/fp/sealed/AgeProblem.java b/training/src/main/java/info/jab/fp/sealed/AgeProblem.java deleted file mode 100644 index 60ce41e..0000000 --- a/training/src/main/java/info/jab/fp/sealed/AgeProblem.java +++ /dev/null @@ -1,10 +0,0 @@ -package info.jab.fp.sealed; - - -/* -// these are the potential problems -sealed interface AgeProblem { - InvalidAge AgeProblem - NotLegalAdult AgeProblem -} -*/ diff --git a/training/src/main/java/info/jab/fp/sealed/AgeProblemExample.java b/training/src/main/java/info/jab/fp/sealed/AgeProblemExample.java index 27953d3..75fb2eb 100644 --- a/training/src/main/java/info/jab/fp/sealed/AgeProblemExample.java +++ b/training/src/main/java/info/jab/fp/sealed/AgeProblemExample.java @@ -3,18 +3,38 @@ public class AgeProblemExample { record Age(Integer age) {} + + // these are the potential problems + sealed interface AgeProblem permits InvalidAge, NotLegalAdult { + String getMessage(); + } + + record InvalidAge() implements AgeProblem { + + @Override + public String getMessage() { + return "Hello"; + } + } - /* - // validation returns either problems or the constructed value - public Either validAdult(Integer age) { - if (age < 0) { - //return AgeProblem.InvalidAge.left(); - } else if (age < 18) { - //return AgeProblem.NotLegalAdult.left(); - } else { - return Age(age).right(); + record NotLegalAdult() implements AgeProblem { + + @Override + public String getMessage() { + return "World"; } } - */ + + //Either problem1 = Either.left(new InvalidAge()); + //Either problem2 = Either.left(new NotLegalAdult()); + //Either success = Either.right(new Age(20)); + + public Either validAdultAge(Integer age) { + return switch (age) { + case Integer a when a < 0 -> Either.left(new InvalidAge()); + case Integer a when a < 18 -> Either.left(new NotLegalAdult()); + default -> Either.right(new Age(age)); + }; + } } diff --git a/training/src/main/java/info/jab/fp/sealed/EnumExample.java b/training/src/main/java/info/jab/fp/sealed/EnumExample.java new file mode 100644 index 0000000..8b0ae93 --- /dev/null +++ b/training/src/main/java/info/jab/fp/sealed/EnumExample.java @@ -0,0 +1,18 @@ +package info.jab.fp.sealed; + +public class EnumExample { + + public static void main() { + + enum Planet { MERCURY, VENUS, EARTH } + + Planet p = Planet.EARTH; + + switch (p) { + case MERCURY -> System.out.println("Mercury"); + case VENUS -> System.out.println("Venus"); + case EARTH -> System.out.println("Earth"); + } + } + +} diff --git a/training/src/test/java/info/jab/fp/sealed/AgeProblemExampleTest.java b/training/src/test/java/info/jab/fp/sealed/AgeProblemExampleTest.java new file mode 100644 index 0000000..e9fe9e9 --- /dev/null +++ b/training/src/test/java/info/jab/fp/sealed/AgeProblemExampleTest.java @@ -0,0 +1,60 @@ +package info.jab.fp.sealed; + +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import info.jab.fp.sealed.AgeProblemExample.Age; +import info.jab.fp.sealed.AgeProblemExample.AgeProblem; +import info.jab.fp.sealed.AgeProblemExample.InvalidAge; +import info.jab.fp.sealed.AgeProblemExample.NotLegalAdult; +import info.jab.utils.TestLoggerExtension; + +@ExtendWith(TestLoggerExtension.class) +public class AgeProblemExampleTest { + + @Test + public void should_notValidate() { + + AgeProblemExample example = new AgeProblemExample(); + + var result = example.validAdultAge(-1); + + assertThat(result).isInstanceOf(Either.class); + assertThat(result.isLeft()).isTrue(); + + var result2 = example.validAdultAge(17); + assertThat(result2).isInstanceOf(Either.class); + assertThat(result2.isLeft()).isTrue(); + + var obj = result2.fold(left -> left, right -> right); + if (obj instanceof AgeProblem) { + AgeProblem ageProblem = (AgeProblem) obj; + if (ageProblem instanceof InvalidAge) { + InvalidAge invalidAge = (InvalidAge) ageProblem; + System.out.println("Handled InvalidAge: " + invalidAge.getMessage()); + } else if (ageProblem instanceof NotLegalAdult) { + NotLegalAdult notLegalAdult = (NotLegalAdult) ageProblem; + System.out.println("Handled NotLegalAdult: " + notLegalAdult.getMessage()); + } + } + } + + @Test + public void should_validate() { + + AgeProblemExample example = new AgeProblemExample(); + + var result = example.validAdultAge(18); + + assertThat(result).isInstanceOf(Either.class); + assertThat(result.isRight()).isTrue(); + + var obj = result.fold(left -> left, right -> right); + if (obj instanceof Age) { + Age age = (Age) obj; + System.out.println("Handled Age: " + age); + } + } + +} \ No newline at end of file diff --git a/training/src/test/java/info/jab/fp/sealed/EitherTest.java b/training/src/test/java/info/jab/fp/sealed/EitherTest.java index da57ef8..e4c6335 100644 --- a/training/src/test/java/info/jab/fp/sealed/EitherTest.java +++ b/training/src/test/java/info/jab/fp/sealed/EitherTest.java @@ -1,14 +1,9 @@ package info.jab.fp.sealed; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; public class EitherTest { - @BeforeAll - public static void setUpClass() { - } - @Test public void testFold() { Either success = Either.right(42); From e761b6afe30a10f705e7cb01a822cac2828200fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Fri, 31 May 2024 15:16:23 +0000 Subject: [PATCH 5/5] Improving examples --- README.md | 31 +++++-------------------------- docs/timeline.md | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 26 deletions(-) create mode 100644 docs/timeline.md diff --git a/README.md b/README.md index 0ed2ff0..72372ec 100644 --- a/README.md +++ b/README.md @@ -28,33 +28,12 @@ sdk env install - [x] [Lambda Expressions](https://openjdk.org/jeps/126) (Functional interfaces, Functions, Supplier, Consumer & Predicates) - [x] [Optional](https://openjdk.org/jeps/401) -- [x] Stream API -- [x] CompletableFuture & Structural Concurrency -- [x] Immutable Lists +- [x] [Stream API](https://openjdk.org/jeps/107) & [Gatherers](https://openjdk.org/jeps/461) +- [x] [CompletableFuture](https://openjdk.org/jeps/266) & [Structural Concurrency](https://openjdk.org/jeps/453) +- [x] [Immutable Lists](https://openjdk.org/jeps/269) - [x] [Sealed Classes](https://openjdk.org/jeps/409) -- [x] Pattern Matching for Switch -- [x] Records & Record Patterns - -## Functional programming timeline in Java - -| Java Version | Feature | Date | Release notes | -|--------------|-------------------------------------------------------------------------------------|-----------|------------------------------------------------------------------------| -| Java 8 | - Lambda Expressions - Optional - Stream API - CompletableFuture | 18/3/2014 | https://www.oracle.com/java/technologies/javase/8-whats-new.html | -| Java 9 | - CompletableFuture updates | 21/9/2017 | https://www.oracle.com/java/technologies/javase/9-all-relnotes.html | -| Java 10 | - Optional updates - Immutable Lists | 20/3/2018 | https://www.oracle.com/java/technologies/javase/10-relnote-issues.html | -| Java 11 | - Not Predicate operator - Local-Variable Syntax for Lambda | 25/9/2018 | https://www.oracle.com/java/technologies/javase/11all-relnotes.html | -| Java 12 | - Teeing Collector - Pattern Matching | 19/3/2019 | https://www.oracle.com/java/technologies/javase/12-relnote-issues.html | -| Java 13 | - Switch Expressions enhancements | 17/9/2019 | https://www.oracle.com/java/technologies/javase/13-relnote-issues.html | -| Java 14 | - Records | 17/3/2020 | https://www.oracle.com/java/technologies/javase/14-relnote-issues.html | -| Java 15 | - Sealed Classes (Preview) | 15/9/2020 | https://www.oracle.com/java/technologies/javase/15-relnote-issues.html | -| Java 16 | - Sealed Classes (Preview) - Stream.toList | 16/3/2021 | https://www.oracle.com/java/technologies/javase/16-relnote-issues.html | -| Java 17 | - Sealed Classes (JEP 409) - Pattern Matching for Switch (JEP 406) (Preview) | 14/9/2021 | https://www.oracle.com/java/technologies/javase/17-relnote-issues.html | -| Java 18 | - Pattern Matching for switch (JEP 420) (Preview) | 22/3/2022 | https://www.oracle.com/java/technologies/javase/18all-relnotes.html | -| Java 19 | - Record Patterns - Pattern Matching for switch (JEP 427) (Preview) | 20/9/2022 | https://www.oracle.com/java/technologies/javase/19-relnote-issues.html | -| Java 20 | - Record Patterns (JEP 432) - Pattern Matching for Switch (JEP 433) (Preview) | 21/3/2023 | https://www.oracle.com/java/technologies/javase/20-relnote-issues.html | -| Java 21 | - Record Patterns (JEP 440) - Pattern Matching for switch (JEP 441) | 19/9/2023 | https://www.oracle.com/java/technologies/javase/21-relnote-issues.html | -| Java 22 | - Stream Gatherers (JEP 461) (Preview) | 19/3/2024 | https://www.oracle.com/java/technologies/javase/22-relnote-issues.html | - +- [x] [Pattern Matching for Switch](https://openjdk.org/jeps/441) +- [x] [Records](https://openjdk.org/jeps/395) & [Record Patterns](https://openjdk.org/jeps/440) ## How to run the presentation in local? diff --git a/docs/timeline.md b/docs/timeline.md new file mode 100644 index 0000000..76e79f7 --- /dev/null +++ b/docs/timeline.md @@ -0,0 +1,20 @@ +## Functional programming timeline in Java + +| Java Version | Feature | Date | Release notes | +|--------------|-------------------------------------------------------------------------------------|-----------|------------------------------------------------------------------------| +| Java 8 | - Lambda Expressions - Optional - Stream API - CompletableFuture | 18/3/2014 | https://www.oracle.com/java/technologies/javase/8-whats-new.html | +| Java 9 | - CompletableFuture updates | 21/9/2017 | https://www.oracle.com/java/technologies/javase/9-all-relnotes.html | +| Java 10 | - Optional updates - Immutable Lists | 20/3/2018 | https://www.oracle.com/java/technologies/javase/10-relnote-issues.html | +| Java 11 | - Not Predicate operator - Local-Variable Syntax for Lambda | 25/9/2018 | https://www.oracle.com/java/technologies/javase/11all-relnotes.html | +| Java 12 | - Teeing Collector - Pattern Matching | 19/3/2019 | https://www.oracle.com/java/technologies/javase/12-relnote-issues.html | +| Java 13 | - Switch Expressions enhancements | 17/9/2019 | https://www.oracle.com/java/technologies/javase/13-relnote-issues.html | +| Java 14 | - Records | 17/3/2020 | https://www.oracle.com/java/technologies/javase/14-relnote-issues.html | +| Java 15 | - Sealed Classes (Preview) | 15/9/2020 | https://www.oracle.com/java/technologies/javase/15-relnote-issues.html | +| Java 16 | - Sealed Classes (Preview) - Stream.toList | 16/3/2021 | https://www.oracle.com/java/technologies/javase/16-relnote-issues.html | +| Java 17 | - Sealed Classes (JEP 409) - Pattern Matching for Switch (JEP 406) (Preview) | 14/9/2021 | https://www.oracle.com/java/technologies/javase/17-relnote-issues.html | +| Java 18 | - Pattern Matching for switch (JEP 420) (Preview) | 22/3/2022 | https://www.oracle.com/java/technologies/javase/18all-relnotes.html | +| Java 19 | - Record Patterns - Pattern Matching for switch (JEP 427) (Preview) | 20/9/2022 | https://www.oracle.com/java/technologies/javase/19-relnote-issues.html | +| Java 20 | - Record Patterns (JEP 432) - Pattern Matching for Switch (JEP 433) (Preview) | 21/3/2023 | https://www.oracle.com/java/technologies/javase/20-relnote-issues.html | +| Java 21 | - Record Patterns (JEP 440) - Pattern Matching for switch (JEP 441) | 19/9/2023 | https://www.oracle.com/java/technologies/javase/21-relnote-issues.html | +| Java 22 | - Stream Gatherers (JEP 461) (Preview) | 19/3/2024 | https://www.oracle.com/java/technologies/javase/22-relnote-issues.html | +