├── java-18 ├── .gitignore ├── img │ └── code-snippet-doc-example.png ├── index.html ├── SwitchWithPatternMatchingSecondPreview.java ├── CodeSnippetInJavaDoc.java ├── SimpleWebServer.java └── README.md ├── java-10 ├── build.sh ├── ProcessTest.java ├── CollectionsCopyOf.java ├── StreamToUnmodifiableCollections.java └── README.md ├── java-11 ├── build.sh ├── HttpBinRequestBuilder.java ├── HttpClientBuilderTest.java ├── PipeStreamTest.java ├── GetRequestTest.java ├── PostRequestTest.java ├── GetRequestAsyncTest.java └── GetRequestReactiveTest.java ├── java-9 ├── others-features │ ├── src │ │ └── main │ │ │ └── java │ │ │ ├── module-info.java │ │ │ └── com │ │ │ └── github │ │ │ └── wesleyegberto │ │ │ └── collections │ │ │ ├── collections │ │ │ ├── StreamTest.java │ │ │ └── CollectionsTest.java │ │ │ ├── processapi │ │ │ └── ProcessTest.java │ │ │ ├── httpclient │ │ │ └── HttpClientTest.java │ │ │ └── reactive │ │ │ └── FlowTest.java │ ├── build_run.sh │ └── pom.xml └── modules │ ├── simple_deps │ ├── run_module_calculator.sh │ ├── calculator │ │ ├── module-info.java │ │ └── com │ │ │ └── github │ │ │ └── wesleyegberto │ │ │ └── calculator │ │ │ └── SimpleCalculator.java │ ├── math_api │ │ ├── com │ │ │ └── github │ │ │ │ └── wesleyegberto │ │ │ │ └── mathapi │ │ │ │ └── Operation.java │ │ └── module-info.java │ ├── build_bundle.sh │ ├── run_bundle.sh │ ├── show_deps.sh │ ├── math_lib │ │ ├── com │ │ │ └── github │ │ │ │ └── wesleyegberto │ │ │ │ └── mathlib │ │ │ │ ├── impl │ │ │ │ ├── AdditionOperation.java │ │ │ │ └── SubtractionOperation.java │ │ │ │ └── MathIntegerOperations.java │ │ └── module-info.java │ └── build_modules.sh │ └── services │ ├── consumer │ ├── module-info.java │ └── com │ │ └── github │ │ └── wesleyegberto │ │ └── consumer │ │ └── MadScientist.java │ ├── provider │ ├── com │ │ └── github │ │ │ └── wesleyegberto │ │ │ └── provider │ │ │ ├── Calculator.java │ │ │ └── dadams │ │ │ └── HitchhikerCalculator.java │ └── module-info.java │ └── run_module_service.sh ├── java-19 ├── img │ ├── 2022-06-12-17-50-45.png │ ├── 2022-06-12-17-51-30.png │ ├── 2022-06-12-18-08-57.png │ ├── macos-threads-settings.png │ ├── platform-thread-count.png │ ├── virtual-thread-count.png │ ├── platform-thread-timeline.png │ ├── virtual-thread-timeline.png │ ├── platform-thread-500ms-count.png │ ├── platform-thread-500ms-error.png │ ├── platform-thread-fib-monitor.png │ ├── virtual-thread-fib-monitor.png │ ├── virtual-thread-fib-timeline.png │ ├── platform-thread-fib-timeline.png │ ├── virtual-thread-fibreq-monitor.png │ ├── platform-thread-fibreq-monitor.png │ ├── platform-thread-fibreq-timeline.png │ ├── virtual-thread-fibreq-timeline.png │ ├── webserver-virtual-thread-monitor.png │ ├── webserver-platform-thread-monitor.png │ ├── webserver-platform-thread-response-time.png │ ├── webserver-virtual-thread-jmeter-summary.png │ ├── webserver-virtual-thread-response-time.png │ └── webserver-platform-thread-jmeter-summary.png ├── structured-concurrency-example.md ├── StressPlatformThreadWithFibonacci.java ├── StressVirtualThreadWithFibonacci.java ├── WebServerThreads.java ├── StressPlatformThreadWithFibonacciAndRequest.java ├── StressPlatformThread.java ├── StressVirtualThreadWithFibonacciAndRequest.java ├── StressVirtualThread.java ├── SwitchWithPatternMatchingThirdPreview.java ├── Fibonacci.java └── RecordPatternsTest.java ├── java-23 ├── img │ └── javadoc-markdown-example.png ├── ImplicityDeclaredClassTestIO.java ├── JavaDocMarkdownExample.java ├── FlexibleConstructorBodiesExample.java ├── ScopedValueUsageExample.java └── PrimitiveTypesPatternsTest.java ├── java-25 ├── img │ └── stable-value-comparison-table.png ├── ImplicityDeclaredClassTestIO.java ├── InstanceMainMethodLauncher.java ├── ModuleImportDeclarationsTest.java ├── ImplicityDeclaredClassMainMethodLauncher.java ├── ProfilingTest.java ├── ImplicityDeclaredClassWithAllowedMembers.java ├── FlexibleConstructorBodiesExample.java ├── FlexibleConstructorBodiesInnerClassExample.java ├── StructuredConcurrencyWithScopedValueExample.java ├── StructuredConcurrencyExample.java └── ScopedValueExampleVsThreadLocal.java ├── projects ├── loom │ ├── img │ │ ├── jvm-threads-with-virtual.png │ │ └── jvm-threads-without-virtual.png │ ├── VirtualThreadExecutorTest.java │ ├── VirtualThreadHelloWorld.java │ └── VirtualThreadCountThreads.java └── valhalla │ ├── PrimitiveRecordExample.java │ ├── PrimitiveClassSharingReferencesExample.java │ └── PrimitiveValueNullabilityExample.java ├── java-22 ├── LaunchMultiFileSourceCodeHelper.java ├── LaunchMultiFileSourceCodeProgramMain.java ├── person_validator.c ├── StatementsBeforeSuperExamples.java ├── StatementsBeforeSuperInnerClassExamples.java ├── StreamGatherersBuiltin.java └── StreamGatherersExamples.java ├── .gitignore ├── java-21 ├── InstanceMainMethodLauncher.java ├── UnnamedClassMainMethodLauncher.java ├── UnnamedClassWithAllowedMembers.java ├── StringTemplateCustomProcessorExample.java ├── StructuredConcurrencyWithSubtaskExample.java ├── ScopedValueUsageExample.java ├── StringTemplateExample.java └── RecordPatternTest.java ├── java-12 ├── CompactNumberFormatExample.java ├── CompletableFutureTest.java ├── CollectorsTeeingTest.java ├── README.md └── SwitchExpressionExample.java ├── java-8 ├── src │ └── main │ │ └── java │ │ └── com │ │ └── github │ │ └── wesleyegberto │ │ ├── model │ │ ├── Warrior.java │ │ └── Person.java │ │ ├── reductions │ │ └── SimpleReductions.java │ │ ├── api │ │ ├── base64 │ │ │ ├── Base64Example.java │ │ │ └── UrlEncoderExample.java │ │ ├── objectsvalidation │ │ │ └── ValidationExamples.java │ │ ├── nashorn │ │ │ └── EngineTest.java │ │ └── datetime │ │ │ └── ClockTest.java │ │ ├── map │ │ ├── StreamFilterTest.java │ │ └── StreamMapTest.java │ │ ├── interfaces │ │ ├── DiamondProblem.java │ │ └── InterfaceTest.java │ │ ├── methodreference │ │ └── Type.java │ │ └── lambdas │ │ ├── sideeffects │ │ └── UnnecessaryOne.java │ │ ├── Example_Consumers.java │ │ └── scope │ │ └── ShadowingTest.java └── pom.xml ├── java-24 ├── ModuleImportDeclarationsTest.java ├── ClassFileApiTestTransformedBasicClass.java ├── BasicClass.java ├── SynchronizeVirtualThreadTest.java ├── StreamGatherersBuiltin.java ├── ClassFileApiReadingExample.java ├── StreamGatherersExamples.java ├── ScopedValueUsageExample.java ├── ClassFileApiTransformingExample.java └── ClassFileApiWritingExample.java ├── java-14 ├── PackagingTool.java ├── TextBlocksExample.java ├── HelpfulNPEMessages.java ├── PatternMatchingForInstanceOf.java ├── JFREventStreamTest.java ├── README.md └── RecordsSerializationTest.java ├── java-13 ├── TextBlocksExample.java ├── README.md └── SwitchExpressionTests.java ├── java-15 ├── RecordWithSealedInterface.java ├── SealedTypesExample.java └── README.md ├── java-20 ├── ScopedValueUsageWithReturnValueExample.java ├── PatternMatchingForSwitchFourthPreviewTest.java ├── RecordPatternsSecondPreviewTest.java ├── StructuredConcurrencyWithScopedValue.java ├── ScopedValueUsageExample.java └── ScopedValueExampleVsThreadLocal.java ├── java-7 └── README.md ├── java-16 ├── RecordStaticInnerMemberTest.java ├── SealedTypesExample.java ├── ValueBasedClassWarnings.java ├── UnixDomainSocketTest.java └── README.md ├── java-17 ├── PseudoRandomNumberGeneratorTest.java └── README.md └── java-26 └── PrimitiveTypesPatternsTest.java /java-18/.gitignore: -------------------------------------------------------------------------------- 1 | code-snippets-doc/ -------------------------------------------------------------------------------- /java-10/build.sh: -------------------------------------------------------------------------------- 1 | [[ -f bin ]] && mkdir bin 2 | javac *.java -d ./bin -------------------------------------------------------------------------------- /java-11/build.sh: -------------------------------------------------------------------------------- 1 | [[ -f bin ]] && mkdir bin 2 | javac *.java -d ./bin -------------------------------------------------------------------------------- /java-9/others-features/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module J9NewFeatures { 2 | requires jdk.incubator.httpclient; 3 | } -------------------------------------------------------------------------------- /java-19/img/2022-06-12-17-50-45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/2022-06-12-17-50-45.png -------------------------------------------------------------------------------- /java-19/img/2022-06-12-17-51-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/2022-06-12-17-51-30.png -------------------------------------------------------------------------------- /java-19/img/2022-06-12-18-08-57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/2022-06-12-18-08-57.png -------------------------------------------------------------------------------- /java-19/img/macos-threads-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/macos-threads-settings.png -------------------------------------------------------------------------------- /java-19/img/platform-thread-count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/platform-thread-count.png -------------------------------------------------------------------------------- /java-19/img/virtual-thread-count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/virtual-thread-count.png -------------------------------------------------------------------------------- /java-18/img/code-snippet-doc-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-18/img/code-snippet-doc-example.png -------------------------------------------------------------------------------- /java-19/img/platform-thread-timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/platform-thread-timeline.png -------------------------------------------------------------------------------- /java-19/img/virtual-thread-timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/virtual-thread-timeline.png -------------------------------------------------------------------------------- /java-23/img/javadoc-markdown-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-23/img/javadoc-markdown-example.png -------------------------------------------------------------------------------- /java-19/img/platform-thread-500ms-count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/platform-thread-500ms-count.png -------------------------------------------------------------------------------- /java-19/img/platform-thread-500ms-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/platform-thread-500ms-error.png -------------------------------------------------------------------------------- /java-19/img/platform-thread-fib-monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/platform-thread-fib-monitor.png -------------------------------------------------------------------------------- /java-19/img/virtual-thread-fib-monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/virtual-thread-fib-monitor.png -------------------------------------------------------------------------------- /java-19/img/virtual-thread-fib-timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/virtual-thread-fib-timeline.png -------------------------------------------------------------------------------- /java-19/img/platform-thread-fib-timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/platform-thread-fib-timeline.png -------------------------------------------------------------------------------- /java-19/img/virtual-thread-fibreq-monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/virtual-thread-fibreq-monitor.png -------------------------------------------------------------------------------- /java-25/img/stable-value-comparison-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-25/img/stable-value-comparison-table.png -------------------------------------------------------------------------------- /java-19/img/platform-thread-fibreq-monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/platform-thread-fibreq-monitor.png -------------------------------------------------------------------------------- /java-19/img/platform-thread-fibreq-timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/platform-thread-fibreq-timeline.png -------------------------------------------------------------------------------- /java-19/img/virtual-thread-fibreq-timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/virtual-thread-fibreq-timeline.png -------------------------------------------------------------------------------- /java-19/img/webserver-virtual-thread-monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/webserver-virtual-thread-monitor.png -------------------------------------------------------------------------------- /projects/loom/img/jvm-threads-with-virtual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/projects/loom/img/jvm-threads-with-virtual.png -------------------------------------------------------------------------------- /java-19/img/webserver-platform-thread-monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/webserver-platform-thread-monitor.png -------------------------------------------------------------------------------- /projects/loom/img/jvm-threads-without-virtual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/projects/loom/img/jvm-threads-without-virtual.png -------------------------------------------------------------------------------- /java-19/img/webserver-platform-thread-response-time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/webserver-platform-thread-response-time.png -------------------------------------------------------------------------------- /java-19/img/webserver-virtual-thread-jmeter-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/webserver-virtual-thread-jmeter-summary.png -------------------------------------------------------------------------------- /java-19/img/webserver-virtual-thread-response-time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/webserver-virtual-thread-response-time.png -------------------------------------------------------------------------------- /java-19/img/webserver-platform-thread-jmeter-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesleyegberto/java-new-features/HEAD/java-19/img/webserver-platform-thread-jmeter-summary.png -------------------------------------------------------------------------------- /java-9/modules/simple_deps/run_module_calculator.sh: -------------------------------------------------------------------------------- 1 | # To run we need to specify the modules path and the entry module name 2 | $JAVA9_HOME/bin/java -p output/mlibs -m simplecalculator -------------------------------------------------------------------------------- /java-9/modules/services/consumer/module-info.java: -------------------------------------------------------------------------------- 1 | 2 | module consumer { 3 | requires provider; 4 | // declares the use of the services 5 | uses com.github.wesleyegberto.provider.Calculator; 6 | } -------------------------------------------------------------------------------- /java-9/modules/services/provider/com/github/wesleyegberto/provider/Calculator.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.provider; 2 | 3 | public interface Calculator { 4 | int calculateUniverseMeaning(); 5 | } -------------------------------------------------------------------------------- /java-23/ImplicityDeclaredClassTestIO.java: -------------------------------------------------------------------------------- 1 | 2 | void main() { 3 | // java.io.IO.readln 4 | String name = readln("Enter your name: "); 5 | 6 | // java.io.IO.println 7 | println("Hello " + name + "!"); 8 | } 9 | -------------------------------------------------------------------------------- /java-25/ImplicityDeclaredClassTestIO.java: -------------------------------------------------------------------------------- 1 | 2 | void main() { 3 | // java.io.IO.readln 4 | String name = IO.readln("Enter your name: "); 5 | 6 | // java.io.IO.println 7 | IO.println("Hello " + name + "!"); 8 | } 9 | -------------------------------------------------------------------------------- /java-25/InstanceMainMethodLauncher.java: -------------------------------------------------------------------------------- 1 | /** 2 | * To run: `java InstanceMainMethodLauncher.java` 3 | */ 4 | class InstanceMainMethodLauncher { 5 | void main() { 6 | System.out.println("Hello world from an instance main method o/"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /java-22/LaunchMultiFileSourceCodeHelper.java: -------------------------------------------------------------------------------- 1 | public class LaunchMultiFileSourceCodeHelper { 2 | static { 3 | System.out.println("LaunchMultiFileHelper static initializer"); 4 | } 5 | 6 | public static int generateValue() { 7 | return 42; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /java-9/modules/simple_deps/calculator/module-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This file defines the module. 3 | * We can define the modules it requires and the packages it exports. 4 | */ 5 | module simplecalculator { 6 | // should be included in the modules path using -p flag 7 | requires mathlib; 8 | } 9 | -------------------------------------------------------------------------------- /java-9/modules/simple_deps/math_api/com/github/wesleyegberto/mathapi/Operation.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.mathapi; 2 | 3 | /** 4 | * with exported public interface 5 | * we can access a non-exported class 6 | */ 7 | public interface Operation { 8 | public T apply(E x, E y); 9 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | .classpath 3 | .project 4 | .settings/ 5 | .metadata/ 6 | .idea/ 7 | target/ 8 | output/ 9 | bin/ 10 | *.jar 11 | *.war 12 | *.ear 13 | *.iml 14 | hs_err_pid* 15 | .vscode/ 16 | .DS_Store 17 | *.data 18 | jdt.ls-java-project/ 19 | *.dmg 20 | *.so 21 | *.aotconf 22 | *.aot 23 | -------------------------------------------------------------------------------- /java-21/InstanceMainMethodLauncher.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Using JDK manually built from main branch. 3 | * 4 | * To run: `java --enable-preview --source 21 InstanceMainMethodLauncher.java` 5 | */ 6 | class InstanceMainMethodLauncher { 7 | void main() { 8 | System.out.println("Hello world from an instance main method o/"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /java-9/modules/simple_deps/build_bundle.sh: -------------------------------------------------------------------------------- 1 | # we must set --module-path to JDK modules and our own modules 2 | $JAVA9_HOME/bin/jlink --module-path $JAVA9_HOME/jmods:output/mlibs \ 3 | --add-modules simplecalculator \ 4 | --launcher simplecalculator=simplecalculator/com.github.wesleyegberto.calculator.SimpleCalculator \ 5 | --output output/simplecalculator -------------------------------------------------------------------------------- /java-9/modules/simple_deps/math_api/module-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This file defines the module. 3 | * We can define the modules it requires and the packages it exports. 4 | */ 5 | module mathapi { 6 | // requires java.base // default import 7 | 8 | // export any public class (visibility) 9 | exports com.github.wesleyegberto.mathapi; 10 | } 11 | -------------------------------------------------------------------------------- /java-18/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Simple Web Server 8 | 9 | 10 | Hello world from Simple Web Server! 11 | 12 | -------------------------------------------------------------------------------- /java-9/modules/services/provider/com/github/wesleyegberto/provider/dadams/HitchhikerCalculator.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.provider.dadams; 2 | 3 | import com.github.wesleyegberto.provider.Calculator; 4 | 5 | public class HitchhikerCalculator implements Calculator { 6 | public int calculateUniverseMeaning() { 7 | return 42; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /java-9/modules/simple_deps/run_bundle.sh: -------------------------------------------------------------------------------- 1 | # listing the modules 2 | echo "Modules in the bundle:" 3 | ./output/simplecalculator/bin/java --list-modules 4 | 5 | # To run we use the java bin generated passing the module to run 6 | ./output/simplecalculator/bin/java -m simplecalculator 7 | 8 | # running the generated script 9 | ./output/simplecalculator/bin/simplecalculator -------------------------------------------------------------------------------- /java-10/ProcessTest.java: -------------------------------------------------------------------------------- 1 | import java.lang.management.ManagementFactory; 2 | import java.lang.management.RuntimeMXBean; 3 | 4 | public class ProcessTest { 5 | public static void main(String[] args) { 6 | final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); 7 | final long pid = runtime.getPid(); 8 | System.out.println("Process ID is: " + pid); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /java-9/modules/simple_deps/show_deps.sh: -------------------------------------------------------------------------------- 1 | echo "MathApi deps:" 2 | $JAVA9_HOME/bin/jdeps output/mlibs/mathapi-1.0.jar 3 | 4 | echo "\nMathLib deps:" 5 | # we need to set modules path if a module use any other define 6 | $JAVA9_HOME/bin/jdeps --module-path output/mlibs/ output/mlibs/mathlib-1.0.jar 7 | 8 | echo "\nCalculator deps:" 9 | $JAVA9_HOME/bin/jdeps --module-path output/mlibs/ output/mlibs/calculator.jar -------------------------------------------------------------------------------- /java-9/modules/services/provider/module-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Define the module which provides the service. 3 | */ 4 | module provider { 5 | // exports the interface 6 | exports com.github.wesleyegberto.provider; 7 | // define the implementation for the interface 8 | provides com.github.wesleyegberto.provider.Calculator 9 | with com.github.wesleyegberto.provider.dadams.HitchhikerCalculator; 10 | } -------------------------------------------------------------------------------- /java-11/HttpBinRequestBuilder.java: -------------------------------------------------------------------------------- 1 | import java.net.URI; 2 | import java.net.http.HttpRequest; 3 | 4 | public class HttpBinRequestBuilder { 5 | public static HttpRequest createGetRequest() { 6 | // HttpRequest is immutable 7 | return HttpRequest.newBuilder() 8 | .GET() 9 | .uri(URI.create("http://httpbin.org/get")) 10 | .header("Accept-Language", "en-US,en;q=0.5") 11 | .build(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /java-12/CompactNumberFormatExample.java: -------------------------------------------------------------------------------- 1 | import java.text.*; 2 | import java.util.Locale; 3 | 4 | public class CompactNumberFormatExample { 5 | public static void main(String[] args) { 6 | NumberFormat followers = NumberFormat.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.SHORT); 7 | followers.setMaximumFractionDigits(1); 8 | System.out.println(followers.format(5412) + " followers"); 9 | } 10 | } -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/model/Warrior.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.model; 2 | 3 | public class Warrior { 4 | private Person person; 5 | private String type; 6 | 7 | public Warrior(Person person) { 8 | this.person = person; 9 | type = "Warrior " + person.getAge(); 10 | } 11 | 12 | public String getType() { 13 | return type; 14 | } 15 | 16 | public String toString() { 17 | return type; 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /java-25/ModuleImportDeclarationsTest.java: -------------------------------------------------------------------------------- 1 | import module java.base; 2 | import module java.sql; 3 | import module java.desktop; 4 | 5 | import java.util.*; // prioritize List 6 | import java.util.Date; 7 | 8 | /** 9 | * Run: `java ModuleImportDeclarationsTest.java` 10 | */ 11 | public class ModuleImportDeclarationsTest { 12 | public static void main(String[] args) { 13 | Date date = new Date(); 14 | 15 | List l = new ArrayList(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /java-24/ModuleImportDeclarationsTest.java: -------------------------------------------------------------------------------- 1 | import module java.base; 2 | import module java.sql; 3 | import module java.desktop; 4 | 5 | import java.util.*; // prioritize List 6 | import java.util.Date; 7 | 8 | /** 9 | * Run: `java --source 24 --enable-preview ModuleImportDeclarationsTest.java` 10 | */ 11 | public class ModuleImportDeclarationsTest { 12 | public static void main(String[] args) { 13 | Date date = new Date(); 14 | 15 | List l = new ArrayList(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /java-19/structured-concurrency-example.md: -------------------------------------------------------------------------------- 1 | # Example of Structured Concurrency 2 | 3 | The output that we can see that the `StructuredTaskScope` canceled other subtask (throwing a `InterruptedException`): 4 | 5 | ![](img/2022-06-12-18-08-57.png) 6 | 7 | Thread view of concurrency using `ExecutorService`: 8 | 9 | ![](img/2022-06-12-17-50-45.png) 10 | 11 | Thread view of concurency using `StructuredTaskScope`: 12 | 13 | ![](img/2022-06-12-17-51-30.png) 14 | 15 | We can not the virtual thread running with ForkJoinPool. 16 | -------------------------------------------------------------------------------- /java-11/HttpClientBuilderTest.java: -------------------------------------------------------------------------------- 1 | import java.net.http.HttpClient; 2 | import java.time.Duration; 3 | 4 | public class HttpClientBuilderTest { 5 | public static HttpClient createHttpClient() { 6 | // The client is immutable =) 7 | return HttpClient.newBuilder() 8 | .version(HttpClient.Version.HTTP_2) // default value 9 | .connectTimeout(Duration.ofSeconds(3)) 10 | .followRedirects(HttpClient.Redirect.NORMAL) 11 | .build(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /java-24/ClassFileApiTestTransformedBasicClass.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Used in Class File API transforming example. 3 | */ 4 | public class ClassFileApiTestTransformedBasicClass { 5 | public static void main(String[] args) { 6 | System.out.println("Using the transformed BasicClass"); 7 | var obj = new BasicClass("The next arg will not be returned", 10203040, true); 8 | // won't exists after transformation 9 | // obj.setTimestamp(123); 10 | System.out.println("Return of getTimestamp: " + obj.getTimestamp()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /java-9/modules/simple_deps/math_lib/com/github/wesleyegberto/mathlib/impl/AdditionOperation.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.mathlib.impl; 2 | 3 | import com.github.wesleyegberto.mathapi.Operation; 4 | import com.github.wesleyegberto.mathlib.*; 5 | 6 | /** 7 | * This implementation we won't export, but we can access it 8 | * through its interface - Operation 9 | */ 10 | public class AdditionOperation implements Operation { 11 | public Integer apply(Integer x, Integer y) { 12 | return x + y; 13 | } 14 | } -------------------------------------------------------------------------------- /java-9/modules/simple_deps/math_lib/com/github/wesleyegberto/mathlib/impl/SubtractionOperation.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.mathlib.impl; 2 | 3 | import com.github.wesleyegberto.mathapi.Operation; 4 | import com.github.wesleyegberto.mathlib.*; 5 | /** 6 | * This implementation we won't export, but we can access it 7 | * through its interface - Operation 8 | */ 9 | public class SubtractionOperation implements Operation { 10 | public Integer apply(Integer x, Integer y) { 11 | return x - y; 12 | } 13 | } -------------------------------------------------------------------------------- /java-9/modules/simple_deps/math_lib/module-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This file defines the module. 3 | * We can define the modules it requires and the packages it exports. 4 | */ 5 | module mathlib { 6 | // requires java.base // default import 7 | 8 | // use transitive to also "export" a dependency 9 | // thus we won't need to import mathapi in the clients 10 | requires transitive mathapi; 11 | 12 | // export any public class (visibility) 13 | exports com.github.wesleyegberto.mathlib; 14 | // subpackages won't be exported 15 | 16 | } 17 | -------------------------------------------------------------------------------- /java-9/others-features/build_run.sh: -------------------------------------------------------------------------------- 1 | rm -rf target 2 | 3 | CLASSES_DIR="target/classes" 4 | JAR_DIR="target/jars" 5 | 6 | mkdir -p $CLASSES_DIR 7 | mkdir -p $JAR_DIR 8 | 9 | $JAVA9_HOME/bin/javac -p jdk.incubator.httpclient -d $CLASSES_DIR --module-version 1.0 `find src/main/java -name *.java` 10 | 11 | # --main-class HttpClientTest \ 12 | $JAVA9_HOME/bin/jar -c -f $JAR_DIR/http-client-test.jar \ 13 | --main-class CollectionsCopyOf.CollectionsTest \ 14 | -C $CLASSES_DIR . 15 | 16 | 17 | $JAVA9_HOME/bin/java -p $JAR_DIR -m J9NewFeatures -------------------------------------------------------------------------------- /java-22/LaunchMultiFileSourceCodeProgramMain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To run: `java --enable-preview --source 22 LaunchMultiFileSourceCodeProgramMain.java` 3 | */ 4 | public class LaunchMultiFileSourceCodeProgramMain { 5 | static { 6 | System.out.println("LaunchMultiFileSourceCodeProgramMain static initializer"); 7 | } 8 | 9 | void main() { 10 | System.out.println("Here the launcher will compile and load the other Java file"); 11 | var value = LaunchMultiFileSourceCodeHelper.generateValue(); 12 | System.out.println("Value: " + value); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /java-12/CompletableFutureTest.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.*; 2 | 3 | public class CompletableFutureTest { 4 | public static void main(String[] args) { 5 | CompletableFuture.runAsync(CompletableFutureTest::workMethod) 6 | .exceptionallyCompose(ex -> { 7 | return CompletableFuture.runAsync(() -> System.out.println("Got some error but now I can keep going")); 8 | }); 9 | 10 | try { 11 | Thread.sleep(1000); 12 | } catch (InterruptedException ex) {} 13 | } 14 | 15 | public static void workMethod() { 16 | System.out.println("Working..."); 17 | throw new IllegalStateException(); 18 | } 19 | } -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/reductions/SimpleReductions.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.reductions; 2 | 3 | import java.util.stream.IntStream; 4 | 5 | /** 6 | * @author Wesley Egberto 7 | */ 8 | public class SimpleReductions { 9 | public static void main(String[] args) { 10 | int result = IntStream.range(0, 100).filter(n -> n % 2 == 0).reduce(0, Integer::sum); 11 | System.out.println("Sum of odd numbers: " + result); 12 | 13 | int powResult = IntStream.range(0, 100).map(x -> x * x).reduce(0, Integer::sum); 14 | System.out.println("Sum of powed numbers: " + powResult); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /java-9/modules/simple_deps/math_lib/com/github/wesleyegberto/mathlib/MathIntegerOperations.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.mathlib; 2 | 3 | import com.github.wesleyegberto.mathapi.Operation; 4 | import com.github.wesleyegberto.mathlib.impl.*; 5 | 6 | /** 7 | * We can expose our implementation using an exported public interface 8 | */ 9 | public class MathIntegerOperations { 10 | public Operation getAdditionOperation() { 11 | return new AdditionOperation(); 12 | } 13 | 14 | public Operation getSubtractionOperation() { 15 | return new SubtractionOperation(); 16 | } 17 | } -------------------------------------------------------------------------------- /java-25/ImplicityDeclaredClassMainMethodLauncher.java: -------------------------------------------------------------------------------- 1 | /** 2 | * To run: `java ImplicityDeclaredClassMainMethodLauncher.java` 3 | */ 4 | void main() { 5 | System.out.println("Hello world from a implicity declared class with a main method o/"); 6 | } 7 | 8 | /** 9 | To see the generated class: 10 | - `javac ImplicityDeclaredClassMainMethodLauncher.java` 11 | - `javap ImplicityDeclaredClassMainMethodLauncher` 12 | 13 | Output: 14 | 15 | ``` 16 | Compiled from "ImplicityDeclaredClassMainMethodLauncher.java" 17 | final class ImplicityDeclaredClassMainMethodLauncher { 18 | ImplicityDeclaredClassMainMethodLauncher(); 19 | void main(); 20 | } 21 | ``` 22 | */ 23 | -------------------------------------------------------------------------------- /java-11/PipeStreamTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.api.io; 2 | 3 | import java.io.*; 4 | 5 | public class PipeStreamTest { 6 | public static void main(String[] args) throws Exception { 7 | var writer = new StringWriter(); 8 | var inputPipe = new PipedInputStream(); 9 | var inputBuffed = new BufferedInputStream(inputPipe); 10 | 11 | var outputPipe = new PipedOutputStream(inputPipe); 12 | var outputBuffered = new BufferedOutputStream(outputPipe); 13 | 14 | var w = new PrintWriter(outputBuffered); 15 | w.write("Hello Bug"); 16 | w.flush(); 17 | w.close(); 18 | 19 | System.out.println(new String(inputBuffed.readAllBytes())); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/api/base64/Base64Example.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.api.base64; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | import java.util.Base64; 5 | 6 | /** 7 | * @author Wesley Egberto 8 | */ 9 | public class Base64Example { 10 | public static void main(String[] args) { 11 | final String text = "Base64 finally in Java 8!"; 12 | final String encoded = Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8)); 13 | System.out.println(encoded); 14 | final String decoded = new String(Base64.getDecoder().decode(encoded), StandardCharsets.UTF_8); 15 | System.out.println(decoded); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /java-19/StressPlatformThreadWithFibonacci.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.Executors; 2 | import java.util.stream.IntStream; 3 | 4 | /** 5 | * Run: 6 | * - `javac Fibonacci.java` 7 | * - `java --enable-preview --source 19 ` 8 | */ 9 | public class StressPlatformThreadWithFibonacci { 10 | public static void main(String[] args) { 11 | var executor = Executors.newCachedThreadPool(); 12 | 13 | IntStream.range(0, 50).forEach(i -> { 14 | executor.submit(() -> { 15 | Fibonacci.parallelFib(47, executor) 16 | .thenAccept(result -> { 17 | System.out.printf("Platform Thread %d - %d%n", i, result); 18 | }); 19 | }); 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /java-9/modules/simple_deps/calculator/com/github/wesleyegberto/calculator/SimpleCalculator.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.calculator; 2 | 3 | // must be public and exported (in the module-info.java) 4 | import com.github.wesleyegberto.mathapi.*; 5 | import com.github.wesleyegberto.mathlib.*; 6 | 7 | public class SimpleCalculator { 8 | public static void main(String[] args) { 9 | MathIntegerOperations math = new MathIntegerOperations(); 10 | System.out.println(math); 11 | 12 | Operation add = math.getAdditionOperation(); 13 | System.out.println(add); 14 | 15 | Integer result = add.apply(2, 5); 16 | System.out.println(result); 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /java-21/UnnamedClassMainMethodLauncher.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Using JDK manually built from main branch. 3 | * 4 | * To run: `java --enable-preview --source 21 UnnamedClassMainMethodLauncher.java` 5 | */ 6 | void main() { 7 | System.out.println("Hello world from a unnamed class with a main method o/"); 8 | } 9 | 10 | /** 11 | To see the generated class: 12 | - `javac --enable-preview --source 21 UnnamedClassMainMethodLauncher.java` 13 | - `javap UnnamedClassMainMethodLauncher` 14 | 15 | Output: 16 | 17 | ``` 18 | Compiled from "UnnamedClassMainMethodLauncher.java" 19 | final class UnnamedClassMainMethodLauncher { 20 | UnnamedClassMainMethodLauncher(); 21 | void main(); 22 | } 23 | ``` 24 | */ 25 | -------------------------------------------------------------------------------- /java-22/person_validator.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Compile: `gcc -shared -o libpersonvalidator.so -I $(pwd) person_validator.c` 3 | */ 4 | #include 5 | 6 | struct Person { 7 | char* name; 8 | short age; 9 | }; 10 | 11 | char* validate_person(struct Person* person) { 12 | if (person == NULL) { 13 | return "Invalid person (null)"; 14 | } 15 | if (person->name == NULL) { 16 | return "Invalid name (null)"; 17 | } 18 | if (strlen(person->name) < 1) { 19 | return "Invalid name (empty)"; 20 | } 21 | if (person->age < 1 || person->age > 150) { 22 | return "Invalid age"; 23 | } 24 | if (person->age < 18) { 25 | return "Person is too young"; 26 | } 27 | return "Person is valid"; 28 | } 29 | -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/api/base64/UrlEncoderExample.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.api.base64; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | import java.util.Base64; 5 | 6 | /** 7 | * @author Wesley Egberto 8 | */ 9 | public class UrlEncoderExample { 10 | public static void main(String[] args) { 11 | String url = "http://github.com/wesleyegberto"; 12 | String encodedUrl = Base64.getUrlEncoder().encodeToString(url.getBytes(StandardCharsets.UTF_8)); 13 | String Decoded = new String(Base64.getUrlDecoder().decode(encodedUrl), StandardCharsets.UTF_8); 14 | System.out.println("encodedUrl = " + encodedUrl); 15 | System.out.println("decodedUrl = "+ Decoded); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/api/objectsvalidation/ValidationExamples.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.api.objectsvalidation; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * @author Wesley Egberto 7 | */ 8 | public class ValidationExamples { 9 | 10 | public static void doFoo(String aVar) { 11 | // will throw a NPE with the given message 12 | Objects.requireNonNull(aVar, "Got a null argument"); 13 | 14 | System.out.println("Requires non-null: " + aVar); 15 | } 16 | 17 | public static void doBar(String anotherVar) { 18 | if(Objects.isNull(anotherVar)) 19 | System.out.println("Got a null"); 20 | else 21 | System.out.println("Got a non-null: " + anotherVar); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/map/StreamFilterTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.map; 2 | 3 | import com.github.wesleyegberto.model.Person; 4 | 5 | import java.util.*; 6 | import java.util.stream.Stream; 7 | 8 | public class StreamFilterTest { 9 | 10 | public static void main(String[] args) { 11 | List persons = Person.getList(); 12 | 13 | // get the stream (sequential version) to apply the filter operation 14 | Stream personsStream = persons.stream(); 15 | 16 | // apply the filter 17 | Stream personsFilters = personsStream.filter(p -> p.getAge() >= 18); 18 | System.out.println("Persons filtered:"); 19 | personsFilters.forEach((p) -> System.out.println(p)); 20 | } 21 | } -------------------------------------------------------------------------------- /java-11/GetRequestTest.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | import java.net.http.HttpClient; 3 | import java.net.http.HttpRequest; 4 | import java.net.http.HttpResponse; 5 | import java.net.http.HttpResponse.BodyHandlers; 6 | 7 | public class GetRequestTest { 8 | public static void main(String[] args) throws IOException, InterruptedException { 9 | HttpRequest request = HttpBinRequestBuilder.createGetRequest(); 10 | 11 | HttpClient httpClient = HttpClientBuilderTest.createHttpClient(); 12 | // HttpClient#send is blocking; the body is kept in memory to be processed 13 | HttpResponse httpResponse = httpClient.send(request, BodyHandlers.ofString()); 14 | System.out.println("Response: " + httpResponse.body()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /java-10/CollectionsCopyOf.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.List; 3 | import java.util.Map; 4 | import java.util.Set; 5 | 6 | public class CollectionsCopyOf { 7 | public static void main(String[] args) { 8 | List muttableList = Arrays.asList("New", "Method", "To", "Copy"); 9 | 10 | // Copy methods 11 | List immutableList = List.copyOf(muttableList); 12 | immutableList.forEach(System.out::println); 13 | 14 | Set immutableSet = Set.copyOf(muttableList); 15 | immutableSet.forEach(System.out::println); 16 | 17 | Map immutableMap = Map.copyOf(Map.of("k1", "v1", "k2", "v2")); 18 | immutableMap.forEach((key, value) -> System.out.println(key + " = " + value)); 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /java-9/modules/services/consumer/com/github/wesleyegberto/consumer/MadScientist.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.consumer; 2 | 3 | import java.util.Iterator; 4 | import java.util.ServiceLoader; 5 | import com.github.wesleyegberto.provider.Calculator; 6 | 7 | public class MadScientist { 8 | private static Calculator getImplementation() { 9 | Iterator impls = ServiceLoader.load(Calculator.class).iterator(); 10 | if (impls.hasNext()) return impls.next(); 11 | throw new RuntimeException("No implementation provided."); 12 | } 13 | 14 | public static void main(String[] args) { 15 | Calculator calculator = getImplementation(); 16 | System.out.println("Universe meaning: " + calculator.calculateUniverseMeaning()); 17 | } 18 | } -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/api/nashorn/EngineTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.api.nashorn; 2 | 3 | import javax.script.ScriptEngine; 4 | import javax.script.ScriptEngineManager; 5 | import javax.script.ScriptException; 6 | 7 | /** 8 | * @author Wesley Egberto 9 | */ 10 | public class EngineTest { 11 | public static void main(String[] args) { 12 | ScriptEngineManager manager = new ScriptEngineManager(); 13 | ScriptEngine engine = manager.getEngineByName("JavaScript"); 14 | System.out.println(engine.getClass().getName()); 15 | try { 16 | System.out.println("Result: " + engine.eval("funsction f() { return 1; }; f() + 1;")); 17 | } catch (ScriptException e) { 18 | e.printStackTrace(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/interfaces/DiamondProblem.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.interfaces; 2 | 3 | public class DiamondProblem { 4 | public static void main(String[] args) { 5 | new TooMuch().walk(); 6 | } 7 | } 8 | 9 | /* 10 | * When the interfaces that we are implementing has 11 | * the same methods signatures then we must override them. 12 | */ 13 | class TooMuch implements Father, Mother { 14 | public void walk() { 15 | System.out.println("Walking like myself"); 16 | } 17 | } 18 | 19 | interface Father { 20 | default void walk() { 21 | System.out.println("Walking like the father"); 22 | } 23 | } 24 | 25 | interface Mother { 26 | default void walk() { 27 | System.out.println("Walking like the mother"); 28 | } 29 | } -------------------------------------------------------------------------------- /java-19/StressVirtualThreadWithFibonacci.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.Executors; 2 | import java.util.stream.IntStream; 3 | 4 | /** 5 | * Run: 6 | * - `javac Fibonacci.java` 7 | * - `java --enable-preview --source 19 ` 8 | */ 9 | public class StressVirtualThreadWithFibonacci { 10 | public static void main(String[] args) { 11 | var executor = Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory()); 12 | 13 | IntStream.range(0, 50).forEach(i -> { 14 | executor.submit(() -> { 15 | Fibonacci.parallelFib(47, executor) 16 | .thenAccept(result -> { 17 | System.out.printf("Virtual Thread %d - %d%n", i, result); 18 | }); 19 | }); 20 | }); 21 | 22 | while (!executor.isTerminated()) { 23 | ; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /projects/valhalla/PrimitiveRecordExample.java: -------------------------------------------------------------------------------- 1 | /** 2 | * To run: `javac -XDenablePrimitiveClasses --source 20 --target 20 PrimitiveRecordExample.java && java -XX:+EnablePrimitiveClasses PrimitiveRecordExample` 3 | */ 4 | public class PrimitiveRecordExample { 5 | public static void main(String[] args) { 6 | var p1 = new Point(10, 10); 7 | Point.ref p2 = p1; 8 | 9 | System.out.println("Is default value equals to new instancee with 0s? " + (new Point(0, 0) == Point.default)); 10 | System.out.println("Are two new instance with same components equals? " + (new Point(42, 42) == new Point(42, 42))); 11 | } 12 | } 13 | 14 | primitive record Point(int x, int y) {} 15 | 16 | // still using value keyword from early version 17 | primitive record A() {} 18 | value record B() {} 19 | -------------------------------------------------------------------------------- /java-10/StreamToUnmodifiableCollections.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | import java.util.Map; 3 | import java.util.function.Function; 4 | import java.util.stream.Collectors; 5 | 6 | public class StreamToUnmodifiableCollections { 7 | public static void main(String[] args) { 8 | List list = List.of("Testing", "Immutable", "List", "From", "Stream"); 9 | 10 | List immutableList = list.stream() 11 | .collect(Collectors.toUnmodifiableList()); 12 | immutableList.forEach(System.out::println); 13 | 14 | Map wordsLengths = list.stream() 15 | .collect(Collectors.toUnmodifiableMap(Function.identity(), word -> word.length())); 16 | wordsLengths.forEach((word, length) -> System.out.println(word + " -> " + length + " letters")); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /java-14/PackagingTool.java: -------------------------------------------------------------------------------- 1 | import javax.swing.JOptionPane; 2 | 3 | /** 4 | * Steps: 5 | * 6 | * - compile: `javac PackagingTool.java` 7 | * - create JAR: `jar -cfe packaging-tool-example.jar PackagingTool PackagingTool.class` 8 | * - test JAR: `java -jar packaging-tool-example.jar` 9 | * - create the Package: `jpackage --name pack-tool-sample --input . --main-jar packaging-tool-example.jar --main-class PackagingTool` 10 | * 11 | * Package will generate: 12 | * - `dmg` on macOS 13 | * - `msi` on Windows 14 | * - `app` on Linux 15 | */ 16 | public class PackagingTool { 17 | public static void main(String[] args) { 18 | System.out.println("Main =)"); 19 | JOptionPane.showMessageDialog(null, "Hello world from self-contained application", null, 20 | JOptionPane.INFORMATION_MESSAGE); 21 | } 22 | } -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/methodreference/Type.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.methodreference; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.function.Supplier; 6 | 7 | /** 8 | * @author Wesley Egberto 9 | */ 10 | public class Type { 11 | public static Type create(Supplier supplier) { 12 | return supplier.get(); 13 | } 14 | 15 | public void printModel() { 16 | System.out.println(hashCode()); 17 | } 18 | 19 | public static void test(Type t) { 20 | System.out.println(t.toString()); 21 | } 22 | 23 | public static void main(String[] args) { 24 | Type t1 = Type.create(Type::new); 25 | 26 | List list = Arrays.asList(t1); 27 | 28 | list.forEach(Type::printModel); 29 | 30 | list.forEach(Type::test); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /java-11/PostRequestTest.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | import java.net.URI; 3 | import java.net.http.HttpClient; 4 | import java.net.http.HttpRequest; 5 | import java.net.http.HttpResponse; 6 | 7 | import static java.net.http.HttpRequest.*; 8 | 9 | public class PostRequestTest { 10 | public static void main(String[] args) throws IOException, InterruptedException { 11 | BodyPublisher body = BodyPublishers.ofString("{'id':1}"); 12 | HttpRequest request = newBuilder() 13 | .POST(body) 14 | .uri(URI.create("http://httpbin.org/post")) 15 | .build(); 16 | 17 | HttpClient httpClient = HttpClientBuilderTest.createHttpClient(); 18 | HttpResponse httpResponse = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); 19 | System.out.println("Response: " + httpResponse.body()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /java-19/WebServerThreads.java: -------------------------------------------------------------------------------- 1 | import com.sun.net.httpserver.*; 2 | import java.net.*; 3 | import java.io.*; 4 | import java.nio.file.*; 5 | import java.util.function.Predicate; 6 | import java.util.concurrent.Executors; 7 | 8 | /** 9 | * Run: `java --enable-preview --source 19 WebServerThreads.java` 10 | */ 11 | public class WebServerThreads { 12 | public static void main(String[] args) throws IOException { 13 | var server = HttpServer.create(new InetSocketAddress(8000), 0); 14 | server.createContext("/", HttpHandlers.of(200, new Headers(), "Handled!")); 15 | 16 | // server.setExecutor(Executors.newCachedThreadPool()); 17 | server.setExecutor(Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory())); 18 | 19 | server.start(); 20 | System.out.println("Server started at " + server.getAddress()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /java-23/JavaDocMarkdownExample.java: -------------------------------------------------------------------------------- 1 | /// To run: 2 | /// - `javadoc JavaDocMarkdownExample.java` 3 | public class JavaDocMarkdownExample { 4 | /// Code to generate **Universe** _answer_: 5 | /// 6 | /// Restrictions: 7 | /// 8 | /// - can take as long as Universe life 9 | /// - can use [java.util.Random] 10 | /// - requires only [base module][java.base/] 11 | /// 12 | /// ```java 13 | /// (int) (new java.util.Random().nextDouble() * 42); 14 | /// ``` 15 | /// 16 | /// @return int with the answer 17 | /// @throws IllegalStateException if the Universe has ended 18 | public int calculateAnswer() { 19 | return (int) (new java.util.Random().nextDouble() * 42); 20 | } 21 | 22 | public static void main(String[] args) { 23 | System.out.println("Universe answer: " + new JavaDocMarkdownExample().calculateAnswer()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /java-8/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.github.wesleyegberto 5 | java-8-new-features 6 | 1.0-SNAPSHOT 7 | jar 8 | 9 | 10 | 11 | 12 | 13 | java-new-features 14 | 15 | 16 | 17 | 1.8 18 | 1.8 19 | false 20 | 21 | -------------------------------------------------------------------------------- /projects/loom/VirtualThreadExecutorTest.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.ExecutorService; 2 | import java.util.concurrent.Executors; 3 | 4 | /** 5 | * Simple project to show how to use the VirtualThread. 6 | * To run: `java --enable-preview --source 19 VirtualThreadExecutorTest.java` 7 | */ 8 | public class VirtualThreadExecutorTest { 9 | public static void main(String[] args) throws Exception { 10 | var threadFactory = Thread.ofVirtual().factory(); 11 | 12 | ExecutorService executorService = Executors.newThreadPerTaskExecutor(threadFactory); 13 | 14 | var result = executorService.submit(() -> { 15 | String name = Thread.currentThread().getName(); 16 | System.out.printf("Hello World from virtual Thread called %s!\n", name); 17 | return 42; 18 | }); 19 | 20 | System.out.println("Answer: " + result.get()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /java-11/GetRequestAsyncTest.java: -------------------------------------------------------------------------------- 1 | import java.net.http.HttpClient; 2 | import java.net.http.HttpRequest; 3 | import java.net.http.HttpResponse; 4 | 5 | public class GetRequestAsyncTest { 6 | public static void main(String[] args) throws InterruptedException { 7 | HttpRequest request = HttpBinRequestBuilder.createGetRequest(); 8 | 9 | HttpClient httpClient = HttpClientBuilderTest.createHttpClient(); 10 | // HttpClient#sendAsync is non-blocking and returns a CompletableFuture 11 | httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()) 12 | .thenApply(HttpResponse::body) 13 | .thenAccept(body -> System.out.println("Async Response: " + body)) 14 | .exceptionally(ex -> { 15 | System.out.println("Exception: " + ex.getLocalizedMessage()); 16 | return null; 17 | }) 18 | .join(); // let's wait 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /java-25/ProfilingTest.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.util.stream.*; 3 | 4 | /** 5 | * Compile: `javac ProfilingTest.java` 6 | * Test AOT cache with two-step: 7 | * * Record mode: `java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf ProfilingTest` 8 | * * Create mode: `java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf -XX:AOTCache=app.aot` 9 | * * Run with AOT cache: `java -XX:AOTCache=app.aot ProfilingTest` 10 | */ 11 | public class ProfilingTest { 12 | static String greeting(int n) { 13 | var words = List.of("Hello", "" + n, "world!"); 14 | return words.stream() 15 | .filter(w -> !w.contains("0")) 16 | .collect(Collectors.joining(", ")); 17 | } 18 | 19 | public static void main(String... args) { 20 | for (int i = 0; i < 100_000; i++) 21 | greeting(i); 22 | System.out.println(greeting(0)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /java-19/StressPlatformThreadWithFibonacciAndRequest.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.Executors; 2 | import java.util.stream.IntStream; 3 | 4 | /** 5 | * Run: 6 | * - `javac Fibonacci.java` 7 | * - `java --enable-preview --source 19 ` 8 | */ 9 | public class StressPlatformThreadWithFibonacciAndRequest { 10 | public static void main(String[] args) { 11 | var executor = Executors.newCachedThreadPool(); 12 | 13 | IntStream.range(0, 100).forEach(i -> { 14 | executor.submit(() -> { 15 | Fibonacci.fibWithRequest(i, 40, executor) 16 | .thenAccept(result -> { 17 | System.out.printf("Platform Thread %d - %d%n", i, result); 18 | }) 19 | .exceptionally(ex -> { 20 | System.out.printf("Platform Thread %d - error: %s%n", i, ex.getMessage()); 21 | return null; 22 | });; 23 | }); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /java-9/others-features/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.github.wesleyegberto 5 | java-9-new-features 6 | 1.0-SNAPSHOT 7 | jar 8 | 9 | 10 | 11 | 12 | 13 | java-9-new-features 14 | 15 | 16 | 17 | 9 18 | 9 19 | false 20 | 21 | 22 | -------------------------------------------------------------------------------- /java-19/StressPlatformThread.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.Executors; 2 | import java.util.stream.IntStream; 3 | 4 | /** 5 | * Run: `java --enable-preview --source 19 ` 6 | */ 7 | public class StressPlatformThread { 8 | public static void main(String[] args) { 9 | var executor = Executors.newCachedThreadPool(); 10 | // WARNING: 10K threads sleeping 500 may restart your computer (save everything before run it!) 11 | // IntStream.range(0, 10_000).forEach(i -> { 12 | IntStream.range(0, 1_000).forEach(i -> { 13 | executor.submit(() -> { 14 | System.out.printf("Thread %d - %s%n", i, Thread.currentThread().getName()); 15 | try { 16 | Thread.sleep(500); 17 | } catch (InterruptedException e) { 18 | System.out.printf("Thread %d - %s interrupted%n", i, Thread.currentThread().getName()); 19 | } 20 | }); 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /java-9/others-features/src/main/java/com/github/wesleyegberto/collections/collections/StreamTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.collections.collections; 2 | 3 | import java.util.List; 4 | import java.util.stream.IntStream; 5 | import java.util.stream.Stream; 6 | 7 | import static java.util.stream.Collectors.filtering; 8 | import static java.util.stream.Collectors.toList; 9 | 10 | public class StreamTest { 11 | public static void main(String[] args) { 12 | Stream shouldBeEmpty = Stream.ofNullable(null); 13 | 14 | // Won't print anything 15 | shouldBeEmpty.forEach(System.out::println); 16 | 17 | List numbers = IntStream.range(0, 10) 18 | .mapToObj(i -> Integer.valueOf(i)) 19 | .collect(filtering(i -> i.intValue() > 5, toList())); 20 | 21 | numbers.forEach(System.out::println); 22 | } 23 | } -------------------------------------------------------------------------------- /java-13/TextBlocksExample.java: -------------------------------------------------------------------------------- 1 | public class TextBlocksExample { 2 | public static void main(String[] args) { 3 | // Error (same line) 4 | // String name = """Pat Q. Smith"""; 5 | 6 | // 3 double-quote must be followed by line terminator (new line) 7 | String niceJson = """ 8 | { 9 | "name": "Odair Jose", 10 | "language": "Java" 11 | }"""; // same line to not append \n at the end 12 | System.out.println(niceJson); 13 | 14 | // the identation is kept based on the most left char of block (incidental white spaces) 15 | String html = """ 16 | 17 | 18 |

Hello World.

19 | 20 | 21 | """; // will append a \n at the end 22 | System.out.println(html); 23 | 24 | String badJson = """ 25 | { 26 | "name": "Odair Jose", 27 | "language": "Java" 28 | }"""; 29 | System.out.println(badJson); 30 | } 31 | } -------------------------------------------------------------------------------- /java-9/others-features/src/main/java/com/github/wesleyegberto/collections/collections/CollectionsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.collections.collections; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.Set; 6 | 7 | public class CollectionsTest { 8 | public static void main(String[] args) { 9 | List.of("First", "Second", "Third") 10 | .forEach(System.out::println); 11 | 12 | Set.of(1, 2, 3, 4, 5) 13 | .forEach(System.out::println); 14 | 15 | Map.of("K1", "V1", "K2", "V2", "K3", "V3", "K4", "V4", "K5", "V5") 16 | .forEach((key, value) -> System.out.println(key + " -> " + value)); 17 | 18 | Map.ofEntries( 19 | Map.entry("K1", "V1"), 20 | Map.entry("K2", "V2"), 21 | Map.entry("K3", "V3"), 22 | Map.entry("K4", "V4"), 23 | Map.entry("K5", "V5") 24 | ) 25 | .forEach((key, value) -> System.out.println(key + " -> " + value)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /java-15/RecordWithSealedInterface.java: -------------------------------------------------------------------------------- 1 | public class RecordWithSealedInterface { 2 | public static void main(String[] args) { 3 | Expr expr = new TimesExpr(new ConstantExpr(6), new ConstantExpr(7)); 4 | System.out.println("Answer: " + expr.evaluate()); 5 | } 6 | } 7 | 8 | sealed interface Expr permits ConstantExpr, PlusExpr, TimesExpr, NegExpr { 9 | Integer evaluate(); 10 | } 11 | 12 | record ConstantExpr(int i) implements Expr { 13 | public Integer evaluate() { 14 | return this.i; 15 | } 16 | } 17 | 18 | record PlusExpr(Expr a, Expr b) implements Expr { 19 | public Integer evaluate() { 20 | return a.evaluate() + b.evaluate(); 21 | } 22 | } 23 | 24 | record TimesExpr(Expr a, Expr b) implements Expr { 25 | public Integer evaluate() { 26 | return a.evaluate() * b.evaluate(); 27 | } 28 | } 29 | 30 | record NegExpr(Expr e) implements Expr { 31 | public Integer evaluate() { 32 | return -1 * this.e.evaluate(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /java-20/ScopedValueUsageWithReturnValueExample.java: -------------------------------------------------------------------------------- 1 | import jdk.incubator.concurrent.*; 2 | 3 | /** 4 | * Run: `java --source 20 --enable-preview --add-modules jdk.incubator.concurrent ScopedValueUsageWithReturnValueExample.java` 5 | */ 6 | public class ScopedValueUsageWithReturnValueExample { 7 | final static ScopedValue MAIN_SCOPE = ScopedValue.newInstance(); 8 | 9 | public static void main(String[] args) throws Exception { 10 | // we use `call` to run a scope and get it returned value 11 | var result = ScopedValue.where(MAIN_SCOPE, 42) 12 | .call(() -> { // throws Exception 13 | var calculator = new Calculator(); 14 | return calculator.calculate(); 15 | }); 16 | System.out.println("Result from calculation: " + result); 17 | } 18 | } 19 | 20 | class Calculator { 21 | public int calculate() { 22 | var seed = ScopedValueUsageWithReturnValueExample.MAIN_SCOPE.get(); 23 | return seed + 42; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /java-19/StressVirtualThreadWithFibonacciAndRequest.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.Executors; 2 | import java.util.stream.IntStream; 3 | 4 | /** 5 | * Run: 6 | * - `javac Fibonacci.java` 7 | * - `java --enable-preview --source 19 ` 8 | */ 9 | public class StressVirtualThreadWithFibonacciAndRequest { 10 | public static void main(String[] args) { 11 | var executor = Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory()); 12 | 13 | IntStream.range(0, 100).forEach(i -> { 14 | executor.submit(() -> { 15 | Fibonacci.fibWithRequest(i, 40, executor) 16 | .thenAccept(result -> { 17 | System.out.printf("Virtual Thread %d - %d%n", i, result); 18 | }) 19 | .exceptionally(ex -> { 20 | System.out.printf("Virtual Thread %d - error: %s%n", i, ex.getMessage()); 21 | return null; 22 | }); 23 | }); 24 | }); 25 | 26 | while (!executor.isTerminated()) { 27 | ; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /java-19/StressVirtualThread.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.Executors; 2 | import java.util.stream.IntStream; 3 | 4 | /** 5 | * Run: `java --enable-preview --source 19 ` 6 | */ 7 | public class StressVirtualThread { 8 | public static void main(String[] args) { 9 | var executor = Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory()); 10 | 11 | IntStream.range(0, 10_000).forEach(i -> { 12 | executor.submit(() -> { 13 | System.out.printf("VirtualThread %d - %s%n", i, Thread.currentThread().getName()); 14 | try { 15 | Thread.sleep(500); 16 | } catch (InterruptedException e) { 17 | System.out.printf("VirtualThread %d - %s interrupted%n", i, Thread.currentThread().getName()); 18 | } finally { 19 | System.out.printf("VirtualThread %d - %s woke up%n", i, Thread.currentThread().getName()); 20 | } 21 | }); 22 | }); 23 | 24 | while (!executor.isTerminated()) { 25 | ; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /java-24/BasicClass.java: -------------------------------------------------------------------------------- 1 | import java.io.Serializable; 2 | 3 | /** 4 | * Used in Class File API examples. 5 | */ 6 | public class BasicClass implements Serializable { 7 | private String attribute; 8 | private int timestamp; 9 | private boolean active; 10 | 11 | public BasicClass() { 12 | } 13 | 14 | public BasicClass(String attribute, int timestamp, boolean active) { 15 | this.attribute = attribute; 16 | this.timestamp = timestamp; 17 | this.active = active; 18 | } 19 | 20 | public String getAttribute() { 21 | return attribute; 22 | } 23 | 24 | public void setAttribute(String attribute) { 25 | this.attribute = attribute; 26 | } 27 | 28 | public int getTimestamp() { 29 | return timestamp; 30 | } 31 | 32 | public void setTimestamp(int timestamp) { 33 | this.timestamp = timestamp; 34 | } 35 | 36 | public boolean isActive() { 37 | return active; 38 | } 39 | 40 | public void setActive(boolean active) { 41 | this.active = active; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /java-12/CollectorsTeeingTest.java: -------------------------------------------------------------------------------- 1 | import java.util.stream.*; 2 | import java.util.Optional; 3 | 4 | public class CollectorsTeeingTest { 5 | public static void main(String[] args) { 6 | Range range = Stream 7 | .of(1, 8, 2, 5) 8 | .collect(Collectors.teeing( 9 | // the collectors produce Optional 10 | Collectors.minBy(Integer::compareTo), 11 | Collectors.maxBy(Integer::compareTo), 12 | // merger 13 | Range::ofOptional) 14 | ); 15 | 16 | System.out.println("Range: " + range.getRange()); 17 | } 18 | } 19 | 20 | class Range { 21 | private String range; 22 | 23 | Range(String range) { 24 | this.range = range; 25 | } 26 | 27 | public static Range ofOptional(Optional min, Optional max) { 28 | if (min.isEmpty() || max.isEmpty()) { 29 | return new Range("EMPTY"); 30 | } 31 | return new Range(String.format("from %d to %d", min.get(), max.get())); 32 | } 33 | 34 | public String getRange() { 35 | return range; 36 | } 37 | } -------------------------------------------------------------------------------- /java-25/ImplicityDeclaredClassWithAllowedMembers.java: -------------------------------------------------------------------------------- 1 | /** 2 | * To run: `java ImplicityDeclaredClassWithAllowedMembers.java` 3 | */ 4 | 5 | static String staticField = "can have static field"; 6 | static String privateStaticField = "can have private static field"; 7 | 8 | String instanceField = "can have instance field"; 9 | private String privateInstanceField = "can have private instance field"; 10 | 11 | static void staticMethod() { 12 | System.out.println("can have static method"); 13 | } 14 | 15 | private static void privateStaticMethod() { 16 | System.out.println("can use any modifier"); 17 | } 18 | 19 | static void instanceMethod() { 20 | System.out.println("can have any instance method"); 21 | } 22 | 23 | void main() { 24 | System.out.println("must always have a valid main method to launch"); 25 | 26 | System.out.println("static field: " + staticField); 27 | System.out.println("instance field: " + instanceField); 28 | 29 | staticMethod(); 30 | this.instanceMethod(); 31 | } 32 | -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/lambdas/sideeffects/UnnecessaryOne.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.lambdas.sideeffects; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | import java.util.stream.IntStream; 7 | 8 | /** 9 | * @author Wesley Egberto 10 | */ 11 | public class UnnecessaryOne { 12 | public static void main(String[] args) { 13 | // Example of an unnecessary side-effect lambda to store the result 14 | List uglyOddNumbers = new ArrayList<>(); 15 | IntStream.range(0, 10) 16 | .filter(i -> i % 2 != 0) 17 | .forEach(i -> uglyOddNumbers.add(i)); 18 | 19 | uglyOddNumbers.forEach(System.out::println); 20 | 21 | // Correct one using collector 22 | List correctOddNumbers = IntStream.range(0, 10) 23 | .filter(i -> i % 2 != 0) 24 | .boxed() 25 | .collect(Collectors.toList()); 26 | correctOddNumbers.forEach(System.out::println); 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /java-9/modules/services/run_module_service.sh: -------------------------------------------------------------------------------- 1 | # create the temp folders 2 | mkdir -p output/mlibs 3 | 4 | 5 | # Building the service provider module 6 | echo 'Building provider module' 7 | mkdir output/classes 8 | # compile the files 9 | $JAVA9_HOME/bin/javac -d output/classes --module-version 1.0 `find provider -name *.java` 10 | # build the modules 11 | $JAVA9_HOME/bin/jar -cf output/mlibs/provider-1.0.jar -C output/classes . 12 | rm -rf output/classes 13 | 14 | 15 | # Building the services consumer module 16 | echo 'Building consumer module' 17 | mkdir output/classes 18 | # compile the files 19 | $JAVA9_HOME/bin/javac -p output/mlibs -d output/classes --module-version 1.0 `find consumer -name *.java` 20 | # build the modules 21 | $JAVA9_HOME/bin/jar -c -f output/mlibs/consumer-1.0.jar \ 22 | --main-class com.github.wesleyegberto.consumer.MadScientist \ 23 | -C output/classes . 24 | rm -rf output/classes 25 | 26 | # Run the builds 27 | echo 'Running' 28 | $JAVA9_HOME/bin/java -p output/mlibs -m consumer -------------------------------------------------------------------------------- /java-7/README.md: -------------------------------------------------------------------------------- 1 | # Java 7 2 | 3 | ## Features 4 | 5 | * Collections API: 6 | * `TransferQueue` 7 | * extends `BlockingQueue` interface 8 | * implementated by `LinkedTransferQueue` 9 | * blocking queue in which producer may wait for consumers to receive elements 10 | * it can publish an element and wait for consumers or just publish and forget 11 | * it can use a timeout to wait for a consumer 12 | * methods: 13 | * `getWaitingConsumerCount()`: returns an estimate of the number of waiting consumer to receive elements via `BlockingQueue` `take` or timed `poll`. 14 | * `hasWaitingConsumer()`: returns true if there is any waiting consumer. 15 | * `transfer(E)`: send an element and wait for the consumer. 16 | * `tryTransfer(E)`: send an element to a waiting consumer, return false immediately if there isn't any consumer. 17 | * `tryTransfer(E, long, TimeUnit)`: like `tryTransfer` but with a timeout to wait for a consumer before returning false. 18 | 19 | -------------------------------------------------------------------------------- /projects/loom/VirtualThreadHelloWorld.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple project to show how to use the VirtualThread. 3 | * To run: `java --enable-preview --source 19 VirtualThreadHelloWorld.java` 4 | */ 5 | public class VirtualThreadHelloWorld { 6 | public static void main(String[] args) throws Exception { 7 | Thread.startVirtualThread(() -> { 8 | String name = Thread.currentThread().getName(); 9 | System.out.printf("Hello World from virtual Thread called %s!\n", name); 10 | }); 11 | 12 | Thread.ofVirtual() 13 | .name("Virtual-Thread-From-Builder") 14 | .start(() -> { 15 | String name = Thread.currentThread().getName(); 16 | System.out.printf("Hello World from virtual Thread called %s!\n", name); 17 | }); 18 | 19 | Thread.ofPlatform() 20 | .name("Real-Thread-From-Builder") 21 | .start(() -> { 22 | String name = Thread.currentThread().getName(); 23 | System.out.printf("Hello World from real Thread called %s!\n", name); 24 | }); 25 | 26 | Thread.sleep(5000); 27 | } 28 | } -------------------------------------------------------------------------------- /java-9/others-features/src/main/java/com/github/wesleyegberto/collections/processapi/ProcessTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.collections.processapi; 2 | 3 | import java.io.IOException; 4 | 5 | public class ProcessTest { 6 | public static void main(String[] args) throws IOException, InterruptedException { 7 | ProcessHandle process = ProcessHandle.current(); 8 | System.out.println("Main pid: " + process.pid()); 9 | System.out.println("Main user: " + process.info().user().orElse("Unknown")); 10 | 11 | Process sleepy = Runtime.getRuntime().exec("sleep 60s"); 12 | System.out.println("Sleepy pid: " + sleepy.pid()); 13 | 14 | System.out.println("Destroying sleepy"); 15 | ProcessHandle handle = ProcessHandle.of(sleepy.pid()).get(); 16 | handle.onExit() 17 | // sleepy.onExit() 18 | .thenRun(() -> { 19 | System.out.println("Alive: " + sleepy.isAlive()); 20 | System.out.println("Exit code: " + sleepy.exitValue()); 21 | }); 22 | sleepy.destroy(); 23 | 24 | Thread.sleep(5000); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /java-21/UnnamedClassWithAllowedMembers.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Using JDK manually built from main branch. 3 | * 4 | * To run: `java --enable-preview --source 21 UnnamedClassWithAllowedMembers.java` 5 | */ 6 | 7 | static String staticField = "can have static field"; 8 | static String privateStaticField = "can have private static field"; 9 | 10 | String instanceField = "can have instance field"; 11 | private String privateInstanceField = "can have private instance field"; 12 | 13 | static void staticMethod() { 14 | System.out.println("can have static method"); 15 | } 16 | 17 | private static void privateStaticMethod() { 18 | System.out.println("can use any modifier"); 19 | } 20 | 21 | static void instanceMethod() { 22 | System.out.println("can have any instance method"); 23 | } 24 | 25 | void main() { 26 | System.out.println("must always have a valid main method to launch"); 27 | 28 | System.out.println("static field: " + staticField); 29 | System.out.println("instance field: " + instanceField); 30 | 31 | staticMethod(); 32 | this.instanceMethod(); 33 | } 34 | -------------------------------------------------------------------------------- /java-9/others-features/src/main/java/com/github/wesleyegberto/collections/httpclient/HttpClientTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.collections.httpclient; 2 | 3 | import java.io.IOException; 4 | import java.net.URI; 5 | import jdk.incubator.http.*; 6 | 7 | public class HttpClientTest { 8 | public static void main(String[] args) throws IOException, InterruptedException { 9 | HttpRequest request = HttpRequest.newBuilder() 10 | .uri(URI.create("http://httpbin.org/uuid")) 11 | .GET() 12 | .build(); 13 | 14 | String syncResponse = HttpClient.newHttpClient() 15 | .send(request, HttpResponse.BodyHandler.asString()) 16 | .body(); 17 | 18 | System.out.println("Sync response: " + syncResponse); 19 | 20 | HttpClient.newHttpClient() 21 | .sendAsync(request, HttpResponse.BodyHandler.asString()) 22 | .thenApply(HttpResponse::body) 23 | .thenAccept(response -> System.out.println("Async response: " + response)); 24 | 25 | 26 | /* 27 | .responseAsync() // CompletableFuture 28 | .thenAccept(httpResponse -> 29 | System.out.println(httpResponse.body(HttpResponse.asString())) 30 | );*/ 31 | Thread.sleep(5000); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/interfaces/InterfaceTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.interfaces; 2 | 3 | /** 4 | * @author Wesley Egberto 5 | */ 6 | public class InterfaceTest implements B/*, C*/ { 7 | @Override 8 | public void abstractMethod() { 9 | System.out.println("In class implemented method"); 10 | } 11 | 12 | public void go() { 13 | concreteMethod(); 14 | A.staticMethod(); 15 | B.staticMethod(); 16 | // staticMethod(); isn't inherited 17 | } 18 | 19 | public static void main(String[] args) { 20 | new InterfaceTest().go(); 21 | } 22 | } 23 | 24 | interface A { 25 | void abstractMethod(); 26 | 27 | default void concreteMethod() { 28 | System.out.println("In interface A concrete method"); 29 | } 30 | 31 | static void staticMethod() { 32 | System.out.println("In interface A static method"); 33 | } 34 | } 35 | 36 | interface B extends A { 37 | default void concreteMethod() { 38 | System.out.println("In interface B concrete method"); 39 | } 40 | 41 | static void staticMethod() { 42 | System.out.println("In interface B static method"); 43 | } 44 | } 45 | 46 | interface C { 47 | default void concreteMethod() { 48 | System.out.println("In interface C concrete method"); 49 | } 50 | } -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/model/Person.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.model; 2 | 3 | import java.util.*; 4 | 5 | public class Person { 6 | private String name; 7 | private int age; 8 | 9 | public Person(String name, int age) { 10 | this.name = name; 11 | this.age = age; 12 | } 13 | 14 | public String getName() { 15 | return name; 16 | } 17 | 18 | public int getAge() { 19 | return age; 20 | } 21 | 22 | public String toString() { 23 | return name + " " + age; 24 | } 25 | 26 | public static List getList() { 27 | List persons = new ArrayList(); 28 | persons.add(new Person("Tony", 10)); 29 | persons.add(new Person("Logan", 18)); 30 | persons.add(new Person("Peter", 21)); 31 | persons.add(new Person("Bruce", 30)); 32 | persons.add(new Person("Rachel", 11)); 33 | persons.add(new Person("Joey", 14)); 34 | persons.add(new Person("Lucas", 22)); 35 | persons.add(new Person("Neo", 24)); 36 | persons.add(new Person("Jorge", 22)); 37 | persons.add(new Person("Matheus", 24)); 38 | persons.add(new Person("Francis", 19)); 39 | persons.add(new Person("Trinity", 23)); 40 | persons.add(new Person("Morpheu", 42)); 41 | persons.add(new Person("Jorge", 17)); 42 | 43 | return persons; 44 | } 45 | } -------------------------------------------------------------------------------- /java-11/GetRequestReactiveTest.java: -------------------------------------------------------------------------------- 1 | import java.net.http.HttpRequest; 2 | import java.net.http.HttpResponse.BodyHandlers; 3 | import java.util.concurrent.Flow.Subscriber; 4 | import java.util.concurrent.Flow.Subscription; 5 | 6 | public class GetRequestReactiveTest { 7 | public static void main(String[] args) { 8 | HttpRequest request = HttpBinRequestBuilder.createGetRequest(); 9 | 10 | HttpClientBuilderTest.createHttpClient() 11 | .sendAsync(request, BodyHandlers.fromLineSubscriber(new LinePrinter())) 12 | .join(); 13 | } 14 | 15 | public static class LinePrinter implements Subscriber { 16 | private Subscription subscription; 17 | 18 | @Override 19 | public void onSubscribe(Subscription subscription) { 20 | this.subscription = subscription; 21 | this.subscription.request(1); 22 | } 23 | 24 | @Override 25 | public void onNext(String item) { 26 | System.out.println("== [LinePrinter] Line received: " + item); 27 | this.subscription.request(1); 28 | } 29 | 30 | @Override 31 | public void onError(Throwable throwable) { 32 | System.out.println("== [LinePrinter] Line received: " + throwable); 33 | } 34 | 35 | @Override 36 | public void onComplete() { 37 | System.out.println("== [LinePrinter] Completed"); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /java-16/RecordStaticInnerMemberTest.java: -------------------------------------------------------------------------------- 1 | public class RecordStaticInnerMemberTest { 2 | public static void main(String[] args) { 3 | var outer = new OutterClass(); 4 | var inner = outer.new InnerClass(); 5 | var staticInnerInner = new OutterClass.InnerClass.InnerInnerStaticClass(); 6 | System.out.println("Secret: " + staticInnerInner.innerSecret.secret()); 7 | } 8 | 9 | } 10 | 11 | /** 12 | * JEP 395: 13 | * Relax the longstanding restriction whereby an inner class cannot declare a member that is explicitly or 14 | * implicitly static. This will become legal and, in particular, will allow an inner class to declare a 15 | * member that is a record class. 16 | */ 17 | class OutterClass { 18 | class InnerClass { 19 | private String innerClassAttr = "My field"; 20 | 21 | // only allowed on JDK 16 22 | static class InnerInnerStaticClass { 23 | InnerRecord innerSecret; 24 | 25 | InnerInnerStaticClass() { 26 | this.innerSecret = new InnerRecord("only allowed in Java 16"); 27 | } 28 | } 29 | 30 | // nested record is implicit static (that way this JEP was done - allow static inner class/record) 31 | record InnerRecord(String secret) { 32 | public String mix() { 33 | return this.secret(); // + InnerClass.this.innerClassAttr; 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /java-20/PatternMatchingForSwitchFourthPreviewTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * To run: `java --enable-preview --source 20 PatternMatchingForSwitchFourthPreviewTest.java` 3 | */ 4 | public class PatternMatchingForSwitchFourthPreviewTest { 5 | public static void main(String[] args) { 6 | recordErrorInSwitchPatternMatching(); 7 | 8 | genericRecordInSwitch(); 9 | } 10 | 11 | static void recordErrorInSwitchPatternMatching() { 12 | var dot = new OneDimensionalPoint(10); 13 | 14 | switch (dot) { 15 | // will cause MatchException with wrapped exception (the record pattern completes abruptly with the ArithmeticException) 16 | case OneDimensionalPoint(var x): System.out.println("1D point"); 17 | // the occurring in guarded clause, it just rethrows the exception 18 | // will cause ArithmeticException 19 | // case OneDimensionalPoint p when (p / 0 == 1): System.out.println("Non sense"); 20 | } 21 | } 22 | 23 | static void genericRecordInSwitch() { 24 | var w = new Wrapper("some text"); 25 | 26 | switch (w) { 27 | // will infer Wrapper 28 | case Wrapper(var v): System.out.println("Wrapped value: " + v); 29 | } 30 | } 31 | } 32 | 33 | record OneDimensionalPoint(int x) { 34 | public int x() { 35 | return x / 0; 36 | } 37 | } 38 | 39 | record Wrapper(T t) {} 40 | -------------------------------------------------------------------------------- /java-16/SealedTypesExample.java: -------------------------------------------------------------------------------- 1 | public class SealedTypesExample { 2 | public static void main(String[] args) { 3 | var gowButton = new Circle(); 4 | gowButton.press(); 5 | 6 | // sealed, permits and non-sealed is contextual keywords (we can use as var name) 7 | var sealed = gowButton != null; 8 | SealedTypesExample.sealed(); 9 | } 10 | 11 | public static void sealed() { 12 | // local class cannot extend/implement a sealed class/interface 13 | // class NewCross extends Cross {} 14 | 15 | System.out.println("My name is Neo"); 16 | } 17 | } 18 | 19 | sealed interface PlayStationButton permits Circle, Square, Triangle, Cross { 20 | void press(); 21 | } 22 | 23 | final class Circle implements PlayStationButton { 24 | public void press() { 25 | System.out.println("Button was pressed"); 26 | } 27 | } 28 | 29 | final class Square implements PlayStationButton { 30 | public void press() { 31 | System.out.println("Button was pressed"); 32 | } 33 | } 34 | 35 | final class Triangle implements PlayStationButton { 36 | public void press() { 37 | System.out.println("Button was pressed"); 38 | } 39 | } 40 | 41 | sealed class Cross implements PlayStationButton { 42 | public void press() { 43 | System.out.println("Button was pressed"); 44 | } 45 | } 46 | 47 | final class DoubleCross extends Cross { } 48 | -------------------------------------------------------------------------------- /java-9/modules/simple_deps/build_modules.sh: -------------------------------------------------------------------------------- 1 | # create the temp folders 2 | mkdir -p output/mlibs 3 | 4 | 5 | # Building the API module 6 | echo 'Building MathApi module' 7 | mkdir output/classes 8 | # compile the files 9 | $JAVA9_HOME/bin/javac -d output/classes --module-version 1.0 `find math_api -name *.java` 10 | # build the modules 11 | $JAVA9_HOME/bin/jar -cf output/mlibs/mathapi-1.0.jar -C output/classes . 12 | rm -rf output/classes 13 | 14 | 15 | # Building the implementation module 16 | echo 'Building MathImpl module' 17 | mkdir output/classes 18 | # compile the classes defining the modules path (-p) we use and our module version 19 | $JAVA9_HOME/bin/javac -p output/mlibs -d output/classes --module-version 1.0 `find math_lib -name *.java` 20 | # build the modules 21 | $JAVA9_HOME/bin/jar -cf output/mlibs/mathlib-1.0.jar -C output/classes . 22 | rm -rf output/classes 23 | 24 | 25 | # Building the user module 26 | echo 'Building Calculator module' 27 | mkdir output/classes 28 | $JAVA9_HOME/bin/javac -p output/mlibs -d output/classes `find calculator -name *.java` 29 | # build the module defining the main class to run (when no class is specified) 30 | $JAVA9_HOME/bin/jar -c -f output/mlibs/calculator.jar \ 31 | --main-class com.github.wesleyegberto.calculator.SimpleCalculator \ 32 | -C output/classes . 33 | rm -rf output/classes -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/lambdas/Example_Consumers.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.lambdas; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.function.Consumer; 6 | 7 | /** 8 | * @author Wesley Egberto. 9 | */ 10 | public class Example_Consumers { 11 | public static void main(String[] args) { 12 | List names = Arrays.asList("Bruce", "Logan", "Peter"); 13 | 14 | System.out.println("Using anonymous class"); 15 | names.forEach(new Consumer() { 16 | @Override 17 | public void accept(String name) { 18 | System.out.println(name); 19 | } 20 | }); 21 | 22 | System.out.println("\nUsing lambda expression"); 23 | names.forEach(name -> System.out.println(name)); 24 | 25 | System.out.println("\nUsing method reference (will create a class on the fly)"); 26 | Consumer myConsumer = System.out::println; 27 | names.forEach(System.out::println); 28 | 29 | System.out.println("\nUsing stream to map to another class"); 30 | names.stream().map(Hero::new) 31 | .map(Hero::getSecretIdentity) 32 | .forEach(myConsumer); 33 | 34 | } 35 | } 36 | 37 | class Hero { 38 | private String secretIdentity; 39 | 40 | public Hero(String secretIdentity) { 41 | this.secretIdentity = "Mr. " + secretIdentity; 42 | } 43 | 44 | public String getSecretIdentity() { 45 | return secretIdentity; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /java-16/ValueBasedClassWarnings.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Error: `java --enable-preview --source 16 ValueBasedClassWarnings.java` 3 | * Only warning: `java -XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=2 --enable-preview --source 16 ValueBasedClassWarnings.java` 4 | * 5 | * From docs: 6 | * @ValueBased is applied to the following declarations in the Java Platform API and the JDK: 7 | * - The primitive wrapper classes in java.lang; 8 | * - The class java.lang.Runtime.Version; 9 | * - The "optional" classes in java.util: Optional, OptionalInt, OptionalLong, and OptionalDouble; 10 | * - Many classes in the java.time API: Instant, LocalDate, LocalTime, LocalDateTime, ZonedDateTime, ZoneId, 11 | * OffsetTime, OffsetDateTime, ZoneOffset, Duration, Period, Year, YearMonth, and MonthDay, and, in 12 | * java.time.chrono: MinguoDate, HijrahDate, JapaneseDate, and ThaiBuddhistDate; 13 | * - The interface java.lang.ProcessHandle and its implementation classes; 14 | * - The implementation classes of the collection factories in java.util: List.of, List.copyOf, Set.of, Set.copyOf, 15 | * Map.of, Map.copyOf, Map.ofEntries, and Map.entry. 16 | */ 17 | public class ValueBasedClassWarnings { 18 | public static void main(String[] args) { 19 | var d = new Double(10); 20 | 21 | synchronized (d) { 22 | System.out.println("Synchronized block using a value-based object"); 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /java-14/TextBlocksExample.java: -------------------------------------------------------------------------------- 1 | public class TextBlocksExample { 2 | public static void main(String[] args) { 3 | // Java 13 4 | 5 | // Error (same line) 6 | // String name = """Pat Q. Smith"""; 7 | 8 | // 3 double-quote must be followed by line terminator (new line) 9 | String niceJson = """ 10 | { 11 | "name": "Odair Jose", 12 | "language": "Java" 13 | }"""; // same line to not append \n at the end 14 | System.out.println(niceJson); 15 | 16 | // the identation is kept based on the most left char of block (incidental white spaces) 17 | String html = """ 18 | 19 | 20 |

Hello World.

21 | 22 | 23 | """; // will append a \n at the end 24 | System.out.println(html); 25 | 26 | String badJson = """ 27 | { 28 | "name": \""Odair Jose", 29 | "language": "Java" 30 | }"""; 31 | System.out.println(badJson); 32 | 33 | 34 | // Java 14 - New escape sequences 35 | 36 | String sameLine = """ 37 | Line 1 \ 38 | Still line 1 \ 39 | Still... \ 40 | """; 41 | System.out.println(sameLine); 42 | 43 | String helpingKeepingTrailing = """ 44 | A lot of space here \s 45 | Here not much \s 46 | Here none but one will be inserted\s 47 | Ends \s 48 | """; 49 | System.out.println(helpingKeepingTrailing); 50 | } 51 | } -------------------------------------------------------------------------------- /java-18/SwitchWithPatternMatchingSecondPreview.java: -------------------------------------------------------------------------------- 1 | import java.time.LocalDate; 2 | import java.time.YearMonth; 3 | import java.time.ZoneOffset; 4 | import java.time.temporal.ChronoUnit; 5 | import java.util.stream.Stream; 6 | 7 | /** 8 | * Run: `java --enable-preview --source 18 ` 9 | */ 10 | public class SwitchWithPatternMatchingSecondPreview { 11 | public static void main(String[] args) { 12 | System.out.println(stringify(42)); 13 | System.out.println(stringify(-42)); 14 | System.out.println(stringify("Some text")); 15 | System.out.println(stringify("")); 16 | System.out.println(stringify(null)); 17 | } 18 | 19 | static String stringify(Object value) { 20 | return switch (value) { 21 | // the constant must be before the guarded pattern (otherwise it will never hit) 22 | case Integer i && i == 42 -> "42 is the answer"; 23 | case Integer i && i > 0 -> "positive number"; 24 | case Integer i && i < 0 -> "negative number"; 25 | // this must be after because it will match all integers 26 | case Integer i -> "should be 0"; 27 | 28 | case String s && s.isEmpty() -> "empty string"; 29 | case String s && s.length() > 50 -> "long string"; 30 | // this must be after because it will match all strings 31 | case String s -> "non-empty string"; 32 | // same here 33 | case CharSequence cs -> "any other CharSequence"; 34 | 35 | case null -> "null =s"; 36 | default -> "unhandled type"; 37 | }; 38 | } 39 | } -------------------------------------------------------------------------------- /java-10/README.md: -------------------------------------------------------------------------------- 1 | # Java 10 2 | 3 | ```sh 4 | sh build.sh 5 | java -cp bin 6 | ``` 7 | 8 | ## JEPs 9 | 10 | * [286](https://openjdk.java.net/jeps/286) - Local-Variable Type Inference 11 | * [296](https://openjdk.java.net/jeps/296) - Consolidate the JDK Forest into a Single Repository 12 | * [304](https://openjdk.java.net/jeps/304) - Garbage-Collector Interface 13 | * [307](https://openjdk.java.net/jeps/307) - Parallel Full GC for G1 14 | * [310](https://openjdk.java.net/jeps/310) - Application Class-Data Sharing 15 | * [312](https://openjdk.java.net/jeps/312) - Thread-Local Handshakes 16 | * [313](https://openjdk.java.net/jeps/313) - Remove the Native-Header Generation Tool (javah) 17 | * [314](https://openjdk.java.net/jeps/314) - Additional Unicode Language-Tag Extensions 18 | * [316](https://openjdk.java.net/jeps/316) - Heap Allocation on Alternative Memory Devices 19 | * [317](https://openjdk.java.net/jeps/317) - Experimental Java-Based JIT Compiler 20 | * [319](https://openjdk.java.net/jeps/319) - Root Certificates 21 | * [322](https://openjdk.java.net/jeps/322) - Time-Based Release Versioning 22 | 23 | ## Features 24 | 25 | * `var` keyword to declare variables 26 | * `var universeAnswer = 42` 27 | * Process API improvements 28 | * Collections API improvements 29 | 30 | ### JVM 31 | 32 | * Application Class-Data Sharing 33 | 34 | ## Links 35 | 36 | * [JDK 10 Documentation](https://docs.oracle.com/javase/10/) 37 | * [JDK 10 JEPs](https://openjdk.java.net/projects/jdk/10/) 38 | -------------------------------------------------------------------------------- /java-22/StatementsBeforeSuperExamples.java: -------------------------------------------------------------------------------- 1 | import java.util.Random; 2 | 3 | /* 4 | * To run: `java --enable-preview --source 22 StatementsBeforeSuperExamples.java` 5 | */ 6 | public class StatementsBeforeSuperExamples { 7 | public static void main() { 8 | new SimpleExample(42); 9 | new SimpleExample(); 10 | new SimpleExample("42"); 11 | } 12 | } 13 | 14 | class BaseClass { 15 | protected int value; 16 | 17 | BaseClass(int value) { 18 | System.out.println("BaseClass constructor: " + value); 19 | this.value = value; 20 | } 21 | } 22 | 23 | class SimpleExample extends BaseClass { 24 | SimpleExample(int v) { 25 | // before 26 | // super(validPositive(v)) 27 | 28 | // we can perform validation (fail fast) 29 | if (v <= 0) 30 | throw new IllegalArgumentException("Value must be positive"); 31 | super(v); 32 | System.out.println("Initialized with value: " + v); 33 | } 34 | 35 | SimpleExample() { 36 | // now we can call static method 37 | System.out.println("Randomizing"); 38 | int v = (int) (Math.random() * 1000); 39 | super(v); 40 | System.out.println("Initialized with random value: " + v); 41 | } 42 | 43 | SimpleExample(String value) { 44 | // we can only access static members of this class 45 | int v = parseValue(value); 46 | super(v); 47 | System.out.println("Initialized with parsed value: " + v); 48 | } 49 | 50 | static int parseValue(String value) { 51 | System.out.println("Parsing"); 52 | return Integer.parseInt(value); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /java-24/SynchronizeVirtualThreadTest.java: -------------------------------------------------------------------------------- 1 | import java.util.Scanner; 2 | import java.util.concurrent.Executors; 3 | 4 | /** 5 | * Try to run in JDK 21 and 24. 6 | * To run: `java -Djdk.virtualThreadScheduler.parallelism=2 -Djdk.tracePinnedThreads=short SynchronizeVirtualThreadTest.java` 7 | */ 8 | public class SynchronizeVirtualThreadTest { 9 | public static void main(String[] args) { 10 | // platform threads runs normally 11 | // var executor = Executors.newFixedThreadPool(2); 12 | 13 | // until Java 24, with parallelism 2, only two virtual thread will run by time 14 | // the virtual threads gets pinned and blocked waiting forever 15 | var factory = Thread.ofVirtual().name("VT-", 0).factory(); 16 | var executor = Executors.newThreadPerTaskExecutor(factory); 17 | 18 | var riskOperation = new RiskOperation(); 19 | 20 | for (int i = 0; i < 5; i++) { 21 | executor.submit(riskOperation::doSomething); 22 | } 23 | 24 | while (!executor.isTerminated()) { 25 | ; 26 | } 27 | } 28 | } 29 | 30 | class RiskOperation { 31 | void doSomething() { 32 | log("About to start a synchronized work"); 33 | this.doSynchronizedWork(); 34 | log("Work done"); 35 | } 36 | 37 | synchronized void doSynchronizedWork() { 38 | log("Doing synchronized work..."); 39 | try { 40 | Thread.sleep(1_000); 41 | } catch (InterruptedException ex) {} 42 | } 43 | 44 | void log(String message) { 45 | System.out.printf("%s - %s%n", Thread.currentThread().toString(), message); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /projects/loom/VirtualThreadCountThreads.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple project to show how to use the VirtualThread. 3 | * To run: `java --enable-preview --source 19 VirtualThreadCountThreads.java` 4 | */ 5 | public class VirtualThreadCountThreads { 6 | public static void main(String[] args) throws Exception { 7 | System.out.println("Open Java VisualVM to see threads"); 8 | 9 | // pause to open Java VisualVM 10 | Thread.sleep(10_000); 11 | System.out.println("Starting Threads"); 12 | 13 | new Thread(() -> { 14 | String name = Thread.currentThread().getName(); 15 | System.out.printf("Hello World from real Thread called %s!\n", name); 16 | 17 | try { 18 | System.out.printf("Thread %s is going to sleep\n", name); 19 | Thread.sleep(15000); 20 | } catch (Exception ex) {} 21 | finally { 22 | System.out.printf("Thread %s woke up\n", name); 23 | } 24 | }) 25 | .start(); 26 | 27 | Thread.startVirtualThread(() -> { 28 | String name = Thread.currentThread().getName(); 29 | System.out.printf("Hello World from VirtualThread called %s!\n", name); 30 | try { 31 | System.out.printf("VirtualThread %s is going to sleep\n", name); 32 | Thread.sleep(15000); 33 | } catch (Exception ex) {} 34 | finally { 35 | System.out.printf("VirtualThread %s woke up\n", name); 36 | } 37 | }); 38 | 39 | // Virtual thread does not count as a thread 40 | System.out.println("Number of threads: " + Thread.activeCount()); 41 | 42 | Thread.sleep(60000); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /java-14/HelpfulNPEMessages.java: -------------------------------------------------------------------------------- 1 | import static java.util.stream.Collectors.toList; 2 | 3 | import java.util.stream.IntStream; 4 | 5 | /** 6 | * To run: `java -XX:+ShowCodeDetailsInExceptionMessages HelpfulNPEMessages.java` 7 | */ 8 | public class HelpfulNPEMessages { 9 | public static void main(String[] args) { 10 | simpleObjectAccess(); 11 | insideStreams(); 12 | } 13 | 14 | private static void simpleObjectAccess() { 15 | System.out.println("=== Simple Object Attribute Access ==="); 16 | try { 17 | var thing = new Thing(11); 18 | System.out.println("Value " + thing.weight.value); 19 | } catch (NullPointerException ex) { 20 | ex.printStackTrace(); 21 | } 22 | } 23 | 24 | private static void insideStreams() { 25 | System.out.println("%n=== Attribute Access Inside Streams ==="); 26 | try { 27 | IntStream.of(2, 4, 6, 8, 9) 28 | .mapToObj(Thing::new) 29 | .map(thing -> thing.weight.value) 30 | .forEach(v -> System.out.println("Val " + v)); 31 | } catch (NullPointerException ex) { 32 | ex.printStackTrace(); 33 | } 34 | } 35 | } 36 | 37 | class Thing { 38 | Weight weight; 39 | 40 | Thing(int weight) { 41 | if (weight % 2 == 0) { 42 | this.weight = new Weight(weight); 43 | } 44 | } 45 | 46 | public Weight getWeight() { 47 | return weight; 48 | } 49 | } 50 | 51 | class Weight { 52 | Integer value; 53 | 54 | Weight(int value) { 55 | if (value % 2 == 0) { 56 | this.value = value; 57 | } 58 | } 59 | 60 | public int getValue() { 61 | return value; 62 | } 63 | } -------------------------------------------------------------------------------- /java-19/SwitchWithPatternMatchingThirdPreview.java: -------------------------------------------------------------------------------- 1 | import java.time.LocalDate; 2 | import java.time.YearMonth; 3 | import java.time.ZoneOffset; 4 | import java.time.temporal.ChronoUnit; 5 | import java.util.stream.Stream; 6 | 7 | /** 8 | * This preview changed `&&` to `when` in guarded clause. 9 | * 10 | * Run: `java --enable-preview --source 19 SwitchWithPatternMatchingThirdPreview.java` 11 | */ 12 | public class SwitchWithPatternMatchingThirdPreview { 13 | public static void main(String[] args) { 14 | System.out.println(stringify(42)); 15 | System.out.println(stringify(-42)); 16 | System.out.println(stringify("Some text")); 17 | System.out.println(stringify("")); 18 | System.out.println(stringify(null)); 19 | } 20 | 21 | static String stringify(Object value) { 22 | return switch (value) { 23 | // the constant must be before the guarded pattern (otherwise it will never hit) 24 | case Integer i when i == 42 -> "42 is the answer"; 25 | case Integer i when i > 0 -> "positive number"; 26 | case Integer i when i < 0 -> "negative number"; 27 | // this must be after because it will match all integers 28 | case Integer i -> "should be 0"; 29 | 30 | case String s when s.isEmpty() -> "empty string"; 31 | case String s when s.length() > 50 -> "long string"; 32 | // this must be after because it will match all strings 33 | case String s -> "non-empty string"; 34 | // same here 35 | case CharSequence cs -> "any other CharSequence"; 36 | 37 | case null -> "null =s"; 38 | default -> "unhandled type"; 39 | }; 40 | } 41 | } -------------------------------------------------------------------------------- /java-21/StringTemplateCustomProcessorExample.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * To run: `java --enable-preview --source 21 StringTemplateCustomProcessorExample.java` 4 | */ 5 | public class StringTemplateCustomProcessorExample { 6 | 7 | public static void main(String[] args) { 8 | usingClass(); 9 | usingLambda(); 10 | usingStaticFactoryMethod(); 11 | } 12 | 13 | static void usingClass() { 14 | class StringNullSanitizer implements StringTemplate.Processor { 15 | public String process(StringTemplate st) { 16 | return interpolate(st); 17 | } 18 | } 19 | 20 | System.out.println(new StringNullSanitizer()."Test null: \{null}"); 21 | } 22 | 23 | static void usingLambda() { 24 | // lambda we must define the type 25 | StringTemplate.Processor STR_NULL_SANITIZER = StringTemplateCustomProcessorExample::interpolate; 26 | System.out.println(STR_NULL_SANITIZER."Test null: \{null}"); 27 | } 28 | 29 | static void usingStaticFactoryMethod() { 30 | var STR_NULL_SANITIZER = StringTemplate.Processor.of(StringTemplateCustomProcessorExample::interpolate); 31 | System.out.println(STR_NULL_SANITIZER."Test null: \{null}"); 32 | } 33 | 34 | static String interpolate(StringTemplate st) { 35 | var sb = new StringBuilder(); 36 | var fragments = st.fragments().iterator(); 37 | for (Object value : st.values()) { 38 | sb.append(fragments.next()); 39 | if (value == null) { 40 | sb.append(""); 41 | } else { 42 | sb.append(value); 43 | } 44 | } 45 | sb.append(fragments.next()); 46 | return sb.toString(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /java-21/StructuredConcurrencyWithSubtaskExample.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.ExecutionException; 2 | import java.util.concurrent.Executors; 3 | import java.util.concurrent.*; 4 | import static java.util.concurrent.StructuredTaskScope.Subtask; 5 | 6 | /** 7 | * To run: `java --source 21 --enable-preview StructuredConcurrencyWithSubtaskExample.java` 8 | */ 9 | public class StructuredConcurrencyWithSubtaskExample { 10 | public static void main(String[] args) throws Exception { 11 | var message = new StructuredConcurrencyWithSubtaskExample().parallelSearch("42"); 12 | System.out.println(message); 13 | } 14 | 15 | private String parallelSearch(String userId) throws InterruptedException, ExecutionException { 16 | try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { 17 | // JDK 21: changed `fork` to return `Subtask` instead of `Future` 18 | Subtask userName = scope.fork(() -> this.findName(userId)); 19 | Subtask answer = scope.fork(() -> this.findPower(userId)); 20 | 21 | scope.join(); 22 | scope.throwIfFailed(); 23 | 24 | // `Subtask::get` behaves like `Future::resultNow` 25 | return "The real name of '%s' is '%s' and its power is %s".formatted(userId, userName.get(), answer.get()); 26 | } 27 | } 28 | 29 | private String findName(String userId) { 30 | System.out.println("Searching name for user ID: " + userId); 31 | return "Thomas Anderson"; 32 | } 33 | 34 | private String findPower(String userId) { 35 | System.out.println("Calculating power for user ID: " + userId); 36 | try { 37 | Thread.sleep(3000); 38 | } catch (Exception ex) {} 39 | return "Over 9000"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /java-23/FlexibleConstructorBodiesExample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To run: `java --enable-preview --source 23 FlexibleConstructorBodiesExample.java` 3 | */ 4 | public class FlexibleConstructorBodiesExample { 5 | 6 | public static void main(String[] args) { 7 | System.out.println("Pet:\n" + new Dog("Shih Tzu")); 8 | } 9 | } 10 | 11 | abstract class Animal { 12 | protected final String domain; 13 | protected final String kingdom; 14 | protected final String phylum; 15 | protected final String subphylum; 16 | protected final String phylumClass; 17 | protected final String family; 18 | 19 | private final String representation; 20 | 21 | protected Animal(String phylum, String subphylum, String phylumClass, String family) { 22 | this.domain = "Eukaryota"; 23 | this.kingdom = "Animalia"; 24 | this.phylum = phylum; 25 | this.subphylum = subphylum; 26 | this.phylumClass = phylumClass; 27 | this.family = family; 28 | 29 | this.representation = getClassification(); 30 | } 31 | 32 | public abstract String getClassification(); 33 | 34 | public String toString() { 35 | return this.representation; 36 | } 37 | } 38 | 39 | class Dog extends Animal { 40 | private final String order; 41 | private final String species; 42 | private final String breed; 43 | 44 | Dog(String breed) { 45 | this.order = "Carnivora"; 46 | this.species = "Dog"; 47 | this.breed = breed; 48 | super("Chordata", "Vertebrata", "Mammals", "Canidae"); 49 | } 50 | 51 | public String getClassification() { 52 | return "Domain: %s / Kingdom: %s / Phylum: %s / Subphylum: %s / Class: %s / Order: %s/ Species: %s / Breed: %s".formatted( 53 | domain, kingdom, phylum, subphylum, phylumClass, order, species, breed 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/lambdas/scope/ShadowingTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.lambdas.scope; 2 | 3 | public class ShadowingTest { 4 | 5 | int x = 23; 6 | 7 | // the lambda expression does not introduce a new level of scoping (it is an anonymous class) 8 | public void doStuff(int x) { 9 | 10 | // x = 298; 11 | // the above line generates error because the lambda expression can only directly access fields, methods, and 12 | // local variables or parameters that are final or effectively final (was not changed in anywhere else of method) 13 | // of the enclosing scope (like anonymous class). 14 | 15 | // Note for Runnable interface: for method arguments, the compiler determines the target type with two other 16 | // language features: overload resolution and type argument inference 17 | Thread t = new Thread(() -> { 18 | // this lambda expression has the scope of doStuff() method, so 19 | // int x = 32; cannot define because the parameter x from doStuff() is considered local 20 | System.out.println("ShadowingTest.this.x = " + ShadowingTest.this.x); 21 | System.out.println("this.x = " + this.x); // use ShadowingTest.this.x 22 | System.out.println("x = " + x); 23 | int y = 530; // this new var is only visible in this anonymous method 24 | System.out.println("y = " + y); 25 | }); 26 | 27 | // x = 116; // here also will gerenate a error because x must be final or effectively final (not modified) 28 | 29 | t.start(); 30 | int y = 3; // so we can define another var with the same name 31 | System.out.println("y = " + y); 32 | } 33 | 34 | public static void main(String[] args) { 35 | ShadowingTest c = new ShadowingTest(); 36 | c.doStuff(30); 37 | } 38 | } -------------------------------------------------------------------------------- /java-9/others-features/src/main/java/com/github/wesleyegberto/collections/reactive/FlowTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.collections.reactive; 2 | 3 | import java.util.concurrent.Flow; 4 | import java.util.concurrent.Flow.Subscriber; 5 | import java.util.concurrent.Flow.Subscription; 6 | import java.util.concurrent.SubmissionPublisher; 7 | import java.util.stream.IntStream; 8 | 9 | public class FlowTest { 10 | public static void main(String[] args) throws InterruptedException { 11 | try (SubmissionPublisher publisher = new SubmissionPublisher<>()) { 12 | publisher.subscribe(new MySubscriber()); 13 | 14 | IntStream.range(0, 15) 15 | .mapToObj(String::valueOf) 16 | .forEach(publisher::submit); 17 | } 18 | Thread.sleep(10000); 19 | } 20 | } 21 | 22 | class MySubscriber implements Subscriber { 23 | private Subscription subscription; 24 | 25 | @Override 26 | public void onComplete() { 27 | System.out.println("Completed"); 28 | } 29 | 30 | @Override 31 | public void onError(Throwable err) { 32 | System.out.println("Error: " + err.getMessage()); 33 | } 34 | 35 | @Override 36 | public void onNext(String item) { 37 | System.out.println("Next: " + item); 38 | requestItem(subscription); 39 | } 40 | 41 | @Override 42 | public void onSubscribe(Subscription subscription) { 43 | this.subscription = subscription; 44 | requestItem(subscription); 45 | } 46 | 47 | private void requestItem(Subscription subscription) { 48 | System.out.println("Subscribed, requesting 1 items..."); 49 | subscription.request(1); 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /java-18/CodeSnippetInJavaDoc.java: -------------------------------------------------------------------------------- 1 | /** 2 | * To generate the javadoc: 3 | * `javadoc -d code-snippets-doc CodeSnippetInJavaDoc.java` 4 | */ 5 | public class CodeSnippetInJavaDoc { 6 | /** 7 | * The @snippet will render something like this: 8 | * 9 | *
10 | 	 * // sum two numbers
11 | 	 * int sum = MathOperationBuilder.builder()
12 | 	 *     .withA(...)
13 | 	 *     .withB(...)
14 | 	 *     .sum();
15 | 	 * {@link System#out System.out}.println(sum);
16 | 	 * 
17 | */ 18 | public void methodWithSimpleDoc() { 19 | } 20 | 21 | /** 22 | * Builder to help execute math operation =). 23 | * Usage: 24 | * {@snippet : 25 | * // sum two numbers 26 | * int sum = MathOperationBuilder.builder() // @highlight substring="builder" 27 | * .withA(1) // @replace regex="\d+" replacement="..." 28 | * .withB(2) // @replace regex="\d+" replacement="..." 29 | * .sum(); // @highlight substring="sum" 30 | * System.out.println(sum); // @link substring="System.out" target="System#out" 31 | * } 32 | */ 33 | public MathOperationBuilder methodWithSnippetDoc() { 34 | return new MathOperationBuilder(); 35 | } 36 | 37 | static class MathOperationBuilder { 38 | private int a; 39 | private int b; 40 | 41 | public MathOperationBuilder withA(int a) { 42 | this.a = a; 43 | return this; 44 | } 45 | 46 | public MathOperationBuilder withB(int b) { 47 | this.b = b; 48 | return this; 49 | } 50 | 51 | public int sum() { 52 | return a + b; 53 | } 54 | 55 | public int subtract() { 56 | return a - b; 57 | } 58 | 59 | public int multiply() { 60 | return a * b; 61 | } 62 | 63 | public int divide() { 64 | return a / b; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /java-25/FlexibleConstructorBodiesExample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To run: `java FlexibleConstructorBodiesExample.java` 3 | */ 4 | public class FlexibleConstructorBodiesExample { 5 | 6 | public static void main(String[] args) { 7 | System.out.println("Pet:\n" + new Dog("Shih Tzu")); 8 | } 9 | } 10 | 11 | abstract class Animal { 12 | protected final String domain; 13 | protected final String kingdom; 14 | protected final String phylum; 15 | protected final String subphylum; 16 | protected final String phylumClass; 17 | protected final String family; 18 | 19 | private final String representation; 20 | 21 | protected Animal(String phylum, String subphylum, String phylumClass, String family) { 22 | this.domain = "Eukaryota"; 23 | this.kingdom = "Animalia"; 24 | this.phylum = phylum; 25 | this.subphylum = subphylum; 26 | this.phylumClass = phylumClass; 27 | this.family = family; 28 | 29 | this.representation = getClassification(); 30 | } 31 | 32 | public abstract String getClassification(); 33 | 34 | public String toString() { 35 | return this.representation; 36 | } 37 | } 38 | 39 | class Dog extends Animal { 40 | private final String order; 41 | private final String species; 42 | private final String breed; 43 | 44 | Dog(String breed) { 45 | // we can perform validation (fail fast) 46 | if (breed == null || breed.isBlank()) { 47 | throw new IllegalArgumentException("Breed cannot be null or empty"); 48 | } 49 | this.order = "Carnivora"; 50 | this.species = "Dog"; 51 | this.breed = breed; 52 | super("Chordata", "Vertebrata", "Mammals", "Canidae"); 53 | } 54 | 55 | public String getClassification() { 56 | return "Domain: %s / Kingdom: %s / Phylum: %s / Subphylum: %s / Class: %s / Order: %s/ Species: %s / Breed: %s".formatted( 57 | domain, kingdom, phylum, subphylum, phylumClass, order, species, breed 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /java-25/FlexibleConstructorBodiesInnerClassExample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To run: `java FlexibleConstructorBodiesInnerClassExample .java` 3 | */ 4 | public class FlexibleConstructorBodiesInnerClassExample { 5 | public static void main(String[] args) { 6 | var e1 = new Example1(); 7 | var i1 = e1.new Inner1(); 8 | 9 | var e2 = new Example2(); 10 | 11 | var e3 = Example3.VALUE_3; 12 | } 13 | } 14 | 15 | class Base { 16 | Base() { 17 | System.out.println("Base constructor"); 18 | } 19 | } 20 | 21 | class Example1 { 22 | private int counter; 23 | 24 | void hello() { 25 | System.out.println("Hello from Example1"); 26 | } 27 | 28 | class Inner1 extends Base { 29 | Inner1() { 30 | // allowed cause when a new instance is created, the outer already exists 31 | Example1.this.counter++; 32 | hello(); 33 | super(); 34 | System.out.println("Inner1 constructor"); 35 | } 36 | } 37 | 38 | Example1() { 39 | // Error: cannot reference this before supertype constructor has been called 40 | // new Inner1(); 41 | 42 | super(); 43 | } 44 | } 45 | 46 | class Example2 { 47 | static class Inner2 extends Base { 48 | Inner2() { 49 | System.out.println("Inner2 constructor"); 50 | } 51 | } 52 | 53 | Example2() { 54 | System.out.println("Example2 constructor"); 55 | new Inner2(); 56 | super(); 57 | } 58 | } 59 | 60 | enum Example3 { 61 | VALUE_1(1), VALUE_2(2), VALUE_3(3); 62 | 63 | private final int value; 64 | private final int valueSquared; 65 | 66 | Example3(int v, int vSquared) { 67 | System.out.printf("Enum - %d ^ 2 = %d%n", v, vSquared); 68 | this.value = v; 69 | this.valueSquared = vSquared; 70 | } 71 | 72 | Example3(int v) { 73 | var vv = v * v; 74 | this(v, vv); 75 | } 76 | 77 | public int getValue() { 78 | return value; 79 | } 80 | 81 | public int getValueSquared() { 82 | return valueSquared; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /java-22/StatementsBeforeSuperInnerClassExamples.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To run: `java --enable-preview --source 22 StatementsBeforeSuperInnerClassExamples.java` 3 | */ 4 | public class StatementsBeforeSuperInnerClassExamples { 5 | public static void main(String[] args) { 6 | var e1 = new Example1(); 7 | var i1 = e1.new Inner1(); 8 | 9 | var e2 = new Example2(); 10 | 11 | var e3 = Example3.VALUE_3; 12 | } 13 | } 14 | 15 | class Base { 16 | Base() { 17 | System.out.println("Base constructor"); 18 | } 19 | } 20 | 21 | class Example1 { 22 | private int counter; 23 | 24 | void hello() { 25 | System.out.println("Hello from Example1"); 26 | } 27 | 28 | class Inner1 extends Base { 29 | Inner1() { 30 | // allowed cause when a new instance is created, the outer already exists 31 | Example1.this.counter++; 32 | hello(); 33 | super(); 34 | System.out.println("Inner1 constructor"); 35 | } 36 | } 37 | 38 | Example1() { 39 | // Error: cannot reference this before supertype constructor has been called 40 | // new Inner1(); 41 | 42 | super(); 43 | } 44 | } 45 | 46 | class Example2 { 47 | static class Inner2 extends Base { 48 | Inner2() { 49 | System.out.println("Inner2 constructor"); 50 | } 51 | } 52 | 53 | Example2() { 54 | System.out.println("Example2 constructor"); 55 | new Inner2(); 56 | super(); 57 | } 58 | } 59 | 60 | enum Example3 { 61 | VALUE_1(1), VALUE_2(2), VALUE_3(3); 62 | 63 | private final int value; 64 | private final int valueSquared; 65 | 66 | Example3(int v, int vSquared) { 67 | System.out.printf("Enum - %d ^ 2 = %d%n", v, vSquared); 68 | this.value = v; 69 | this.valueSquared = vSquared; 70 | } 71 | 72 | Example3(int v) { 73 | var vv = v * v; 74 | this(v, vv); 75 | } 76 | 77 | public int getValue() { 78 | return value; 79 | } 80 | 81 | public int getValueSquared() { 82 | return valueSquared; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /java-14/PatternMatchingForInstanceOf.java: -------------------------------------------------------------------------------- 1 | public class PatternMatchingForInstanceOf { 2 | public static void main(String[] args) { 3 | Animal dog1 = new Dog("Bob"); 4 | Animal c = new Cat(); 5 | 6 | // Old verbose way 7 | if (dog1 instanceof Dog) { 8 | // A cast just to manipulate the specific type 9 | Dog d1 = (Dog) dog1; 10 | play(d1); 11 | } 12 | 13 | // New way 14 | if (dog1 instanceof Dog d1) { 15 | play(d1); 16 | } 17 | if (c instanceof Cat c1) { 18 | play(c1); 19 | } 20 | 21 | Animal dog2 = new Dog("Bob"); 22 | System.out.println("\nAre both equal? " + dog1.equals(dog2)); 23 | } 24 | 25 | static void play(Dog d) { 26 | System.out.println("Playing with Dog..."); 27 | d.makeSound(); 28 | } 29 | 30 | static void play(Cat c) { 31 | System.out.println("Playing with Cat..."); 32 | c.makeSound(); 33 | } 34 | } 35 | 36 | class Animal { 37 | void makeSound() { 38 | System.out.println("Generic sound"); 39 | } 40 | } 41 | 42 | class Cat extends Animal { 43 | void makeSound() { 44 | System.out.println("Miau"); 45 | } 46 | } 47 | 48 | class Dog extends Animal { 49 | // here we assume that are equal when they have the same name 50 | private String name; 51 | 52 | Dog(String name) { 53 | this.name = name; 54 | } 55 | 56 | void makeSound() { 57 | System.out.println("Au au"); 58 | } 59 | 60 | /* 61 | * Old way where we need to cast after the `instanceof`. 62 | */ 63 | public boolean equalsOldWay(Object o) { 64 | // need to check if is the same type 65 | if (!(o instanceof Dog)) 66 | return false; 67 | // then we cast to work with this type 68 | Dog d1 = (Dog) o; 69 | // only now we can performe our [business] logic to compare 70 | return d1.name.equals(d1.name); 71 | } 72 | 73 | public boolean equals(Object o) { 74 | // more straightforward 75 | return (o instanceof Dog d1) 76 | && d1.name.equals(d1.name); 77 | } 78 | } -------------------------------------------------------------------------------- /java-20/RecordPatternsSecondPreviewTest.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | import java.util.ArrayList; 3 | 4 | /** 5 | * To run: `java --enable-preview --source 20 RecordsPatternSecondPreviewTest.java` 6 | */ 7 | public class RecordPatternsSecondPreviewTest { 8 | public static void main(String[] args) { 9 | enhancedForLoop(); 10 | 11 | genericInferrenceTest(); 12 | 13 | recordPatternInEnhancedForLoopHeader(); 14 | } 15 | 16 | public static void enhancedForLoop() { 17 | var points = new Point[] { 18 | new Point(10, 10), 19 | new Point(20, 20), 20 | new Point(30, 30), 21 | new Point(20, 50), 22 | new Point(10, 60) 23 | }; 24 | 25 | // we can now deconstruct a record type in the enhanced for loop 26 | for (Point(int x, int y) : points) { 27 | System.out.printf("Drawing at x=%d and y=%d%n", x, y); 28 | } 29 | } 30 | 31 | public static void genericInferrenceTest() { 32 | var point = new Point(42, 42); 33 | var decoratedPoint = new Decorator(new ColoredPoint(point, "RED")); 34 | var anotherDecorated = new Decorator(decoratedPoint); 35 | 36 | // here we don't need to use `Decorator>(Decorator(ColoredPoint cp))` like in JDK 19 37 | if (anotherDecorated instanceof Decorator(Decorator(ColoredPoint(Point(int x, int y), String color)))) { 38 | System.out.println("\nAren't you using too much decorator?"); 39 | System.out.printf("x=%d, y=%d; color=%s%n%n", x, y, color); 40 | } 41 | } 42 | 43 | static void recordPatternInEnhancedForLoopHeader() { 44 | var items = new ColoredPoint[] { new ColoredPoint(new Point(42, 42), "red") }; 45 | 46 | for (ColoredPoint(Point(var x, var y), String color) : items) { 47 | System.out.printf("Point [%d, %d] has color %s", x, y, color); 48 | } 49 | } 50 | } 51 | 52 | record Point(int x, int y) {} 53 | 54 | record ColoredPoint(Point p, String color) {} 55 | 56 | record Decorator(T t) {} 57 | 58 | -------------------------------------------------------------------------------- /java-17/PseudoRandomNumberGeneratorTest.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.util.random.*; 3 | 4 | /** 5 | * Splittable algorithms: 6 | * - L32X64MixRandom 7 | * - L32X64StarStarRandom 8 | * - L64X128MixRandom 9 | * - L64X128StarStarRandom 10 | * - L64X256MixRandom 11 | * - L64X1024MixRandom 12 | * - L128X128MixRandom 13 | * - L128X256MixRandom 14 | * - L128X1024MixRandom 15 | * 16 | * Jumpable algorithms: 17 | * - Xoroshiro128PlusPlus 18 | * - Xoshiro256PlusPlus 19 | */ 20 | public class PseudoRandomNumberGeneratorTest { 21 | private static long SEED = 42L; 22 | 23 | public static void main(String[] args) { 24 | testJumpableRandom(); 25 | testSplittableRandom(); 26 | } 27 | 28 | private static void testJumpableRandom() { 29 | RandomGenerator.JumpableGenerator gen = (RandomGenerator.JumpableGenerator) RandomGeneratorFactory.of("Xoroshiro128PlusPlus").create(SEED); 30 | 31 | Map numbers = new HashMap<>(); 32 | for (int i = 0; i < 10000; i++) { 33 | var n = gen.nextLong(100); 34 | if (numbers.containsKey(n)) 35 | numbers.computeIfPresent(n, (key, val) -> val + 1); 36 | else 37 | numbers.put(n, 1L); 38 | 39 | if (i % 100 == 0) 40 | gen.jump(); 41 | } 42 | 43 | numbers.entrySet().forEach(entry -> System.out.println(entry.getKey() + " -> " + entry.getValue())); 44 | } 45 | 46 | private static void testSplittableRandom() { 47 | RandomGenerator.SplittableGenerator gen = (RandomGenerator.SplittableGenerator) RandomGeneratorFactory.of("L32X64MixRandom").create(SEED); 48 | 49 | Map numbers = new HashMap<>(); 50 | for (int i = 0; i < 10000; i++) { 51 | var n = gen.nextLong(100); 52 | if (numbers.containsKey(n)) 53 | numbers.computeIfPresent(n, (key, val) -> val + 1); 54 | else 55 | numbers.put(n, 1L); 56 | } 57 | 58 | numbers.entrySet().forEach(entry -> System.out.println(entry.getKey() + " -> " + entry.getValue())); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /java-25/StructuredConcurrencyWithScopedValueExample.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.*; 2 | import java.util.concurrent.StructuredTaskScope.Joiner; 3 | import java.util.concurrent.StructuredTaskScope.Subtask; 4 | import javax.management.RuntimeErrorException; 5 | 6 | /** 7 | * To run: `java --source 25 --enable-preview StructuredConcurrencyWithScopedValueExample.java` 8 | */ 9 | public class StructuredConcurrencyWithScopedValueExample { 10 | private final static ScopedValue USER_ID = ScopedValue.newInstance(); 11 | 12 | public static void main(String[] args) { 13 | new StructuredConcurrencyWithScopedValueExample().run(); 14 | } 15 | 16 | public void run() { 17 | try { 18 | var result = ScopedValue.where(USER_ID, "neo").call(this::parallelHandle); 19 | System.out.println(result); 20 | } catch (Exception ex) { 21 | ex.printStackTrace(); 22 | } 23 | } 24 | 25 | private String parallelHandle() throws InterruptedException, ExecutionException { 26 | // when we create a scope, the scoped values are captured 27 | try (var scope = StructuredTaskScope.open()) { 28 | // the child scopes can use its parent's scoped value bindings 29 | Subtask userName = scope.fork(this::findUserName); 30 | Subtask answer = scope.fork(this::findPower); 31 | 32 | scope.join(); 33 | 34 | return "The real name of '%s' is '%s' and its power is %s" 35 | .formatted(USER_ID.get(), userName.get(), answer.get()); 36 | } 37 | } 38 | 39 | private String findUserName() { 40 | var userId = USER_ID.get(); 41 | System.out.println("Searching name for user ID: " + userId); 42 | try { 43 | Thread.sleep(500); 44 | } catch (Exception ex) {} 45 | return userId; 46 | } 47 | 48 | private String findPower() { 49 | var userId = USER_ID.get(); 50 | System.out.println("Calculating power for user ID: " + userId); 51 | try { 52 | Thread.sleep(3000); 53 | } catch (Exception ex) {} 54 | return "Over 9000"; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /java-19/Fibonacci.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.Executor; 2 | import java.util.concurrent.CompletableFuture; 3 | import java.util.concurrent.CompletionStage; 4 | import java.net.URI; 5 | import java.net.http.HttpRequest; 6 | import java.net.http.HttpClient; 7 | import java.time.Duration; 8 | import java.io.IOException; 9 | import java.net.http.HttpClient; 10 | import java.net.http.HttpRequest; 11 | import java.net.http.HttpResponse; 12 | import java.net.http.HttpResponse.BodyHandlers; 13 | 14 | /** 15 | * fib of 47 takes ~11s 16 | * fib of 49 fakes ~30s 17 | */ 18 | public class Fibonacci { 19 | public static long fib(int n) { 20 | if (n <= 2) 21 | return 1; 22 | return fib(n - 1) + fib(n - 2); 23 | } 24 | 25 | public static CompletableFuture parallelFib(int n, Executor executor) { 26 | CompletableFuture partOne = CompletableFuture.supplyAsync(() -> fib(n - 1), executor); 27 | CompletableFuture partTwo = CompletableFuture.supplyAsync(() -> fib(n - 2), executor); 28 | return partOne.thenCombineAsync(partTwo, (resultOne, resultTwo) -> resultOne + resultTwo, executor); 29 | } 30 | 31 | public static CompletableFuture fibWithRequest(int i, int n, Executor executor) { 32 | return CompletableFuture.supplyAsync(() -> fib(n), executor) 33 | .thenComposeAsync(result -> { 34 | var request = HttpRequest.newBuilder() 35 | .GET() 36 | .uri(URI.create("https://httpbin.org/delay/5")) 37 | .build(); 38 | var httpClient = HttpClient.newBuilder() 39 | .version(HttpClient.Version.HTTP_1_1) 40 | .connectTimeout(Duration.ofSeconds(30)) 41 | .executor(executor) 42 | .build(); 43 | try { 44 | System.out.printf("Thread %d - requesting%n", i); 45 | return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()) 46 | .thenApplyAsync(resp -> result); 47 | } catch (Exception ex) { 48 | throw new RuntimeException(ex); 49 | } 50 | }, executor); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /java-12/README.md: -------------------------------------------------------------------------------- 1 | # Java 12 2 | 3 | To run each example use: `java --enable-preview --source 12 ` 4 | 5 | ## JEPs 6 | 7 | * [12](https://openjdk.java.net/jeps/12) - Preview language and VM features 8 | * [189](https://openjdk.java.net/jeps/189) - Low-Pause-Time GC (experimental) 9 | * [230](https://openjdk.java.net/jeps/230) - Microbenchmark Suite 10 | * [325](https://openjdk.java.net/jeps/325) - Switch expressions (preview) 11 | * [334](https://openjdk.java.net/jeps/334) - JVM Constants API 12 | * [340](https://openjdk.java.net/jeps/340) - One AArch64 13 | * [341](https://openjdk.java.net/jeps/341) - Default CDS Archives 14 | * [344](https://openjdk.java.net/jeps/344) - Abortable mixed collections for G1 15 | * [345](https://openjdk.java.net/jeps/346) - Promptly return unused memory from G1 16 | 17 | ## Features 18 | 19 | * Switch Expression (preview) 20 | * Compact Number Format 21 | * `Collectors.teeing` 22 | * More Versatile Error Recovery With CompletableFuture 23 | * `exceptionallyAsync(Function f)` 24 | * `exceptionallyAsync(Function f, Executor e)` 25 | * `exceptionallyCompose(Function> f)` 26 | * `exceptionallyComposeAsync(Function> f)` 27 | * `exceptionallyComposeAsync(Function> f, Executor e)` 28 | 29 | ### JVM 30 | 31 | * Default CDS Archives 32 | * `-Xshare:off` to disable it 33 | * Garbage Collection 34 | * Shenandoah: Red Hat low-pause-time GC, experimental; 35 | * G1: improvements and promptly returns unused memory SO; 36 | 37 | ## Links 38 | 39 | * [Java 12 Documentation](https://docs.oracle.com/en/java/javase/12/index.html) 40 | * [Java 12 Guide](https://blog.codefx.org/java/java-12-guide/) 41 | * [Should you adopt Java 12 or stick on Java 11?](https://blog.joda.org/2018/10/adopt-java-12-or-stick-on-11.html) 42 | * [Shenandoah GC](https://wiki.openjdk.java.net/display/shenandoah/Main) 43 | -------------------------------------------------------------------------------- /java-20/StructuredConcurrencyWithScopedValue.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.ExecutionException; 2 | import java.util.concurrent.Executors; 3 | import java.util.concurrent.Future; 4 | 5 | import javax.management.RuntimeErrorException; 6 | 7 | import jdk.incubator.concurrent.*; 8 | 9 | /** 10 | * To run: `java --source 20 --enable-preview --add-modules jdk.incubator.concurrent StructuredConcurrencyWithScopedValue.java` 11 | */ 12 | public class StructuredConcurrencyWithScopedValue { 13 | private final static ScopedValue USER_ID = ScopedValue.newInstance(); 14 | 15 | public static void main(String[] args) { 16 | new StructuredConcurrencyWithScopedValue().run(); 17 | } 18 | 19 | public void run() { 20 | try { 21 | var result = ScopedValue.where(USER_ID, "neo").call(this::parallelHandle); 22 | System.out.println(result); 23 | } catch (Exception ex) { 24 | ex.printStackTrace(); 25 | } 26 | } 27 | 28 | private String parallelHandle() throws InterruptedException, ExecutionException { 29 | // when we create a scope, the scoped values are captured 30 | try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { 31 | // the child scopes can use its parent's scoped value bindings 32 | Future userName = scope.fork(this::findUserName); 33 | Future answer = scope.fork(this::findPower); 34 | 35 | scope.join(); 36 | scope.throwIfFailed(); 37 | 38 | var userId = USER_ID.get(); 39 | return "The real name of '%s' is '%s' and its power is %s".formatted(userId, userName.resultNow(), answer.resultNow()); 40 | } 41 | } 42 | 43 | private String findUserName() { 44 | var userId = USER_ID.get(); 45 | System.out.println("Searching name for user ID: " + userId); 46 | return userId; 47 | } 48 | 49 | private String findPower() { 50 | var userId = USER_ID.get(); 51 | System.out.println("Calculating power for user ID: " + userId); 52 | try { 53 | Thread.sleep(3000); 54 | } catch (Exception ex) {} 55 | return "Over 9000"; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/map/StreamMapTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.map; 2 | 3 | import java.util.*; 4 | import java.util.stream.Stream; 5 | import java.util.function.Function; // map operations -> transformations 6 | 7 | import com.github.wesleyegberto.model.Person; 8 | import com.github.wesleyegberto.model.Warrior; 9 | 10 | public class StreamMapTest { 11 | 12 | public static void main(String[] args) { 13 | List persons = Person.getList(); 14 | 15 | System.out.println("Map operation using anonymous inner class: "); 16 | Stream warriors = persons.stream() 17 | .filter(p -> p.getAge() > 20 && p.getAge() < 40) 18 | // the Function uses two type arguments to use at apply() method: 19 | // the first is the type of argument and the second is the return type 20 | .map(new Function() { // Person -> parameter type, Warrior -> return type 21 | @Override 22 | public Warrior apply(Person person) { 23 | return new Warrior(person); 24 | } 25 | }); 26 | warriors.forEach((w) -> System.out.println(w)); 27 | 28 | 29 | System.out.println("\nMap operation using lambda syntax: "); 30 | warriors = persons.stream() 31 | .filter(p -> p.getAge() > 20 && p.getAge() < 40) 32 | // a simple lambda that call the Warrior's constructor 33 | .map(person -> new Warrior(person)); // here the lambda expression (anonymous method) is passed as an argument 34 | warriors.forEach((w) -> System.out.println(w)); 35 | 36 | 37 | System.out.println("\nMap operation using lambda syntax using the method reference: "); 38 | warriors = persons.stream() 39 | .filter(p -> p.getAge() > 20 && p.getAge() < 40) 40 | // the compiler will figure out which is the type of arg to construct and will use each element from the list 41 | .map(Warrior::new); // :new is a method reference to constructor (used instead of a simple lambda to call the constructor) 42 | warriors.forEach((w) -> System.out.println(w)); 43 | 44 | 45 | } 46 | } -------------------------------------------------------------------------------- /java-13/README.md: -------------------------------------------------------------------------------- 1 | # Java 13 2 | 3 | To run each example use: `java --enable-preview --source 13 ` 4 | 5 | ## JEPs 6 | 7 | * [354](https://openjdk.java.net/jeps/354) - Switch expression (preview 2) 8 | * [355](https://openjdk.java.net/jeps/355) - Text blocks (preview) 9 | * [350](https://openjdk.java.net/jeps/350) - Dynamic CDS Archives 10 | * [351](https://openjdk.java.net/jeps/351) - ZGC: Uncommit Unused Memory 11 | * [353](https://openjdk.java.net/jeps/353) - Reimplement the Legacy Socket API 12 | 13 | ## Features 14 | 15 | * **Switch Expressions (second preview)** 16 | * Changed `break` from Java 12 to `yield` 17 | * **Text Blocks (preview)** 18 | * flag to compile: `-Xlint:text-blocks` 19 | * **Reimplement Legacy Socket API** 20 | * `Socket` and `ServerSocket` reimplementation (alignment to [Project Loom](https://openjdk.java.net/projects/loom/)) 21 | 22 | ### API 23 | 24 | * String methods: 25 | * `stripIdent`: same operation done by the compiler to strip incidental identation from text block'; 26 | * `translateEscapes`: same operation done by the compiler to translate escapes in strings; 27 | * `formatted`: shortcut to String.format '`"%s years old".formatted(42)`) 28 | * NIO improvements 29 | 30 | ### JVM 31 | 32 | * Creating Class-Data archives For AppCDS 33 | * flag to java `-XX:ArchiveClassesAtExit=` to generate class-data on exit 34 | * run with it: `-XX:SharedArchiveFile=` 35 | * ZGC (Oracle's Z GC) returns unused memory to SO 36 | * `-XX:ZUncommitDelay=` to set the delay in seconds 37 | * `-XX:SoftMaxHeapSize`: soft (won't generate OutOfMemoryError - will request more) limit to avoid the JVM to grow in memory 38 | 39 | ## Links 40 | 41 | * [Java 13 Documentation](https://docs.oracle.com/en/java/javase/13/index.html) 42 | * [Java 13 Guide](https://blog.codefx.org/java/java-13-guide/) 43 | * [Switch Expression](https://blog.codefx.org/java/switch-expressions/) 44 | * [Text Block Guid](http://cr.openjdk.java.net/~jlaskey/Strings/TextBlocksGuide_v9.html) 45 | 46 | -------------------------------------------------------------------------------- /java-8/src/main/java/com/github/wesleyegberto/api/datetime/ClockTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wesleyegberto.api.datetime; 2 | 3 | import java.time.Clock; 4 | import java.time.Duration; 5 | import java.time.LocalDate; 6 | import java.time.LocalDateTime; 7 | import java.time.LocalTime; 8 | import java.time.ZoneId; 9 | import java.time.ZonedDateTime; 10 | 11 | /** 12 | * @author Wesley Egberto 13 | */ 14 | public class ClockTest { 15 | public static void main(String[] args) { 16 | Clock currentClock = Clock.systemUTC(); 17 | System.out.println("Instant = " + currentClock.instant()); 18 | System.out.println("Ms = " + currentClock.millis()); 19 | 20 | // Without time 21 | LocalDate localDate = LocalDate.now(); 22 | LocalDate clockDate = LocalDate.now(currentClock); 23 | 24 | System.out.println("localDate = " + localDate); 25 | System.out.println("clockDate = " + clockDate); 26 | 27 | // Without date 28 | LocalTime localTime = LocalTime.now(); 29 | LocalTime clockTime = LocalTime.now(currentClock); 30 | 31 | System.out.println("localTime = " + localTime); 32 | System.out.println("clockTime = " + clockTime); 33 | 34 | // Without Time-Zone 35 | LocalDateTime localDateTime = LocalDateTime.now(); 36 | LocalDateTime clockDateTime = LocalDateTime.now(currentClock); 37 | 38 | System.out.println("localDateTime = " + localDateTime); 39 | System.out.println("clockDateTime = " + clockDateTime); 40 | 41 | // Zoned Date Time 42 | ZonedDateTime zonedDateTime = ZonedDateTime.now(); 43 | ZonedDateTime clockZoned = ZonedDateTime.now(currentClock); 44 | ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now(ZoneId.of("America/Los_Angeles")); 45 | 46 | System.out.println("zonedDateTime = " + zonedDateTime); 47 | System.out.println("clockZoned = " + clockZoned); 48 | System.out.println("zonedDatetimeFromZone = " + zonedDatetimeFromZone); 49 | 50 | final Duration duration = Duration.between(zonedDateTime, zonedDatetimeFromZone); 51 | System.out.println("Duration in nanos: " + duration.toNanos()); 52 | System.out.println("Duration in millis: " + duration.toMillis()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /java-15/SealedTypesExample.java: -------------------------------------------------------------------------------- 1 | /** 2 | * To run: `java --enable-preview --source 15 SealedTypesExample.java` 3 | */ 4 | public class SealedTypesExample { 5 | public static void main(String[] args) { 6 | // get something from somewhere 7 | var player = new Player(); 8 | var entity = player.getCollidingEntity(); 9 | 10 | if (entity instanceof Player p) { 11 | player.move(); 12 | p.move(); 13 | } else if (entity instanceof Enemy e) { 14 | player.kill(e); 15 | } else if (entity instanceof SceneryObject o) { 16 | o.move(); 17 | } 18 | // we dont need to do this (nor ifs) - because we restricted the implementations types (we know them) 19 | // else { 20 | // throw IllegalStateException("Unexpected entity"); 21 | // } 22 | } 23 | } 24 | 25 | /** 26 | * Sealed types will help us to restrict which types can extend/implement a type. 27 | * Will allow us to write less verbose polymorphic code. 28 | * 29 | * Constraints: 30 | * - The sealed class and its permitted subclasses must belong to the same module, and, if declared in an unnamed module, the same package. 31 | * - Every permitted subclass must directly extend the sealed class. 32 | * - Every permitted subclass must choose a modifier to describe how it continues the sealing initiated by its superclass: 33 | * - `final` 34 | * - `sealed` 35 | * - `non-sealed` (back to a normal class open to extensibility) 36 | */ 37 | sealed abstract class GameEntity permits Player, Enemy, SceneryObject { 38 | public void move() { 39 | System.out.println("Moving"); 40 | } 41 | 42 | public void destroy() { 43 | System.out.println("Destroying"); 44 | } 45 | } 46 | 47 | final class Player extends GameEntity { 48 | /** 49 | * Returns the entity which is colling with the player. 50 | */ 51 | public GameEntity getCollidingEntity() { 52 | // obscure logic 53 | return new Enemy(); 54 | } 55 | 56 | public void kill(GameEntity killedBy) { 57 | // obscure death 58 | System.out.println("Killing"); 59 | } 60 | } 61 | 62 | final class Enemy extends GameEntity {} 63 | 64 | non-sealed class SceneryObject extends GameEntity {} 65 | -------------------------------------------------------------------------------- /java-24/StreamGatherersBuiltin.java: -------------------------------------------------------------------------------- 1 | import static java.util.stream.Collectors.toList; 2 | import java.util.stream.Stream; 3 | import java.util.stream.Gatherer; 4 | import java.util.stream.Gatherers; 5 | 6 | /* 7 | * To run: `java StreamGatherersBuiltin.java` 8 | */ 9 | public class StreamGatherersBuiltin { 10 | public static void main(String[] args) { 11 | System.out.println("=== Fold ==="); 12 | fold(); 13 | System.out.println("=== Scan ==="); 14 | scan(); 15 | System.out.println("=== Window Fixed ==="); 16 | windowFixed(); 17 | System.out.println("=== Window Sliding ==="); 18 | windowSliding(); 19 | System.out.println("=== Map Concurrent ==="); 20 | mapConcurrent(); 21 | } 22 | 23 | static void fold() { 24 | var sum = generate(10) 25 | .gather( 26 | Gatherers.fold(() -> 0, (acc, elem) -> acc + elem) 27 | ) 28 | .findFirst() 29 | .get(); 30 | System.out.println("The sum of all elements: " + sum); 31 | } 32 | 33 | static void scan() { 34 | var sums = generate(10) 35 | .gather( 36 | Gatherers.scan(() -> 0, (acc, elem) -> acc + elem) 37 | ) 38 | .collect(toList()); 39 | System.out.println("The sum of each element with its previous: " + sums); 40 | } 41 | 42 | static void windowFixed() { 43 | var pairs = generate(10) 44 | .gather( 45 | Gatherers.windowFixed(2) 46 | ) 47 | .collect(toList()); 48 | System.out.println("Pair of elements: " + pairs); 49 | } 50 | 51 | static void windowSliding() { 52 | var neighbors = generate(10) 53 | .gather( 54 | Gatherers.windowSliding(2) 55 | ) 56 | .collect(toList()); 57 | System.out.println("Elements that are neighbor: " + neighbors); 58 | } 59 | 60 | static void mapConcurrent() { 61 | // mapConcurrent uses VirtualThreads 62 | // preserves the ordering of the stream 63 | var first10thSquares = generate(50) 64 | .gather(Gatherers.mapConcurrent(5, elem -> elem * elem)) 65 | .collect(toList()); 66 | System.out.println("First 50th squares: " + first10thSquares); 67 | } 68 | 69 | static Stream generate(int size) { 70 | return Stream.iterate(1, acc -> acc + 1).limit(size); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /java-18/SimpleWebServer.java: -------------------------------------------------------------------------------- 1 | import com.sun.net.httpserver.*; 2 | import java.net.*; 3 | import java.io.*; 4 | import java.nio.file.*; 5 | import java.util.function.Predicate; 6 | 7 | /** 8 | * To run from the terminal we can use the utility command-line tool: 9 | * `jwebserver -b 0.0.0.0 -p 8080` 10 | * 11 | * The API only supports GET and HEAD requests, but we can added manual support with `HttpHandlers.handleOrElse`. 12 | * 13 | * Doc: https://download.java.net/java/early_access/jdk18/docs/api/jdk.httpserver/com/sun/net/httpserver/SimpleFileServer.html 14 | */ 15 | public class SimpleWebServer { 16 | private static final String SERVER_DIR = System.getProperty("user.dir"); 17 | 18 | public static void main(String[] args) { 19 | var server = SimpleFileServer.createFileServer( 20 | new InetSocketAddress(8080), 21 | Path.of(SERVER_DIR), 22 | SimpleFileServer.OutputLevel.VERBOSE 23 | ); 24 | 25 | var defaultHandler = HttpHandlers.of(404, new Headers(), "Not found"); 26 | 27 | Predicate IS_POST = req -> "POST".equals(req.getRequestMethod()); 28 | 29 | var postHandler = HttpHandlers.handleOrElse( 30 | IS_POST, 31 | (exchange) -> { 32 | System.out.println("Handling POST request"); 33 | 34 | System.out.println("Headers:"); 35 | exchange.getRequestHeaders().forEach((k, v) -> System.out.printf("\t%s: %s\n", k, v)); 36 | 37 | InputStream requestBody = exchange.getRequestBody(); 38 | try (var reader = new BufferedReader(new InputStreamReader(requestBody))) { 39 | System.out.println("\nBody:"); 40 | reader.lines().forEach(line -> System.out.printf("\t%s", line)); 41 | } catch (RuntimeException | IOException ex) { 42 | System.err.println("Error reading request body: " + ex.getMessage()); 43 | } 44 | 45 | var responseBody = "POST handled successfully".getBytes(); 46 | exchange.sendResponseHeaders(200, responseBody.length); 47 | exchange.getResponseBody().write(responseBody); 48 | }, 49 | defaultHandler 50 | ); 51 | server.createContext("/post", postHandler); 52 | 53 | server.start(); 54 | System.out.println("Server started at " + server.getAddress()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /java-24/ClassFileApiReadingExample.java: -------------------------------------------------------------------------------- 1 | import java.lang.classfile.*; 2 | import java.lang.classfile.constantpool.ClassEntry; 3 | import java.lang.constant.*; 4 | import java.nio.file.Files; 5 | import java.nio.file.Paths; 6 | import java.util.stream.Collectors; 7 | 8 | /** 9 | * Run: `javac BasicClass.java && java ClassFileApiReadingExample.java` 10 | */ 11 | public class ClassFileApiReadingExample { 12 | public static void main(String[] args) throws Exception { 13 | var className = "BasicClass.class"; 14 | // var className = "HelloWorldFromClassFile.class"; 15 | 16 | var classBytes = Files.readAllBytes(Paths.get(className)); 17 | 18 | // ClassModel is an immutable description of a class file 19 | ClassModel cm = ClassFile.of().parse(classBytes); 20 | 21 | // ClassModel is lazy, iterating over it parses the entire class 22 | for (ClassElement ce : cm) { 23 | // possible values: https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/classfile/ClassElement.html 24 | switch (ce) { 25 | case Superclass cn -> System.out.println("Superclass: " + cn.superclassEntry().name().stringValue()); 26 | 27 | case Interfaces i -> { 28 | var interfaces = i.interfaces().stream() 29 | .map(ClassEntry::name) 30 | .collect(Collectors.joining(",")); 31 | System.out.println("Interfaces: " + interfaces); 32 | } 33 | 34 | // ClassModel.fields() 35 | case FieldModel fm -> { 36 | var fieldType = fm.fieldTypeSymbol().displayName(); 37 | var fieldName = fm.fieldName().stringValue(); 38 | System.out.printf("Field: %s %s%n", fieldType, fieldName); 39 | } 40 | 41 | // ClassModel.methods() 42 | case MethodModel mm -> { 43 | var symbol = mm.methodTypeSymbol(); 44 | var returnType = symbol.returnType().displayName(); 45 | var parameters = symbol.parameterList().stream() 46 | .map(ClassDesc::displayName) 47 | .collect(Collectors.joining(",")); 48 | var methodName = mm.methodName().stringValue(); 49 | System.out.printf("Method: %s %s(%s)%n", returnType, methodName, parameters); 50 | } 51 | default -> System.out.printf("Other: %s%n", ce); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /java-20/ScopedValueUsageExample.java: -------------------------------------------------------------------------------- 1 | import jdk.incubator.concurrent.*; 2 | 3 | /** 4 | * Run: `java --source 20 --enable-preview --add-modules jdk.incubator.concurrent ScopedValueUsageExample.java` 5 | */ 6 | public class ScopedValueUsageExample { 7 | final static ScopedValue MAIN_SCOPE = ScopedValue.newInstance(); 8 | 9 | public static void main(String[] args) { 10 | System.out.println("Starting scoped value"); 11 | 12 | // we can share a value from here 13 | ScopedValue.where(MAIN_SCOPE, "message from main") 14 | .run(() -> { 15 | var worker = new Worker(); 16 | worker.execute(); 17 | }); 18 | System.out.println("main ending"); 19 | } 20 | } 21 | 22 | class Worker { 23 | final static ScopedValue WORKER_SCOPE = ScopedValue.newInstance(); 24 | 25 | public void execute() { 26 | // accessing the value from the scope 27 | System.out.println("shared value from main: " + ScopedValueUsageExample.MAIN_SCOPE.get()); 28 | 29 | // === Nested Scope === 30 | // we can create a nested scope 31 | ScopedValue.where(WORKER_SCOPE, "message from worker") 32 | .run(() -> { 33 | // the outmost scope will still works 34 | var messageFromMain = ScopedValueUsageExample.MAIN_SCOPE.get(); 35 | var messageFromWorker = WORKER_SCOPE.get(); 36 | System.out.println("shared value to inner scope from main: " + messageFromMain); 37 | System.out.println("shared value to inner scope from worker: " + messageFromWorker); 38 | }); 39 | 40 | // we cannot access it from outside its scope (NoSuchElementException) 41 | // var invalidAccess = WORKER_SCOPE.get(); 42 | 43 | // === Rebinded Scope Value === 44 | // we can create a new scope that rebinds a new value to the created scope (when using the same variable) 45 | ScopedValue.where(ScopedValueUsageExample.MAIN_SCOPE, "message from worker over main") 46 | .run(() -> { 47 | // the outmost scope will still works 48 | var rebindedMessage = ScopedValueUsageExample.MAIN_SCOPE.get(); 49 | System.out.println("shared value from shadowed scope: " + rebindedMessage); 50 | }); 51 | 52 | // but the original scope from main will still have its initial value (immutable) 53 | System.out.println("shared value from main after all scopes: " + ScopedValueUsageExample.MAIN_SCOPE.get()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /java-25/StructuredConcurrencyExample.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.*; 2 | import java.util.concurrent.StructuredTaskScope.Joiner; 3 | import java.util.concurrent.StructuredTaskScope.Subtask; 4 | import java.util.concurrent.StructuredTaskScope.FailedException; 5 | import static java.util.concurrent.StructuredTaskScope.Subtask; 6 | 7 | /** 8 | * To run: `java --source 25 --enable-preview StructuredConcurrencyWithSubtaskExample.java` 9 | */ 10 | public class StructuredConcurrencyWithSubtaskExample { 11 | public static void main(String[] args) throws Exception { 12 | var message = new StructuredConcurrencyWithSubtaskExample().parallelSearch("42"); 13 | System.out.println(message); 14 | } 15 | 16 | private String parallelSearch(String userId) throws InterruptedException, ExecutionException { 17 | // now we use static factory method `StructuredTaskScope.open` to create a scope 18 | // we can pass different policy from `Joiner` to control the behavior of the scope 19 | // default policy of `open()` is `Joiner.allSuccessfulOrThrow()` 20 | try (var scope = StructuredTaskScope.open()) { 21 | // JDK 21: changed `fork` to return `Subtask` instead of `Future` 22 | Subtask userName = scope.fork(() -> this.findName(userId)); 23 | Subtask answer = scope.fork(() -> this.findPower(userId)); 24 | 25 | // don't need to call `scope.throwIfFailed()` because now we have policy 26 | // return null when using default policy or throws a `FailedException` 27 | scope.join(); 28 | 29 | // `Subtask::get` behaves like `Future::resultNow` 30 | return "The real name of '%s' is '%s' and its power is %s".formatted(userId, userName.get(), answer.get()); 31 | } catch (FailedException ex) { 32 | return "Failure: " + ex.getMessage(); 33 | } 34 | } 35 | 36 | private String findName(String userId) { 37 | System.out.println("Searching name for user ID: " + userId); 38 | try { 39 | Thread.sleep(500); 40 | } catch (Exception ex) {} 41 | if ("13".equals(userId)) { 42 | throw new RuntimeException("User unlucky"); 43 | } 44 | return "Thomas Anderson"; 45 | } 46 | 47 | private String findPower(String userId) { 48 | System.out.println("Calculating power for user ID: " + userId); 49 | try { 50 | Thread.sleep(3000); 51 | } catch (Exception ex) {} 52 | return "Over 9000"; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /java-22/StreamGatherersBuiltin.java: -------------------------------------------------------------------------------- 1 | import static java.util.stream.Collectors.toList; 2 | import java.util.stream.Stream; 3 | import java.util.stream.Gatherer; 4 | import java.util.stream.Gatherers; 5 | 6 | /* 7 | * To run: `java --enable-preview --source 22 StreamGatherersBuiltin.java` 8 | */ 9 | public class StreamGatherersBuiltin { 10 | public static void main(String[] args) { 11 | System.out.println("=== Peek ==="); 12 | peek(); 13 | System.out.println("=== Fold ==="); 14 | fold(); 15 | System.out.println("=== Scan ==="); 16 | scan(); 17 | System.out.println("=== Window Fixed ==="); 18 | windowFixed(); 19 | System.out.println("=== Window Sliding ==="); 20 | windowSliding(); 21 | } 22 | 23 | static void peek() { 24 | System.out.print("Elements: "); 25 | var elements = generate(10).collect(toList()); 26 | System.out.println(elements); 27 | /* 28 | * Shows in [Javadoc](https://cr.openjdk.org/~vklang/gatherers/api/java.base/java/util/stream/Gatherers.html#peek(java.util.function.Consumer)) 29 | * but seems not implemented yet. 30 | generate(10) 31 | .gather( 32 | Gatherers.peek(elem -> System.out.printf("%s ")) 33 | ) 34 | .collect(toList()); 35 | System.out.println(); 36 | */ 37 | } 38 | 39 | static void fold() { 40 | var sum = generate(10) 41 | .gather( 42 | Gatherers.fold(() -> 0, (acc, elem) -> acc + elem) 43 | ) 44 | .findFirst() 45 | .get(); 46 | System.out.println("The sum of all elements: " + sum); 47 | } 48 | 49 | static void scan() { 50 | var sums = generate(10) 51 | .gather( 52 | Gatherers.scan(() -> 0, (acc, elem) -> acc + elem) 53 | ) 54 | .collect(toList()); 55 | System.out.println("The sum of each element with its previous: " + sums); 56 | } 57 | 58 | static void windowFixed() { 59 | var pairs = generate(10) 60 | .gather( 61 | Gatherers.windowFixed(2) 62 | ) 63 | .collect(toList()); 64 | System.out.println("Pair of elements: " + pairs); 65 | } 66 | 67 | static void windowSliding() { 68 | var neighbors = generate(10) 69 | .gather( 70 | Gatherers.windowSliding(2) 71 | ) 72 | .collect(toList()); 73 | System.out.println("Elements that are neighbor: " + neighbors); 74 | } 75 | 76 | static Stream generate(int size) { 77 | return Stream.iterate(1, acc -> acc + 1).limit(size); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /java-14/JFREventStreamTest.java: -------------------------------------------------------------------------------- 1 | import java.time.Duration; 2 | import java.util.stream.IntStream; 3 | import java.util.ArrayList; 4 | 5 | import jdk.jfr.consumer.RecordingStream; 6 | 7 | /*** 8 | * The profiles configurations is stored in: `$JAVA_HOME/lib/jrf/` 9 | */ 10 | public class JFREventStreamTest { 11 | public static void main(String[] args) throws InterruptedException { 12 | var task = new FibonacciCalculator(Thread.currentThread()); 13 | 14 | var thread = new Thread(task, "t-fib"); 15 | thread.start(); 16 | 17 | try (var rs = new RecordingStream()) { 18 | rs.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1)); 19 | rs.enable("jdk.GarbageCollection").withPeriod(Duration.ofSeconds(1)); 20 | rs.enable("jdk.GCHeapSummary").withPeriod(Duration.ofSeconds(1)); 21 | 22 | rs.onEvent("jdk.CPULoad", event -> { 23 | System.out.printf("\tCPU load: %f%% - %f%%%n", 24 | (event.getFloat("jvmUser") * 100), 25 | (event.getFloat("machineTotal") * 100) 26 | ); 27 | }); 28 | rs.onEvent("jdk.GCHeapSummary", event -> { 29 | System.out.printf("\tGC - Summary - %s %f MB%n", 30 | event.getString("when"), 31 | (event.getFloat("heapUsed") / 1_000_000) 32 | ); 33 | 34 | }); 35 | rs.onEvent("jdk.GarbageCollection", event -> { 36 | System.out.printf("\tGC - Cause %s - Durantion: %.04fms%n", event.getString("cause"), (event.getFloat("duration") / 1_000_000)); 37 | }); 38 | rs.startAsync(); 39 | 40 | thread.join(); 41 | } 42 | 43 | } 44 | } 45 | 46 | class FibonacciCalculator implements Runnable { 47 | private Thread thread; 48 | 49 | FibonacciCalculator(Thread thread) { 50 | this.thread = thread; 51 | } 52 | 53 | public void run() { 54 | System.out.println("Starting calculation"); 55 | int number = 40; 56 | while (true) { 57 | System.out.println("Calculating for " + number); 58 | var result = calculate(number); 59 | System.out.println("Result for " + number + " is " + result); 60 | if (!thread.isAlive()) { 61 | System.out.println("Ending calculation"); 62 | break; 63 | } 64 | 65 | number += 5; 66 | } 67 | } 68 | 69 | /** 70 | * Bad implementation to take much time. 71 | */ 72 | public long calculate(int n) { 73 | if (n <= 1) 74 | return 1; 75 | var list = new ArrayList<>(n); 76 | IntStream.range(0, n).forEach(__ -> list.add(new Object())); 77 | return calculate(n - 1) + calculate(n - 2); 78 | } 79 | } -------------------------------------------------------------------------------- /java-21/ScopedValueUsageExample.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.*; 2 | 3 | /** 4 | * Using JDK manually built from main branch. 5 | * 6 | * The only change from JDK 20 is the package to import 7 | * (we no longer need to use add-module jdk.incubator.concurrent). 8 | * 9 | * **Not released in the build yet** 10 | * Run: `java --source 21 --enable-preview ScopedValueUsageExample.java` 11 | */ 12 | public class ScopedValueUsageExample { 13 | final static ScopedValue MAIN_SCOPE = ScopedValue.newInstance(); 14 | 15 | public static void main(String[] args) { 16 | System.out.println("Starting scoped value"); 17 | 18 | // we can share a value from here 19 | ScopedValue.where(MAIN_SCOPE, "message from main") 20 | .run(() -> { 21 | var worker = new Worker(); 22 | worker.execute(); 23 | }); 24 | System.out.println("main ending"); 25 | } 26 | } 27 | 28 | class Worker { 29 | final static ScopedValue WORKER_SCOPE = ScopedValue.newInstance(); 30 | 31 | public void execute() { 32 | // accessing the value from the scope 33 | System.out.println("shared value from main: " + ScopedValueUsageExample.MAIN_SCOPE.get()); 34 | 35 | // === Nested Scope === 36 | // we can create a nested scope 37 | ScopedValue.where(WORKER_SCOPE, "message from worker") 38 | .run(() -> { 39 | // the outmost scope will still works 40 | var messageFromMain = ScopedValueUsageExample.MAIN_SCOPE.get(); 41 | var messageFromWorker = WORKER_SCOPE.get(); 42 | System.out.println("shared value to inner scope from main: " + messageFromMain); 43 | System.out.println("shared value to inner scope from worker: " + messageFromWorker); 44 | }); 45 | 46 | // we cannot access it from outside its scope (NoSuchElementException) 47 | // var invalidAccess = WORKER_SCOPE.get(); 48 | 49 | // === Rebinded Scope Value === 50 | // we can create a new scope that rebinds a new value to the created scope (when using the same variable) 51 | ScopedValue.where(ScopedValueUsageExample.MAIN_SCOPE, "message from worker over main") 52 | .run(() -> { 53 | // the outmost scope will still works 54 | var rebindedMessage = ScopedValueUsageExample.MAIN_SCOPE.get(); 55 | System.out.println("shared value from shadowed scope: " + rebindedMessage); 56 | }); 57 | 58 | // but the original scope from main will still have its initial value (immutable) 59 | System.out.println("shared value from main after all scopes: " + ScopedValueUsageExample.MAIN_SCOPE.get()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /projects/valhalla/PrimitiveClassSharingReferencesExample.java: -------------------------------------------------------------------------------- 1 | /** 2 | * To run: `javac -XDenablePrimitiveClasses --source 20 --target 20 PrimitiveClassSharingReferencesExample.java && java -XX:+EnablePrimitiveClasses PrimitiveClassSharingReferencesExample` 3 | */ 4 | public class PrimitiveClassSharingReferencesExample { 5 | public static void main(String[] args) { 6 | testPrimitiveValues(); 7 | } 8 | 9 | static void testPrimitiveValues() { 10 | // Point.default is loaded with the class 11 | log("Default value reference (%s): %s", Point.default.toNotation(), Point.default); 12 | 13 | // the object is shared like in a pool when the fields have the same value 14 | var origin = new Point(0, 0); 15 | log("Origin %s value reference: %s", origin.toNotation(), origin); 16 | 17 | log("Is origin equals to default value? " + (origin == Point.default)); 18 | 19 | log("Are two new instances with same field values equals? %s", new Point(2, 2), new Point(2, 2)); 20 | log("[1;1] value reference: %s", new Point(1, 1)); 21 | var point = origin.translate(1, 1); 22 | log("%s value reference: %s", point.toNotation(), point); 23 | 24 | var rect1 = new Rectangle(new Point(10, 50), new Point(50, 30), true, "RED"); 25 | var rect2 = new Rectangle(new Point(10, 50), new Point(50, 30), true, "RED"); 26 | log("Is equals? %b", (rect1 == rect2)); 27 | // when the field has a new object 28 | var rect3 = new Rectangle(new Point(10, 50), new Point(50, 30), true, new String("RED")); 29 | log("Is equals even with new String? %b", (rect1 == rect3)); 30 | } 31 | 32 | static void log(String message, Object ...args) { 33 | System.out.printf(message + "%n", args); 34 | } 35 | } 36 | 37 | primitive class Point { 38 | private int x; 39 | private int y; 40 | 41 | public Point(int x, int y) { 42 | this.x = x; 43 | this.y = y; 44 | } 45 | 46 | public int x() { 47 | return this.x; 48 | } 49 | 50 | public int y() { 51 | return this.y; 52 | } 53 | 54 | public Point translate(int dx, int dy) { 55 | return new Point (x + dx, y + dy); 56 | } 57 | 58 | public String toNotation() { 59 | return "%d;%d".formatted(x, y); 60 | } 61 | } 62 | 63 | primitive class Rectangle { 64 | private Point upperLeftPoint; 65 | private Point lowerRightPoint; 66 | private boolean fill; 67 | private String color; 68 | 69 | public Rectangle(Point ul, Point lr, boolean fill, String color) { 70 | this.upperLeftPoint = ul; 71 | this.lowerRightPoint = lr; 72 | this.fill = fill; 73 | this.color = color; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /java-24/StreamGatherersExamples.java: -------------------------------------------------------------------------------- 1 | import static java.util.stream.Collectors.toList; 2 | import java.util.LinkedList; 3 | import java.util.List; 4 | import java.util.Set; 5 | import java.util.TreeSet; 6 | import java.util.stream.Stream; 7 | import java.util.stream.Gatherer; 8 | import java.util.stream.Gatherers; 9 | 10 | /* 11 | * To run: `java StreamGatherersExamples.java` 12 | */ 13 | public class StreamGatherersExamples { 14 | public static void main(String[] args) { 15 | deduplicateStream(); 16 | filterIfHasAtLeastFiveEvenNumbers(); 17 | } 18 | 19 | static void deduplicateStream() { 20 | var uniques = Stream.of(1, 2, 5, 8, 1, 9, 3, 5, 4, 8, 7, 3) 21 | .gather(deduplicate()) 22 | .collect(toList()); 23 | System.out.println("Unique elements: " + uniques); 24 | } 25 | 26 | static Gatherer, Integer> deduplicate() { 27 | return Gatherer.ofSequential( 28 | // initializer: start the state with a Set 29 | () -> new TreeSet<>(), 30 | // integrator: only add if doesn't exists in the set 31 | Gatherer.Integrator.ofGreedy((state, element, downstream) -> { 32 | if (state.contains(element)) { 33 | // ask for the next element if the downstream is on 34 | return !downstream.isRejecting(); 35 | } 36 | state.add(element); 37 | // pushes downstream and ask for more if the downstream is on 38 | return downstream.push(element); 39 | }) 40 | ); 41 | } 42 | 43 | static void filterIfHasAtLeastFiveEvenNumbers() { 44 | var list = Stream.generate(() -> (int) (Math.random() * 10) + 1) 45 | .limit(10) 46 | .gather(filterAtLeastFiveEvenNumbers()) 47 | .collect(toList()); 48 | if (list.isEmpty()) 49 | System.out.println("There were not enough even numbers"); 50 | else 51 | System.out.println("Even numbers: " + list); 52 | } 53 | 54 | static Gatherer, Integer> filterAtLeastFiveEvenNumbers() { 55 | return Gatherer.of( 56 | // initializer: start a new list 57 | LinkedList::new, 58 | // integrator: only add if it is an even number, also increments 59 | (state, element, downstream) -> { 60 | if (element % 2 == 0) { 61 | state.add(element); 62 | } 63 | return !downstream.isRejecting(); 64 | }, 65 | // combiner: merge the parallel gathering 66 | (leftState, rightState) -> { 67 | leftState.addAll(rightState); 68 | return leftState; 69 | }, 70 | // finisher: only pushes if has at least five even numbers 71 | (state, downstream) -> { 72 | if (state.size() < 5) { 73 | return; 74 | } 75 | state.forEach(i -> { 76 | downstream.push(i); 77 | }); 78 | } 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /java-22/StreamGatherersExamples.java: -------------------------------------------------------------------------------- 1 | import static java.util.stream.Collectors.toList; 2 | import java.util.LinkedList; 3 | import java.util.List; 4 | import java.util.Set; 5 | import java.util.TreeSet; 6 | import java.util.stream.Stream; 7 | import java.util.stream.Gatherer; 8 | import java.util.stream.Gatherers; 9 | 10 | /* 11 | * To run: `java --enable-preview --source 22 StreamGatherersExamples.java` 12 | */ 13 | public class StreamGatherersExamples { 14 | public static void main(String[] args) { 15 | deduplicateStream(); 16 | filterIfHasAtLeastFiveEvenNumbers(); 17 | } 18 | 19 | static void deduplicateStream() { 20 | var uniques = Stream.of(1, 2, 5, 8, 1, 9, 3, 5, 4, 8, 7, 3) 21 | .gather(deduplicate()) 22 | .collect(toList()); 23 | System.out.println("Unique elements: " + uniques); 24 | } 25 | 26 | static Gatherer, Integer> deduplicate() { 27 | return Gatherer.ofSequential( 28 | // initializer: start the state with a Set 29 | () -> new TreeSet<>(), 30 | // integrator: only add if doesn't exists in the set 31 | Gatherer.Integrator.ofGreedy((state, element, downstream) -> { 32 | if (state.contains(element)) { 33 | // ask for the next element if the downstream is on 34 | return !downstream.isRejecting(); 35 | } 36 | state.add(element); 37 | // pushes downstream and ask for more if the downstream is on 38 | return downstream.push(element); 39 | }) 40 | ); 41 | } 42 | 43 | static void filterIfHasAtLeastFiveEvenNumbers() { 44 | var list = Stream.generate(() -> (int) (Math.random() * 10) + 1) 45 | .limit(10) 46 | .gather(filterAtLeastFiveEvenNumbers()) 47 | .collect(toList()); 48 | if (list.isEmpty()) 49 | System.out.println("There were not enough even numbers"); 50 | else 51 | System.out.println("Even numbers: " + list); 52 | } 53 | 54 | static Gatherer, Integer> filterAtLeastFiveEvenNumbers() { 55 | return Gatherer.of( 56 | // initializer: start a new list 57 | LinkedList::new, 58 | // integrator: only add if it is an even number, also increments 59 | (state, element, downstream) -> { 60 | if (element % 2 == 0) { 61 | state.add(element); 62 | } 63 | return !downstream.isRejecting(); 64 | }, 65 | // combiner: merge the parallel gathering 66 | (leftState, rightState) -> { 67 | leftState.addAll(rightState); 68 | return leftState; 69 | }, 70 | // finisher: only pushes if has at least five even numbers 71 | (state, downstream) -> { 72 | if (state.size() < 5) { 73 | return; 74 | } 75 | state.forEach(i -> { 76 | downstream.push(i); 77 | }); 78 | } 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /java-18/README.md: -------------------------------------------------------------------------------- 1 | # Java 18 2 | 3 | To run each example use: `java --enable-preview --source 18 ` 4 | 5 | ## JEPs 6 | 7 | * [400](https://openjdk.java.net/jeps/400) - UTF-8 by Default 8 | * [408](https://openjdk.java.net/jeps/408) - Simple Web Server 9 | * [413](https://openjdk.java.net/jeps/413) - Code Snippets in Java API Documentation 10 | * [416](https://openjdk.java.net/jeps/416) - Reimplement Code Reflection with Method Handles 11 | * [417](https://openjdk.java.net/jeps/417) - Vector API (Third Incubator) 12 | * [418](https://openjdk.java.net/jeps/418) - Internet-Address Resolution SPI 13 | * [419](https://openjdk.java.net/jeps/419) - Foreign Function & Memory API (Second Incubator) 14 | * [420](https://openjdk.java.net/jeps/420) - Pattern matching for `switch` (Second Preview) 15 | * [421](https://openjdk.java.net/jeps/421) - Deprecate Finalization for Removal 16 | 17 | ## Features 18 | 19 | * **Chartset UTF-8 by Default** 20 | * to see which is default: `java -XshowSettings:properties -version 2>&1 | grep file.encoding` 21 | * we can change the chartset with property: `-Dfile.encoding=UTF-8` 22 | * affected classes: 23 | * Stream Reader and Writer 24 | * File Reader and Writer 25 | * `Formatter` and `Scanner` 26 | * `URLEncoder` and `URLDecoder` 27 | * the `System.out` and `System.err` will use the same charset from the terminal 28 | * we can see with: `Console.charset()` 29 | * **Pattern Matching for `switch` (second preview)** 30 | * Minor improvements from JDK 17: 31 | * refined to use dominance checking that will force constant case label to appear before a guarded pattern of the same type; 32 | * exhaustiveness checking is now more precise with sealed hierarchies. 33 | * **Code snippet in Java Doc** 34 | * was introduced the `@snippet` tag to help write code fragments in Java docs 35 | * the goals is to provide a way to get this fragments (so it can be validated by other tool), enable syntax highlighting and provide better IDE support 36 | * code snippet suports: 37 | * attributes (key-pair values like `usage="sort"`) 38 | * ID to be referred in others snippets (through `id` attribute) 39 | * language definition (through `lang` attribute) - default is java 40 | * external files (through `file` attribute) - using external file to define the snippets allow us to use everything that Java supports (like comments with `/** */`) 41 | * we can pass `--snippet-path` to `javadoc` tool to define the folders for external snippets 42 | * example: 43 | * ![](img/code-snippet-doc-example.png) 44 | 45 | ### JVM 46 | 47 | * Reimplemented code reflection to use Method Handles 48 | 49 | ## Links 50 | 51 | * [JDK 18 Jeps](https://openjdk.java.net/projects/jdk/18/) 52 | -------------------------------------------------------------------------------- /java-21/StringTemplateExample.java: -------------------------------------------------------------------------------- 1 | import java.time.*; 2 | import java.time.format.DateTimeFormatter; 3 | 4 | /** 5 | * To run: `java --enable-preview --source 21 StringTemplateExample.java` 6 | */ 7 | public class StringTemplateExample { 8 | static Type type = Type.HACKER; 9 | static String firstName = "Thomas"; 10 | static String lastName = "Anderson"; 11 | static String hackerName = "Neo"; 12 | 13 | public static void main(String[] args) { 14 | rawTemplateProcessor(); 15 | simpleTemplate(); 16 | allowedExpressionsInsideEmbeddedTemplate(); 17 | } 18 | 19 | static void rawTemplateProcessor() { 20 | StringTemplate st = StringTemplate.RAW."String template built from RAW template processor: \{firstName}"; 21 | String message = StringTemplate.STR.process(st); 22 | // same as 23 | message = STR."String template built from RAW template processor: \{firstName}"; 24 | System.out.println(message); 25 | } 26 | 27 | static void simpleTemplate() { 28 | // STR template processor returns a string 29 | String str = STR."Simple string template without embedded expression"; 30 | 31 | // we can use template embedded with string literal 32 | System.out.println(STR."Wake up \{hackerName}..."); 33 | 34 | // we can also use template expression with template string 35 | System.out.println(STR.""" 36 | Mr. \{lastName}! Welcome back, we missed you! 37 | """); 38 | 39 | // we can multiline the embedded expression 40 | System.out.println(STR."The time is \{ 41 | DateTimeFormatter 42 | .ofPattern("HH:mm:ss") 43 | .format(LocalTime.now()) 44 | } right now"); 45 | 46 | // we don't need to escape " 47 | System.out.println(STR."Follow the white \{"rabbit"}..."); 48 | } 49 | 50 | // we can use any Java expression 51 | static void allowedExpressionsInsideEmbeddedTemplate() { 52 | boolean isCaptured = true; 53 | 54 | // arithmetic expression 55 | var counter = 0; 56 | System.out.println(STR."Counting... \{++counter}... \{++counter}... \{++counter}..."); 57 | System.out.println(STR."How long has he been arrested? \{4 + 2} hours"); 58 | System.out.println(STR."How long is his name? \{firstName.length() + lastName.length()}"); 59 | 60 | // call method 61 | System.out.println(STR."What was his first program? \{greetings()}"); 62 | 63 | // ternary expression 64 | System.out.println(STR."As you can see Mr. \{ 65 | isCaptured ? lastName : hackerName 66 | }, we've been tracking you..."); 67 | 68 | // switch expression 69 | System.out.println(STR."What is he? \{ 70 | switch (type) { 71 | case HACKER -> "hackerman"; 72 | case PERSON -> "bot"; 73 | } 74 | }"); 75 | } 76 | 77 | static String greetings() { 78 | return "Hello matrix"; 79 | } 80 | } 81 | 82 | enum Type { 83 | HACKER, 84 | PERSON 85 | } 86 | -------------------------------------------------------------------------------- /java-16/UnixDomainSocketTest.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | import java.net.StandardProtocolFamily; 3 | import java.net.UnixDomainSocketAddress; 4 | import java.nio.channels.*; 5 | import java.nio.*; 6 | import java.nio.file.*; 7 | import java.rmi.server.SocketSecurityException; 8 | 9 | public class UnixDomainSocketTest { 10 | private static final String SOCKET_PATH = "server.socket"; 11 | 12 | public static void main(String[] args) throws Exception { 13 | var socketFile = Path.of(System.getProperty("user.home")).resolve(SOCKET_PATH); 14 | var address = UnixDomainSocketAddress.of(socketFile); 15 | 16 | Thread.sleep(500); 17 | new Thread(new ServerProcess(address)).start(); 18 | 19 | Thread.sleep(1000); 20 | new Thread(new ClientProcess(address)).start(); 21 | 22 | Thread.currentThread().join(10_000); 23 | } 24 | } 25 | 26 | class ServerProcess implements Runnable { 27 | private final UnixDomainSocketAddress address; 28 | 29 | ServerProcess(UnixDomainSocketAddress address) { 30 | this.address = address; 31 | } 32 | 33 | public void run() { 34 | try (ServerSocketChannel server = ServerSocketChannel.open(StandardProtocolFamily.UNIX)) { 35 | server.bind(this.address); 36 | 37 | System.out.println("[Server] starting"); 38 | SocketChannel channel = server.accept(); 39 | 40 | System.out.println("[Server] sending message"); 41 | channel.write(ByteBuffer.wrap("Hello client!".getBytes())); 42 | 43 | var buffer = ByteBuffer.allocate(1024); 44 | var length = channel.read(buffer); 45 | if (length > 0) { 46 | System.out.println("[Server] message from client: " + new String(buffer.array())); 47 | } else { 48 | System.out.println("[Server] empty"); 49 | } 50 | channel.close(); 51 | } catch (IOException ex) { 52 | ex.printStackTrace(); 53 | } 54 | } 55 | } 56 | 57 | class ClientProcess implements Runnable { 58 | private final UnixDomainSocketAddress address; 59 | 60 | ClientProcess(UnixDomainSocketAddress address) { 61 | this.address = address; 62 | } 63 | 64 | public void run() { 65 | try (SocketChannel client = SocketChannel.open(StandardProtocolFamily.UNIX)) { 66 | System.out.println("[Client] starting"); 67 | client.connect(this.address); 68 | 69 | System.out.println("[Client] reading message"); 70 | var buffer = ByteBuffer.allocate(1024); 71 | var length = client.read(buffer); 72 | if (length > 0) { 73 | System.out.println("[Client] message from the server: " + new String(buffer.array())); 74 | } else { 75 | System.out.println("[Client] empty"); 76 | } 77 | System.out.println("[Client] sending message"); 78 | client.write(ByteBuffer.wrap("Hello server, I'm your new client!".getBytes())); 79 | } catch (IOException ex) { 80 | ex.printStackTrace(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /java-14/README.md: -------------------------------------------------------------------------------- 1 | # Java 14 2 | 3 | To run each example use: `java --enable-preview --source 14 ` 4 | 5 | ## JEPs 6 | 7 | * [305](https://openjdk.java.net/jeps/305) - Pattern Matching for instanceof (Preview) 8 | * [343](https://openjdk.java.net/jeps/343) - Packaging Tool (Incubator) 9 | * [345](https://openjdk.java.net/jeps/345) - NUMA-Aware Memory Allocation for G1 10 | * [349](https://openjdk.java.net/jeps/349) - JFR Event Streaming 11 | * [352](https://openjdk.java.net/jeps/352) - Non-Volatile Mapped Byte Buffers 12 | * [358](https://openjdk.java.net/jeps/358) - Helpful NullPointerExceptions 13 | * [359](https://openjdk.java.net/jeps/359) - Records (Preview) 14 | * [361](https://openjdk.java.net/jeps/361) - Switch Expressions (Standard) 15 | * [362](https://openjdk.java.net/jeps/362) - Deprecate the Solaris and SPARC Ports 16 | * [363](https://openjdk.java.net/jeps/363) - Remove the Concurrent Mark Sweep (CMS) Garbage Collector 17 | * [364](https://openjdk.java.net/jeps/364) - ZGC on macOS 18 | * [365](https://openjdk.java.net/jeps/365) - ZGC on Windows 19 | * [366](https://openjdk.java.net/jeps/366) - Deprecate the ParallelScavenge + SerialOld GC Combination 20 | * [367](https://openjdk.java.net/jeps/367) - Remove the Pack200 Tools and API 21 | * [368](https://openjdk.java.net/jeps/368) - Text Blocks (Second Preview) 22 | * [370](https://openjdk.java.net/jeps/370) - Foreign-Memory Access API (Incubator) 23 | 24 | ## Features 25 | 26 | * **Switch Expressions** 27 | * Promotion to standard 28 | * **Text Blocks (second preview)** 29 | * added new flags 30 | * **Pattern Matching for `instanceof` (preview)** 31 | * added as Preview 32 | * **Records (preview)** 33 | * added as Preview 34 | * Notes: 35 | * Does not have a `extends` clause, only extends `java.lang.Record`; 36 | * Is implicitly final, thus cannot be extended; 37 | * Cannot declare other fields and cannot contain instance initializers, it only contains its components declared at record header; 38 | * Its components are final and cannot be updated via reflection (throw `IllegalAccessException`); 39 | * Cannot declare native methods; 40 | * Local records is always static (local class and enum as never static). 41 | * **JFR Event Streaming** 42 | * [Here](https://github.com/flight-recorder/health-report) is a great example of a tool built 43 | 44 | ### JVM 45 | 46 | * Helpful NullPointerExpections 47 | * flag to enable: `-XX:+ShowCodeDetailsInExceptionMessages` 48 | * Packaging tool to create self-contained Java applications 49 | * bin: `jpackage` 50 | 51 | ## Links 52 | 53 | * [Java 14 Documentation](https://docs.oracle.com/en/java/javase/14/index.html) 54 | * [Java 14 JEPs](https://openjdk.java.net/projects/jdk/14/) 55 | * [Java Magazine about Java 14](https://blogs.oracle.com/javamagazine/java-14-arrives-with-a-host-of-new-features) 56 | -------------------------------------------------------------------------------- /java-16/README.md: -------------------------------------------------------------------------------- 1 | # Java 16 2 | 3 | To run each example use: `java --enable-preview --source 16 ` 4 | 5 | ## JEPs 6 | 7 | * [338](https://openjdk.java.net/jeps/338) - Vector API (Incubator) 8 | * [347](https://openjdk.java.net/jeps/347) - Enable C++14 Language Features 9 | * [357](https://openjdk.java.net/jeps/357) - Migrate from Mercurial to Git 10 | * [369](https://openjdk.java.net/jeps/369) - Migrate to GitHub 11 | * [376](https://openjdk.java.net/jeps/376) - ZGC: Concurrent Thread-Stack Processing 12 | * [380](https://openjdk.java.net/jeps/380) - Unix-Domain Socket Channels 13 | * [386](https://openjdk.java.net/jeps/386) - Alpine Linux Port 14 | * [387](https://openjdk.java.net/jeps/387) - Elastic Metaspace 15 | * [388](https://openjdk.java.net/jeps/388) - Windows/AArch64 Port 16 | * [389](https://openjdk.java.net/jeps/389) - Foreign Linker API (Incubator) 17 | * [390](https://openjdk.java.net/jeps/390) - Warnings for Value-Based Classes 18 | * [392](https://openjdk.java.net/jeps/392) - Packaging Tool 19 | * [393](https://openjdk.java.net/jeps/393) - Foreign-Memory Access API (Third Incubator) 20 | * [394](https://openjdk.java.net/jeps/394) - Pattern Matching for instanceof 21 | * [395](https://openjdk.java.net/jeps/395) - Records 22 | * [396](https://openjdk.java.net/jeps/396) - Strongly Encapsulate JDK Internals by Default 23 | * [397](https://openjdk.java.net/jeps/397) - Sealed Classes (Second Preview) 24 | 25 | ## Features 26 | 27 | * **Pattern Matching for `instanceof` (standard)** 28 | * **Records** 29 | * now we can declare static class or a record in an inner class 30 | * **Warnings for [Value-Based Classes](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/doc-files/ValueBased.html)** 31 | * starting the preparatives for Project Valhalla (can't wait for it to be fully implemented) 32 | * warning the using value-based classes in synchronization and flag to force an error (1) or log (2) 33 | * flag: `-XX:DiagnoseSyncOnValueBasedClasses=1|2` 34 | * starting with primitive wrappers (but soon might be expanded) 35 | * **Foreign-Memory Access API (third incubator)** 36 | * change in the API 37 | * **Sealed Classes (second preview)** 38 | * `sealed`, `non-sealed` and `permits` became contextual keywords (we can use it as var name or method name) 39 | * **Unix-Domain Socket Channels** 40 | 41 | ### JVM 42 | 43 | * Elastic Metaspace - allow JVM to return unused memory to OS 44 | * flag to customize: `-XX:MetaspaceReclaimPolicy=balanced|aggressive|none` 45 | * Packaging tool promoted to standard 46 | * changing only on flag: `--bind-services` to `--jlink-options` 47 | * Changed default flag for JDK internals: 48 | * now it is `--illegal-access=deny` 49 | 50 | ## Links 51 | 52 | * [JDK 16 Jeps](https://openjdk.java.net/projects/jdk/16/) 53 | * [Valhalla Project](https://openjdk.java.net/projects/valhalla/) 54 | -------------------------------------------------------------------------------- /java-15/README.md: -------------------------------------------------------------------------------- 1 | # Java 15 2 | 3 | To run each example use: `java --enable-preview --source 15 ` 4 | 5 | ## JEPs 6 | 7 | * [339](https://openjdk.java.net/jeps/339) - Edwards-Curve Digital Signature Algorithm (EdDSA) 8 | * [360](https://openjdk.java.net/jeps/360) - Sealed Classes (Preview) 9 | * [371](https://openjdk.java.net/jeps/371) - Hidden Classes 10 | * [372](https://openjdk.java.net/jeps/372) - Remove the Nashorn JavaScript Engine 11 | * [373](https://openjdk.java.net/jeps/373) - Reimplement the Legacy DatagramSocket API 12 | * [374](https://openjdk.java.net/jeps/374) - Disable and Deprecate Biased Locking 13 | * [375](https://openjdk.java.net/jeps/375) - Pattern Matching for instanceof (Second Preview) 14 | * [377](https://openjdk.java.net/jeps/377) - ZGC: A Scalable Low-Latency Garbage Collector 15 | * [378](https://openjdk.java.net/jeps/378) - Text Blocks 16 | * [379](https://openjdk.java.net/jeps/379) - Shenandoah: A Low-Pause-Time Garbage Collector 17 | * [381](https://openjdk.java.net/jeps/381) - Remove the Solaris and SPARC Ports 18 | * [383](https://openjdk.java.net/jeps/383) - Foreign-Memory Access API (Second Incubator) 19 | * [384](https://openjdk.java.net/jeps/384) - Records (Second Preview) 20 | * [385](https://openjdk.java.net/jeps/385) - Deprecate RMI Activation for Removal 21 | 22 | ## Features 23 | 24 | * **Sealed Types** 25 | * Restrict which types can extend/implement a type 26 | * Constraints: 27 | * The sealed class and its permitted subclasses must belong to the same module, and, if declared in an unnamed module, the same package. 28 | * Every permitted subclass must directly extend the sealed class. 29 | * Every permitted subclass must choose a modifier to describe how it continues the sealing initiated by its superclass: 30 | * `final` 31 | * `sealed` 32 | * `non-sealed` (back to a normal class open to extensibility) 33 | * **Pattern Matching for `instanceof` (second preview - no changes)** 34 | * **Text Blocks (standard)** 35 | * **Records (second preview)** 36 | * Integration with sealed types in interfaces 37 | * The combination of record and sealed types is referred as algebraic data types. 38 | 39 | ### JVM 40 | 41 | * GC turned final: 42 | * [Shenandoah](https://wiki.openjdk.java.net/display/shenandoah/Main) 43 | * Flag: `-XX:+UseShenandoahGC` 44 | * [ZGC](https://wiki.openjdk.java.net/display/zgc/Main) 45 | * Flag: `-XX:+UseZGC` 46 | 47 | ## Links 48 | 49 | * [JDK 15 Jeps](https://openjdk.java.net/projects/jdk/15/) 50 | * [Doc about record and sealed types](https://cr.openjdk.java.net/~briangoetz/amber/datum.html) 51 | * [ZGC | What's new in JDK 15](https://malloc.se/blog/zgc-jdk15) 52 | * [Inside Java 15 JEPs in Five Buckets](https://blogs.oracle.com/javamagazine/inside-java-15-fourteen-jeps-in-five-buckets) 53 | * [Programmer's Guide to Text Blocks](https://openjdk.org/projects/amber/guides/text-blocks-guide) 54 | 55 | -------------------------------------------------------------------------------- /java-19/RecordPatternsTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Run: `java --enable-preview --source 19 RecordPatternsTest.java` 3 | */ 4 | public class RecordPatternsTest { 5 | public static void main(String[] args) { 6 | simpleExampleOfDeconstruct(); 7 | 8 | var p1 = new Point(10, 10); 9 | var p2 = new ColoredPoint(new Point(10, 10), Color.GREEN); 10 | 11 | System.out.println("Has collision: " + checkCollisionIfs(p1, p2)); 12 | 13 | System.out.println("Has collision: " + checkCollisionSwitches(p1, p2)); 14 | } 15 | 16 | static void simpleExampleOfDeconstruct() { 17 | record ComputedPoint (int x, int y) { 18 | // the accessor method is used is the deconstruction 19 | public int y() { 20 | return this.y + 10; 21 | } 22 | } 23 | 24 | Object point = new ComputedPoint(42, 42); 25 | 26 | // `int x` will receive the result of implitcy accessor `Point.x()` 27 | // `int y` will receive the result of explicity accesor `Point.y()` 28 | if (point instanceof ComputedPoint(int x, var y)) { 29 | System.out.printf("Deconstruction: x=%d, y=%d%n%n", x, y); 30 | } else { 31 | System.out.println("Not a instance of ComputedPoint"); 32 | } 33 | } 34 | 35 | static boolean checkCollisionIfs(Object p1, Object p2) { 36 | if (p1 instanceof Point(int x1, int y1) && p2 instanceof Point(int x2, int y2)) { 37 | return x1 == x2 && y1 == y2; 38 | } 39 | if (p1 instanceof Point(int x1, int y1) && p2 instanceof ColoredPoint(Point(int x2, int y2), Color c)) { 40 | return x1 == x2 && y1 == y2; 41 | } 42 | if (p1 instanceof ColoredPoint(Point(int x1, int y1), Color c) && p2 instanceof Point(int x2, int y2)) { 43 | return x1 == x2 && y1 == y2; 44 | } 45 | if (p1 instanceof ColoredPoint(Point(int x1, int y1), Color c1) 46 | && p2 instanceof ColoredPoint(Point(int x2, int y2), Color c2)) { 47 | return x1 == x2 && y1 == y2; 48 | } 49 | throw new IllegalArgumentException("Invalid type"); 50 | } 51 | 52 | static boolean checkCollisionSwitches(Object p1, Object p2) { 53 | int x1, y1, x2, y2; 54 | 55 | // Record pattern on switch should be exhaustive (careful with generics on record) 56 | switch (p1) { 57 | case Point(int px1, int py1) -> { 58 | x1 = px1; 59 | y1 = py1; 60 | } 61 | case ColoredPoint(Point(int px1, int py1), Color c) -> { 62 | x1 = px1; 63 | y1 = py1; 64 | } 65 | case null, default -> throw new IllegalArgumentException("Invalid type"); 66 | } 67 | 68 | switch (p2) { 69 | case Point(int px2, int py2) -> { 70 | x2 = px2; 71 | y2 = py2; 72 | } 73 | case ColoredPoint(Point(int px2, int py2), Color c) -> { 74 | x2 = px2; 75 | y2 = py2; 76 | } 77 | case null, default -> throw new IllegalArgumentException("Invalid type"); 78 | } 79 | return x1 == x2 && y1 == y2; 80 | } 81 | } 82 | 83 | record Point(int x, int y) {} 84 | 85 | enum Color { RED, GREEN, BLUE } 86 | 87 | record ColoredPoint(Point p, Color c) {} 88 | 89 | -------------------------------------------------------------------------------- /java-21/RecordPatternTest.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | /** 4 | * To run: `java RecordPatternTest.java` 5 | */ 6 | public class RecordPatternTest { 7 | public static void main(String[] args) { 8 | instanceofExample(); 9 | switchExample(); 10 | genericInferenceTest(); 11 | } 12 | 13 | public static void instanceofExample() { 14 | System.out.println("=== instanceof example ==="); 15 | var point = new Point(10, 10); 16 | var coloredPoint = new ColoredPoint(point, "blue"); 17 | Object obj = coloredPoint; 18 | 19 | // JDK 16 20 | if (obj instanceof ColoredPoint cp) { 21 | System.out.println("obj is a ColoredPoint: " + cp); 22 | } 23 | 24 | if (obj instanceof Point p) { 25 | System.out.println("obj is a point: " + p); 26 | } else { 27 | System.out.println("obj is not a point"); 28 | } 29 | 30 | // JDK 20 31 | if (obj instanceof ColoredPoint(Point(int x, var y), String color)) { 32 | System.out.printf("Point [%d,%d] has color %s%n", x, y, color); 33 | } 34 | } 35 | 36 | public static void switchExample() { 37 | System.out.println("=== switch example ==="); 38 | var list = new Decorator[] { 39 | new Decorator(new Point(21, 21)), 40 | new Decorator(new ColoredPoint(new Point(42, 42), "red")), 41 | new Decorator("test") 42 | }; 43 | 44 | for (Decorator d : list) { 45 | switch (d) { 46 | case Decorator(Point(var x, var y)) -> { 47 | System.out.printf("Point [%d,%d]%n", x, y); 48 | } 49 | case Decorator(ColoredPoint(Point(var x, var y), String color)) -> { 50 | System.out.printf("ColoredPoint [%d,%d] with color %s%n", x, y, color); 51 | } 52 | case Decorator(String s) -> { 53 | System.out.println("Decorated string: " + s); 54 | } 55 | // required to be exhaustive 56 | default -> System.out.println("None matched"); 57 | } 58 | } 59 | } 60 | 61 | public static void genericInferenceTest() { 62 | System.out.println("=== generic type inference example ==="); 63 | var point = new Point(42, 42); 64 | var decoratedPoint = new Decorator(new ColoredPoint(point, "RED")); 65 | var anotherDecorated = new Decorator(decoratedPoint); 66 | 67 | // JDK 20: type inference in Decorator(Decorator(T)) 68 | if (anotherDecorated instanceof Decorator(Decorator(ColoredPoint(Point(int x, int y), String color)))) { 69 | System.out.printf("x=%d, y=%d; color=%s%n%n", x, y, color); 70 | } 71 | } 72 | 73 | static void removedSupportToUseRecordPatternInEnhancedForLoop() { 74 | var items = new ColoredPoint[] { new ColoredPoint(new Point(42, 42), "red") }; 75 | 76 | // support removed in JDK 21 77 | /* 78 | // only works in JDK 20 79 | for (ColoredPoint(Point(var x, var y), String color) : items) { 80 | System.out.printf("Point [%d, %d] has color %s", x, y, color); 81 | } 82 | */ 83 | } 84 | } 85 | 86 | record Point(int x, int y) {} 87 | 88 | record ColoredPoint(Point p, String color) {} 89 | 90 | record Decorator(T t) {} 91 | 92 | -------------------------------------------------------------------------------- /java-23/ScopedValueUsageExample.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.concurrent.*; 3 | 4 | /** 5 | * Run: `java --source 23 --enable-preview ScopedValueUsageExample.java` 6 | */ 7 | public class ScopedValueUsageExample { 8 | final static ScopedValue MAIN_SCOPE = ScopedValue.newInstance(); 9 | 10 | public static void main(String[] args) { 11 | System.out.println("Starting scoped value"); 12 | 13 | // we can share a value from here 14 | ScopedValue.where(MAIN_SCOPE, "message from main") 15 | .run(() -> { 16 | var worker = new Worker(); 17 | worker.execute(); 18 | }); 19 | System.out.println("main ending"); 20 | } 21 | } 22 | 23 | class Worker { 24 | final static ScopedValue WORKER_SCOPE = ScopedValue.newInstance(); 25 | 26 | public void execute() { 27 | // accessing the value from the scope 28 | System.out.println("shared value from main: " + ScopedValueUsageExample.MAIN_SCOPE.get()); 29 | 30 | // === Nested Scope === 31 | // we can create a nested scope 32 | ScopedValue.where(WORKER_SCOPE, "message from worker") 33 | .run(() -> { 34 | // the outmost scope will still works 35 | var messageFromMain = ScopedValueUsageExample.MAIN_SCOPE.get(); 36 | var messageFromWorker = WORKER_SCOPE.get(); 37 | System.out.println("shared value to inner scope from main: " + messageFromMain); 38 | System.out.println("shared value to inner scope from worker: " + messageFromWorker); 39 | }); 40 | 41 | // we cannot access it from outside its scope (NoSuchElementException) 42 | // var invalidAccess = WORKER_SCOPE.get(); 43 | 44 | // === Rebinded Scope Value === 45 | // we can create a new scope that rebinds a new value to the created scope (when using the same variable) 46 | ScopedValue.where(ScopedValueUsageExample.MAIN_SCOPE, "message from worker over main") 47 | .run(() -> { 48 | // the outmost scope will still works 49 | var rebindedMessage = ScopedValueUsageExample.MAIN_SCOPE.get(); 50 | System.out.println("shared value from shadowed scope: " + rebindedMessage); 51 | }); 52 | 53 | // but the original scope from main will still have its initial value (immutable) 54 | System.out.println("shared value from main after all scopes: " + ScopedValueUsageExample.MAIN_SCOPE.get()); 55 | 56 | // === Failure Handle === 57 | try { 58 | // with `callWhere` we get checked exception type inference (requiring try-catch block) 59 | var result = ScopedValue.callWhere(WORKER_SCOPE, "message for a risk move", () -> { 60 | var message = WORKER_SCOPE.get(); 61 | 62 | if (message.length() > 15) { 63 | throw new MessageTooLongException(); 64 | } 65 | return 42; 66 | }); 67 | System.out.println("Result from risk move: " + result); 68 | } catch (MessageTooLongException ex) { 69 | System.err.println("Error during risk move: " + ex.getMessage()); 70 | } 71 | } 72 | } 73 | 74 | class MessageTooLongException extends Exception { 75 | MessageTooLongException() { 76 | super("Message provided in the scope was too long"); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /java-24/ScopedValueUsageExample.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.concurrent.*; 3 | 4 | /** 5 | * Run: `java --source 24 --enable-preview ScopedValueUsageExample.java` 6 | */ 7 | public class ScopedValueUsageExample { 8 | final static ScopedValue MAIN_SCOPE = ScopedValue.newInstance(); 9 | 10 | public static void main(String[] args) { 11 | System.out.println("Starting scoped value"); 12 | 13 | // we can share a value from here 14 | ScopedValue.where(MAIN_SCOPE, "message from main") 15 | .run(() -> { 16 | var worker = new Worker(); 17 | worker.execute(); 18 | }); 19 | System.out.println("main ending"); 20 | } 21 | } 22 | 23 | class Worker { 24 | final static ScopedValue WORKER_SCOPE = ScopedValue.newInstance(); 25 | 26 | public void execute() { 27 | // accessing the value from the scope 28 | System.out.println("shared value from main: " + ScopedValueUsageExample.MAIN_SCOPE.get()); 29 | 30 | // === Nested Scope === 31 | // we can create a nested scope 32 | ScopedValue.where(WORKER_SCOPE, "message from worker") 33 | .run(() -> { 34 | // the outmost scope will still works 35 | var messageFromMain = ScopedValueUsageExample.MAIN_SCOPE.get(); 36 | var messageFromWorker = WORKER_SCOPE.get(); 37 | System.out.println("shared value to inner scope from main: " + messageFromMain); 38 | System.out.println("shared value to inner scope from worker: " + messageFromWorker); 39 | }); 40 | 41 | // we cannot access it from outside its scope (NoSuchElementException) 42 | // var invalidAccess = WORKER_SCOPE.get(); 43 | 44 | // === Rebinded Scope Value === 45 | // we can create a new scope that rebinds a new value to the created scope (when using the same variable) 46 | ScopedValue.where(ScopedValueUsageExample.MAIN_SCOPE, "message from worker over main") 47 | .run(() -> { 48 | // the outmost scope will still works 49 | var rebindedMessage = ScopedValueUsageExample.MAIN_SCOPE.get(); 50 | System.out.println("shared value from shadowed scope: " + rebindedMessage); 51 | }); 52 | 53 | // but the original scope from main will still have its initial value (immutable) 54 | System.out.println("shared value from main after all scopes: " + ScopedValueUsageExample.MAIN_SCOPE.get()); 55 | 56 | // === Failure Handle === 57 | try { 58 | // with `where` we get checked exception type inference (requiring try-catch block) 59 | var result = ScopedValue.where(WORKER_SCOPE, "message for a risk move") 60 | .call(() -> { 61 | var message = WORKER_SCOPE.get(); 62 | 63 | if (message.length() > 15) { 64 | throw new MessageTooLongException(); 65 | } 66 | return 42; 67 | }); 68 | System.out.println("Result from risk move: " + result); 69 | } catch (MessageTooLongException ex) { 70 | System.err.println("Error during risk move: " + ex.getMessage()); 71 | } 72 | } 73 | } 74 | 75 | class MessageTooLongException extends Exception { 76 | MessageTooLongException() { 77 | super("Message provided in the scope was too long"); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /java-24/ClassFileApiTransformingExample.java: -------------------------------------------------------------------------------- 1 | import java.lang.classfile.*; 2 | import java.lang.constant.*; 3 | import java.nio.file.Files; 4 | import java.nio.file.Paths; 5 | 6 | /** 7 | * CodeBuilder doc: https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/classfile/CodeBuilder.html 8 | * 9 | * - compile BasicClass and ClassFileApiTestTransformedBasicClass classes 10 | * - run transformation code in the BasicClass bytes 11 | * - run BasicClass testing class 12 | * 13 | * Run: `javac ClassFileApiTestTransformedBasicClass.java && java ClassFileApiTransformingExample.java && java ClassFileApiTestTransformedBasicClass` 14 | */ 15 | public class ClassFileApiTransformingExample { 16 | public static void main(String[] args) throws Exception { 17 | var classBytes = Files.readAllBytes(Paths.get("BasicClass.class")); 18 | 19 | var transformedClassBytes = dropMethod(classBytes); 20 | transformedClassBytes = transformMethod(transformedClassBytes); 21 | 22 | writeFile(transformedClassBytes); 23 | } 24 | 25 | static byte[] dropMethod(byte[] classBytes) { 26 | System.out.println("Dropping setters"); 27 | ClassModel originalClassModel = ClassFile.of().parse(classBytes); 28 | byte[] transformedClassBytes = ClassFile.of().build( 29 | originalClassModel.thisClass().asSymbol(), 30 | classBuilder -> { 31 | for (ClassElement ce : originalClassModel) { 32 | // removes every setter 33 | if (!(ce instanceof MethodModel mm && mm.methodName().stringValue().startsWith("set"))) { 34 | classBuilder.with(ce); 35 | } 36 | } 37 | } 38 | ); 39 | 40 | // there are helpful methods in ClassFile to do the transformations 41 | var classfile = ClassFile.of(); 42 | transformedClassBytes = classfile.transformClass( 43 | classfile.parse(classBytes), 44 | ClassTransform.dropping(ce -> ce instanceof MethodModel mm && mm.methodName().stringValue().startsWith("set")) 45 | ); 46 | return transformedClassBytes; 47 | } 48 | 49 | static byte[] transformMethod(byte[] classBytes) { 50 | System.out.println("Transforming timestamp getter"); 51 | ClassModel originalClassModel = ClassFile.of().parse(classBytes); 52 | byte[] transformedClassBytes = ClassFile.of().build( 53 | originalClassModel.thisClass().asSymbol(), 54 | cb -> { 55 | for (ClassElement ce : originalClassModel) { 56 | // replaces the getTimestamp method 57 | if (ce instanceof MethodModel mm && mm.methodName().stringValue().equals("getTimestamp")) { 58 | var mtdInt = MethodTypeDesc.of(ConstantDescs.CD_int); 59 | cb.withFlags() 60 | .withMethodBody( 61 | mm.methodName().stringValue(), mtdInt, ClassFile.ACC_PUBLIC, 62 | cob -> cob.ldc(42).ireturn() 63 | ); 64 | } else { 65 | cb.with(ce); 66 | } 67 | } 68 | } 69 | ); 70 | return transformedClassBytes; 71 | } 72 | 73 | static void writeFile(byte[] bytes) { 74 | System.out.println("Writing BasicClass file"); 75 | try { 76 | Files.write(Paths.get("BasicClass.class"), bytes); 77 | } catch (Exception ex) { 78 | System.err.println("Error during writing: " + ex.getMessage()); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /java-24/ClassFileApiWritingExample.java: -------------------------------------------------------------------------------- 1 | import java.lang.classfile.*; 2 | import java.lang.constant.*; 3 | import java.nio.file.Files; 4 | import java.nio.file.Paths; 5 | import java.nio.file.OpenOption; 6 | 7 | /** 8 | * CodeBuilder doc: https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/classfile/CodeBuilder.html 9 | * 10 | * Run: `java ClassFileApiWritingExample.java` 11 | */ 12 | public class ClassFileApiWritingExample { 13 | public static void main(String[] args) { 14 | var className = "HelloWorldFromClassFile"; 15 | 16 | var CD_System = ClassDesc.of("java.lang.System"); 17 | var CD_PrintStream = ClassDesc.of("java.io.PrintStream"); 18 | // we can use ClassDesc.of to get String class descriptor or use ConstantDescs with fixed class descriptors 19 | // arrayType returns a class descriptors for array of that type 20 | var MTD_void_StringArray = MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_String.arrayType()); 21 | var MTD_void_String = MethodTypeDesc.of(ConstantDescs.CD_void, ClassDesc.of("java.lang.String")); 22 | 23 | System.out.println("Building class"); 24 | byte[] bytes = ClassFile.of().build( 25 | ClassDesc.of(className), 26 | clb -> clb.withFlags(ClassFile.ACC_PUBLIC) 27 | .withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, ClassFile.ACC_PUBLIC, 28 | mb -> mb.withCode( 29 | cob -> cob.aload(0) 30 | // invokes Object constructor 31 | .invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME, ConstantDescs.MTD_void) 32 | // calls System.out.println 33 | .getstatic(CD_System, "out", CD_PrintStream) 34 | .ldc("Class " + className + " constructor") 35 | .invokevirtual(CD_PrintStream, "println", MTD_void_String) 36 | .return_() 37 | ) 38 | ) 39 | // another way to build method without using MethodBuilder.withCode 40 | .withMethodBody("main", MTD_void_StringArray, ClassFile.ACC_PUBLIC + ClassFile.ACC_STATIC, 41 | cob -> cob.getstatic(CD_System, "out", CD_PrintStream) 42 | .ldc("Hello World from class built from Class File API") 43 | .invokevirtual(CD_PrintStream, "println", MTD_void_String) 44 | .return_() 45 | ) 46 | ); 47 | 48 | // writes the class to file 49 | // Inspect with: `javap HelloWorldFromClassFile.class` 50 | // Run with: `java HelloWorldFromClassFile` 51 | try { 52 | System.out.println("Writing class"); 53 | Files.write(Paths.get(className + ".class"), bytes); 54 | } catch (Exception ex) { 55 | System.err.println("Error during writing: " + ex.getMessage()); 56 | } 57 | 58 | // loads the written class 59 | try { 60 | System.out.println("Loading and running class"); 61 | var clazz = ClassLoader.getSystemClassLoader().loadClass(className); 62 | var instance = clazz.getConstructors()[0].newInstance(); 63 | clazz.getMethods()[0].invoke(instance, new Object[] { args }); 64 | } catch (ClassNotFoundException ex) { 65 | System.err.println("Class not found"); 66 | } catch (Exception ex) { 67 | System.err.println("Error during running: " + ex.getMessage()); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /java-25/ScopedValueExampleVsThreadLocal.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | import java.util.concurrent.*; 3 | 4 | /** 5 | * Run: `java ScopedValueExampleVsThreadLocal.java` 6 | */ 7 | public class ScopedValueExampleVsThreadLocal { 8 | // pretty much the same 9 | final static ThreadLocal USER_LOCAL = new ThreadLocal<>(); 10 | final static ScopedValue USER_SCOPE = ScopedValue.newInstance(); 11 | 12 | 13 | public static void main(String[] args) { 14 | var users = List.of( 15 | "Neo", 16 | "Trinity", 17 | "Morpheus", 18 | "Switch", 19 | "Dozer" 20 | ); 21 | 22 | var calculator = new Calculator(); 23 | var worker = new UserWorker(calculator); 24 | 25 | // now ExecutorService extends AutoCloseable 26 | try (var executor = Executors.newThreadPerTaskExecutor(Thread.ofPlatform().factory())) { 27 | System.out.println("Starting processing"); 28 | 29 | for (var i = 0; i < 5; i++) { 30 | var user = users.get(i); 31 | 32 | System.out.printf("Starting worker user %s%n", user); 33 | executor.submit(() -> { 34 | // ThreadLocal just set 35 | USER_LOCAL.set(user); 36 | 37 | // with ScopedValue, we set the value and define the scope in which it will be available 38 | ScopedValue.where(USER_SCOPE, user) 39 | .run(worker::run); 40 | 41 | var userLocal = USER_LOCAL.get(); 42 | System.out.printf("User is still available in ThreadLocal: %s%n", userLocal); 43 | }); 44 | } 45 | } 46 | 47 | System.out.println("Processing ended"); 48 | } 49 | } 50 | 51 | class UserWorker implements Runnable { 52 | private Calculator calculator; 53 | 54 | public UserWorker(Calculator calculator) { 55 | this.calculator = calculator; 56 | } 57 | 58 | public void run() { 59 | System.out.printf("Getting user for calculation...%n"); 60 | // both we retrieve the value in the same way 61 | var user = ScopedValueExampleVsThreadLocal.USER_SCOPE.get(); 62 | var userLocal = ScopedValueExampleVsThreadLocal.USER_LOCAL.get(); 63 | 64 | System.out.printf("Users - ScopedValue: %s - ThreadLocal: %s%n", user, userLocal); 65 | if (!user.equals(userLocal)) { 66 | System.out.printf("Users from ScopedValue and ThreadLocal aren't the same%n", user); 67 | return; 68 | } 69 | // the first difference, in ThreadLocal we can change the value at any time 70 | ScopedValueExampleVsThreadLocal.USER_LOCAL.set(userLocal + " -- was changed"); 71 | 72 | System.out.printf("User %s - calculating...%n", user); 73 | var answer = this.calculator.calculate(); 74 | System.out.printf("User %s - answer: %d%n", user, answer); 75 | } 76 | } 77 | 78 | class Calculator { 79 | public int calculate() { 80 | // now the ThreadLocal will see a different value 81 | // (could be change anywhere, it require us to look for the points that is changing it) 82 | var user = ScopedValueExampleVsThreadLocal.USER_SCOPE.get(); 83 | var userLocal = ScopedValueExampleVsThreadLocal.USER_LOCAL.get(); 84 | 85 | System.out.printf("Users - ScopedValue: %s - ThreadLocal: %s%n", user, userLocal); 86 | // pretend to go to DB to sum the rows 87 | try { 88 | Thread.sleep(500); 89 | } catch (InterruptedException ex) {} 90 | return user.length(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /java-14/RecordsSerializationTest.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | public class RecordsSerializationTest { 4 | public static void main(String[] args) { 5 | // Try to comment this and change the serialVersionUID value 6 | write(); 7 | read(); 8 | } 9 | 10 | private static void write() { 11 | var point = new CustomSerializableRecord(10, 20); 12 | 13 | try (FileOutputStream fos = new FileOutputStream("record_custom.data"); 14 | ObjectOutputStream out = new ObjectOutputStream(fos)) { 15 | 16 | out.writeObject(point); 17 | 18 | } catch (Exception ex) { 19 | ex.printStackTrace(); 20 | } finally { 21 | System.out.println("Finished"); 22 | } 23 | } 24 | 25 | private static void read() { 26 | try (FileInputStream fis = new FileInputStream("record_custom.data"); 27 | ObjectInputStream in = new ObjectInputStream(fis)) { 28 | 29 | var readPoint = (CustomSerializableRecord) in.readObject(); 30 | System.out.println("Read: " + readPoint); 31 | 32 | } catch (Exception ex) { 33 | ex.printStackTrace(); 34 | } finally { 35 | System.out.println("Finished"); 36 | } 37 | } 38 | } 39 | 40 | /** 41 | * Records are serialized different from ordinary classes. 42 | * Its fields are written in the same order as declared. 43 | * When it is read, the component constructor is called as normal code would need to do. 44 | * It cannot customize its serialization, only the method `writeReplace` can be used to 45 | * create a copy to be serialized. 46 | * 47 | * The value of serialVersionUID is fixed to 0L. If we added components to the record, 48 | * it will contain the default value for that type. 49 | * If we change the existing componentes it will throw something like: 50 | * `java.io.InvalidClassException: CustomSerializableRecord; incompatible types for field x` 51 | * 52 | * http://cr.openjdk.java.net/~chegar/records/spec/records-serialization.03.html#serialization-of-records 53 | */ 54 | record CustomSerializableRecord(int x, int y) implements Serializable { 55 | private static final long serialVersionUID = 2L; 56 | 57 | public CustomSerializableRecord { 58 | System.out.printf("Compact constructor (%s, %s)\n", x, y); 59 | } 60 | 61 | private Object writeReplace() throws ObjectStreamException { 62 | System.out.print("Creating a copy to be serialized: "); 63 | return new CustomSerializableRecord(x + 1, y + 1); 64 | } 65 | 66 | private Object readResolve() throws ObjectStreamException { 67 | System.out.printf("Reading from serialized object - x: %s, y: %s\n", x, y); 68 | return new CustomSerializableRecord(x - 1, y - 1); 69 | } 70 | 71 | // Won't be called 72 | private void writeObject(ObjectOutputStream out) throws IOException { 73 | System.out.println("Writing object..."); 74 | 75 | out.writeUTF("Message to write"); 76 | out.writeInt(x); 77 | out.writeInt(y); 78 | } 79 | 80 | // Won't be called 81 | private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 82 | System.out.println("Reading object..."); 83 | 84 | String message = in.readUTF(); 85 | System.out.println("Message read: " + message); 86 | System.out.println("X = " + in.readInt()); 87 | System.out.println("y = " + in.readInt()); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /java-12/SwitchExpressionExample.java: -------------------------------------------------------------------------------- 1 | public class SwitchExpressionExample { 2 | public static void main(String ... args) { 3 | compatibleWithOldVersion(); 4 | 5 | longVersion(); 6 | shortVersion(); 7 | 8 | switchWithReturn(); 9 | 10 | inferringType(); 11 | } 12 | 13 | public static void compatibleWithOldVersion() { 14 | int luckNumber = 7; 15 | 16 | // we can use the old syntax (case:) 17 | var wasLucky = switch (luckNumber) { 18 | // here the fall-through happens (if there is no break or return the next case will be executed) 19 | case 7: 20 | break false; // break was changed to yield in Java 13 21 | case 13: 22 | break true; 23 | // here we must provide a default case (compiler checks exhaustiveness) 24 | default: 25 | throw new IllegalArgumentException("Wrong number"); 26 | }; // switch expression needs ; 27 | 28 | System.out.println("\nWas I lucky? " + wasLucky); 29 | } 30 | 31 | public static void longVersion() { 32 | var mood = Incomes.Good; 33 | 34 | // arrow syntax with no fall-through (only the arrow block will be executed) 35 | var shouldIGo = switch (mood) { 36 | // accepts multiple case labels 37 | case Good, Regular -> { 38 | break true; 39 | } 40 | case Bad -> { 41 | break false; 42 | } 43 | // there is no need to use default (we covered all possible cases) 44 | }; 45 | 46 | System.out.println("\nShould I go? " + shouldIGo); 47 | } 48 | 49 | public static void shortVersion() { 50 | var mood = Incomes.Good; 51 | 52 | // cool syntax with no fall-through (only the arrow block will be executed) 53 | var shouldIGo = switch (mood) { 54 | // accepts multiple case labels 55 | case Good, Regular -> true; 56 | case Bad -> false; 57 | // there is no need to use default (we covered all possible cases) 58 | }; 59 | 60 | System.out.println("\nShould I go? " + shouldIGo); 61 | } 62 | 63 | public static void switchWithReturn() { 64 | var mood = Incomes.Bad; 65 | 66 | // used as statement (there is no assign) 67 | switch (mood) { 68 | case Good -> { 69 | var easy = true; 70 | System.out.println("\nKeep working"); 71 | } 72 | case Regular, Bad -> { 73 | // we can now declare vars with same name (each arrow has its own scope) 74 | var easy = true; 75 | System.out.println("\nGo home"); 76 | /* 77 | * we can only return inside a block and when switch 78 | * is used as statement 79 | */ 80 | return; 81 | } 82 | } 83 | } 84 | 85 | public static void inferringType() { 86 | var mood = Incomes.Good; 87 | 88 | // compiler infers the most specific supertype 89 | // of String and IllegalArgumentException is Serializable 90 | // Serializable whichType // we can only use its supertype 91 | var whichType = switch (mood) { 92 | case Good -> "All right"; 93 | default -> new IllegalArgumentException("Not right"); 94 | }; 95 | 96 | // won't work 97 | // System.out.println("What is the length? " + whichType.length()); 98 | } 99 | } 100 | 101 | enum Incomes { 102 | Good, 103 | Regular, 104 | Bad 105 | } -------------------------------------------------------------------------------- /java-13/SwitchExpressionTests.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Same example from Java 12 but with syntax update (changed `break` to `yield`). 3 | */ 4 | public class SwitchExpressionTests { 5 | public static void main(String ... args) { 6 | compatibleWithOldVersion(); 7 | 8 | longVersion(); 9 | shortVersion(); 10 | 11 | switchWithReturn(); 12 | 13 | inferringType(); 14 | } 15 | 16 | public static void compatibleWithOldVersion() { 17 | int luckNumber = 7; 18 | 19 | // we can use the old syntax (case:) 20 | var wasLucky = switch (luckNumber) { 21 | // here the fall-through happens (if there is no break or return the next case will be executed) 22 | case 7: 23 | yield false; 24 | case 13: 25 | yield true; 26 | // here we must provide a default case (compiler checks exhaustiveness) 27 | default: 28 | throw new IllegalArgumentException("Wrong number"); 29 | }; // switch expression needs ; 30 | 31 | System.out.println("\nWas I lucky? " + wasLucky); 32 | } 33 | 34 | public static void longVersion() { 35 | var mood = Incomes.Good; 36 | 37 | // arrow syntax with no fall-through (only the arrow block will be executed) 38 | var shouldIGo = switch (mood) { 39 | // accepts multiple case labels 40 | case Good, Regular -> { 41 | yield true; 42 | } 43 | case Bad -> { 44 | yield false; 45 | } 46 | // there is no need to use default (we covered all possible cases) 47 | }; 48 | 49 | System.out.println("\nShould I go? " + shouldIGo); 50 | } 51 | 52 | public static void shortVersion() { 53 | var mood = Incomes.Good; 54 | 55 | // cool syntax with no fall-through (only the arrow block will be executed) 56 | var shouldIGo = switch (mood) { 57 | // accepts multiple case labels 58 | case Good, Regular -> true; 59 | case Bad -> false; 60 | // there is no need to use default (we covered all possible cases) 61 | }; 62 | 63 | System.out.println("\nShould I go? " + shouldIGo); 64 | } 65 | 66 | public static void switchWithReturn() { 67 | var mood = Incomes.Bad; 68 | 69 | // used as statement (there is no assign) 70 | switch (mood) { 71 | case Good -> { 72 | var easy = true; 73 | System.out.println("\nKeep working"); 74 | } 75 | case Regular, Bad -> { 76 | // we can now declare vars with same name (each arrow has its own scope) 77 | var easy = true; 78 | System.out.println("\nGo home"); 79 | /* 80 | * we can only return inside a block and when switch 81 | * is used as statement 82 | */ 83 | return; 84 | } 85 | } 86 | } 87 | 88 | public static void inferringType() { 89 | var mood = Incomes.Good; 90 | 91 | // compiler infers the most specific supertype 92 | // of String and IllegalArgumentException = Serializable 93 | // Serializable whichType // we can only use its supertype 94 | var whichType = switch (mood) { 95 | case Good -> "All right"; 96 | default -> new IllegalArgumentException("Not right"); 97 | }; 98 | 99 | // won't work 100 | // System.out.println("What is the length? " + whichType.length()); 101 | } 102 | } 103 | 104 | enum Incomes { 105 | Good, 106 | Regular, 107 | Bad 108 | } -------------------------------------------------------------------------------- /java-20/ScopedValueExampleVsThreadLocal.java: -------------------------------------------------------------------------------- 1 | import jdk.incubator.concurrent.*; 2 | import java.util.List; 3 | import java.util.concurrent.Executors; 4 | 5 | /** 6 | * Run: `java --source 20 --enable-preview --add-modules jdk.incubator.concurrent ScopedValueExampleVsThreadLocal.java` 7 | */ 8 | public class ScopedValueExampleVsThreadLocal { 9 | // pretty much the same 10 | final static ThreadLocal USER_LOCAL = new ThreadLocal<>(); 11 | final static ScopedValue USER_SCOPE = ScopedValue.newInstance(); 12 | 13 | 14 | public static void main(String[] args) { 15 | var users = List.of( 16 | "Neo", 17 | "Trinity", 18 | "Morpheus", 19 | "Switch", 20 | "Dozer" 21 | ); 22 | 23 | var calculator = new Calculator(); 24 | var worker = new UserWorker(calculator); 25 | 26 | // now ExecutorService extends AutoCloseable 27 | try (var executor = Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory())) { 28 | System.out.println("Starting processing"); 29 | for (var i = 0; i < 5; i++) { 30 | var user = users.get(i); 31 | 32 | System.out.printf("Starting worker user %s%n", user); 33 | executor.submit(() -> { 34 | // ThreadLocal just set 35 | USER_LOCAL.set(user); 36 | 37 | // with ScopedValue, we set the value and define the scope in which it will be available 38 | ScopedValue.where(USER_SCOPE, user) 39 | .run(worker::run); 40 | 41 | var userLocal = USER_LOCAL.get(); 42 | System.out.printf("User is still available in ThreadLocal: %s%n", userLocal); 43 | }); 44 | } 45 | } 46 | 47 | System.out.println("Processing ended"); 48 | } 49 | } 50 | 51 | class UserWorker implements Runnable { 52 | private Calculator calculator; 53 | 54 | public UserWorker(Calculator calculator) { 55 | this.calculator = calculator; 56 | } 57 | 58 | public void run() { 59 | System.out.printf("Getting user for calculation...%n"); 60 | // both we retrieve the value in the same way 61 | var user = ScopedValueExampleVsThreadLocal.USER_SCOPE.get(); 62 | var userLocal = ScopedValueExampleVsThreadLocal.USER_LOCAL.get(); 63 | 64 | System.out.printf("Users - ScopedValue: %s - ThreadLocal: %s%n", user, userLocal); 65 | if (!user.equals(userLocal)) { 66 | System.out.printf("Users from ScopedValue and ThreadLocal aren't the same%n", user); 67 | return; 68 | } 69 | // the first difference, in ThreadLocal we can change the value at any time 70 | ScopedValueExampleVsThreadLocal.USER_LOCAL.set(userLocal + " -- was changed"); 71 | 72 | System.out.printf("User %s - calculating...%n", user); 73 | var answer = this.calculator.calculate(); 74 | System.out.printf("User %s - answer: %d%n", user, answer); 75 | } 76 | } 77 | 78 | class Calculator { 79 | public int calculate() { 80 | // now the ThreadLocal will see a different value 81 | // (could be change anywhere, it require us to look for the points that is changing it) 82 | var user = ScopedValueExampleVsThreadLocal.USER_SCOPE.get(); 83 | var userLocal = ScopedValueExampleVsThreadLocal.USER_LOCAL.get(); 84 | 85 | System.out.printf("Users - ScopedValue: %s - ThreadLocal: %s%n", user, userLocal); 86 | // pretend to go to DB to sum the rows 87 | try { 88 | Thread.sleep(500); 89 | } catch (InterruptedException ex) {} 90 | return user.length(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /java-23/PrimitiveTypesPatternsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To run: `java --enable-preview --source 23 PrimitiveTypesPatternsTest.java` 3 | */ 4 | 5 | void main() { 6 | beforeJdk23(); 7 | 8 | instancePrimitiveTypePattern(); 9 | switchPrimitiveTypePattern(); 10 | } 11 | 12 | void beforeJdk23() { 13 | int status = 2; 14 | var message = switch (status) { 15 | case 0 -> "ok"; 16 | case 1 -> "not bad"; 17 | case 2 -> "not ok"; 18 | default -> "unknown - " + status; 19 | }; 20 | System.out.println("Staus: " + message); 21 | 22 | Number statusRef = 0; 23 | message = switch (statusRef) { 24 | case Integer i when i == 0 -> "ok"; 25 | case Integer i when i > 0 && i < 10 -> "not bad"; 26 | case Integer i -> "not ok"; 27 | case Long _ -> "not allowed to use long"; 28 | default -> "unknown type - " + statusRef; 29 | }; 30 | System.out.println("Staus: " + message); 31 | } 32 | 33 | void instancePrimitiveTypePattern() { 34 | System.out.println("=== instanceof ==="); 35 | int i = 42; 36 | 37 | if (i instanceof byte b) { // exact conversion 38 | System.out.println("byte is " + b); 39 | } 40 | if (i instanceof short s) { // exact conversion 41 | System.out.println("short is " + s); 42 | } 43 | 44 | int i2 = 16_777_217; 45 | System.out.println("i2 is short? " + (i2 instanceof short)); 46 | System.out.println("i2 is long? " + (i2 instanceof long)); // unconditionally exact 47 | System.out.println("i2 is float? " + (i2 instanceof float)); // not exact conversion 48 | System.out.println("i2 is double? " + (i2 instanceof double)); // exact conversion 49 | System.out.println("i2 is Number? " + (i2 instanceof Number)); // unconditionally exact 50 | 51 | double d = 42.0d; 52 | System.out.println("d is short? " + (d instanceof short)); // exact conversion 53 | System.out.println("d is float? " + (d instanceof float)); // exact conversion 54 | System.out.println("d is int? " + (d instanceof int)); // exact conversion 55 | } 56 | 57 | void switchPrimitiveTypePattern() { 58 | System.out.println("=== switch ==="); 59 | 60 | var message = switch (42) { 61 | case byte b -> "byte matched"; 62 | case short s -> "short matched"; 63 | case long l -> "long matched"; 64 | }; 65 | System.out.println(message); 66 | 67 | boolean truth = true; 68 | message = switch (truth) { 69 | case true -> "It is true"; 70 | case false -> "Oddly, it is false"; 71 | }; 72 | System.out.println("Boolean var: " + message); 73 | 74 | float f = 41.99999f; 75 | message = switch (f) { 76 | // if we don't use `f`: error: constant label of type int is not compatible with switch selector type float 77 | case 0f -> "zero"; 78 | case 42.9f -> "almost universe answer"; 79 | case 41.99999f -> "almost universe answer"; 80 | // float <= 32 or >= 32 with more than 5 decimals will be rounded 81 | // we get an error: duplicate case label (rounded to case 42f) 82 | // case 41.999999f -> "almost universe answer?"; 83 | case 42f -> "universe answer"; 84 | case 42.09f -> "almost universe answer?"; 85 | case 42.5f -> "universe answer plus half"; 86 | case int i2 when i2 == 84 -> "universe answer times two"; 87 | case int _ -> "is a int but not 42"; 88 | // unconditional type pattern (a float is always a double) 89 | case double d -> "default case =)"; 90 | }; 91 | System.out.println("Switch f: " + message); 92 | } 93 | -------------------------------------------------------------------------------- /java-26/PrimitiveTypesPatternsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To run: `java --enable-preview --source 26 PrimitiveTypesPatternsTest.java` 3 | */ 4 | 5 | void main() { 6 | beforeJdk23(); 7 | 8 | instancePrimitiveTypePattern(); 9 | switchPrimitiveTypePattern(); 10 | } 11 | 12 | void beforeJdk23() { 13 | int status = 2; 14 | var message = switch (status) { 15 | case 0 -> "ok"; 16 | case 1 -> "not bad"; 17 | case 2 -> "not ok"; 18 | default -> "unknown - " + status; 19 | }; 20 | System.out.println("Staus: " + message); 21 | 22 | Number statusRef = 0; 23 | message = switch (statusRef) { 24 | case Integer i when i == 0 -> "ok"; 25 | case Integer i when i > 0 && i < 10 -> "not bad"; 26 | case Integer i -> "not ok"; 27 | case Long _ -> "not allowed to use long"; 28 | default -> "unknown type - " + statusRef; 29 | }; 30 | System.out.println("Staus: " + message); 31 | } 32 | 33 | void instancePrimitiveTypePattern() { 34 | System.out.println("=== instanceof ==="); 35 | int i = 42; 36 | 37 | if (i instanceof byte b) { // exact conversion 38 | System.out.println("byte is " + b); 39 | } 40 | if (i instanceof short s) { // exact conversion 41 | System.out.println("short is " + s); 42 | } 43 | 44 | int i2 = 16_777_217; 45 | System.out.println("i2 is short? " + (i2 instanceof short)); 46 | System.out.println("i2 is long? " + (i2 instanceof long)); // unconditionally exact 47 | System.out.println("i2 is float? " + (i2 instanceof float)); // not exact conversion 48 | System.out.println("i2 is double? " + (i2 instanceof double)); // exact conversion 49 | System.out.println("i2 is Number? " + (i2 instanceof Number)); // unconditionally exact 50 | 51 | double d = 42.0d; 52 | System.out.println("d is short? " + (d instanceof short)); // exact conversion 53 | System.out.println("d is float? " + (d instanceof float)); // exact conversion 54 | System.out.println("d is int? " + (d instanceof int)); // exact conversion 55 | } 56 | 57 | void switchPrimitiveTypePattern() { 58 | System.out.println("=== switch ==="); 59 | 60 | var message = switch (42) { 61 | case byte b -> "byte matched"; 62 | case short s -> "short matched"; 63 | case long l -> "long matched"; 64 | }; 65 | System.out.println(message); 66 | 67 | boolean truth = true; 68 | message = switch (truth) { 69 | case true -> "It is true"; 70 | case false -> "Oddly, it is false"; 71 | }; 72 | System.out.println("Boolean var: " + message); 73 | 74 | float f = 41.99999f; 75 | message = switch (f) { 76 | // if we don't use `f`: error: constant label of type int is not compatible with switch selector type float 77 | case 0f -> "zero"; 78 | case 42.9f -> "almost universe answer"; 79 | case 41.99999f -> "almost universe answer"; 80 | // float <= 32 or >= 32 with more than 5 decimals will be rounded 81 | // we get an error: duplicate case label (rounded to case 42f) 82 | // case 41.999999f -> "almost universe answer?"; 83 | case 42f -> "universe answer"; 84 | case 42.09f -> "almost universe answer?"; 85 | case 42.5f -> "universe answer plus half"; 86 | case int i2 when i2 == 84 -> "universe answer times two"; 87 | case int _ -> "is a int but not 42"; 88 | // unconditional type pattern (a float is always a double) 89 | case double d -> "default case =)"; 90 | }; 91 | System.out.println("Switch f: " + message); 92 | } 93 | -------------------------------------------------------------------------------- /java-17/README.md: -------------------------------------------------------------------------------- 1 | # Java 17 2 | 3 | To run each example use: `java --enable-preview --source 17 ` 4 | 5 | ## JEPs 6 | 7 | * [306](https://openjdk.java.net/jeps/306) - Restore Always-Strict Floating-Point Semantics 8 | * [356](https://openjdk.java.net/jeps/356) - Enhanced Pseudo-Random Number Generators 9 | * [382](https://openjdk.java.net/jeps/382) - New macOS Rendering Pipeline 10 | * [391](https://openjdk.java.net/jeps/391) - macOS/AArch64 Port 11 | * [398](https://openjdk.java.net/jeps/398) - Deprecate the Applet API for Removal 12 | * [403](https://openjdk.java.net/jeps/403) - Strongly Encapsulate JDK Internals 13 | * [406](https://openjdk.java.net/jeps/406) - Pattern Matching for switch (Preview) 14 | * [407](https://openjdk.java.net/jeps/407) - Remove RMI Activation 15 | * [409](https://openjdk.java.net/jeps/409) - Sealed Classes 16 | * [410](https://openjdk.java.net/jeps/410) - Remove the Experimental AOT and JIT Compiler 17 | * [411](https://openjdk.java.net/jeps/411) - Deprecate the Security Manager for Removal 18 | * [412](https://openjdk.java.net/jeps/412) - Foreign Function & Memory API (Incubator) 19 | * [414](https://openjdk.java.net/jeps/414) - Vector API (Second Incubator) 20 | * [415](https://openjdk.java.net/jeps/415) - Context-Specific Deserialization Filters 21 | 22 | ## Features 23 | 24 | * **Sealed Classes (standard)** 25 | * promotion to standard without change 26 | * **Pattern Matching for `switch` (preview)** 27 | * improved switch to support pattern matching for types (like `instanceof`) 28 | * support for `null` case 29 | * support for guards where we can use a boolean expression like `case String s && s.length > 10:` 30 | * **Pseudo-Random Number Generators (PRNG)** 31 | * created new classes to generate number 32 | * two groups of PRNG algorithms: 33 | * splittable (LXM family): 34 | * allow spawn a new generator using existing one that produce statistically independent results 35 | * implemented by LXM algorithms (like `L32X64MixRandom`, `L32X64StarStarRandom`, `L64X128MixRandom`, `L64X128StarStarRandom` and others with different bitsizes) 36 | * jumpable: 37 | * allow the client to jump ahead a moderate number of draws 38 | * implemented by `Xoroshiro128PlusPlus` and `Xoshiro256PlusPlus` 39 | * we can use `RandomGeneratorFactory` to create the generators passing the algorithm name (like `L32X64MixRandom` or `Xoroshiro128PlusPlus`) 40 | * new types: 41 | * `SplittableGenerator` 42 | * `JumpableGenerator` 43 | * `LeapableGenerator`: allow the client to jump head a large number of draws; 44 | * `ArbitrarilyJumpableGenerator`: extends LeapableRandomGenerator and allow to jump arbitrary numbero of draws. 45 | * more detailed info in the [docs](https://download.java.net/java/early_access/jdk17/docs/api/java.base/java/util/random/package-summary.html) 46 | 47 | ### JVM 48 | 49 | * Strongly encapsulate JDK internals 50 | * make illegal access internal API flag obsolate (was `--illegal-access=deny` in Java 16) 51 | * only `sun.misc` and `sun.reflect` will be allowed to be access through `jdk.unsupported` module 52 | * Disable SHA-1 XML Signatures 53 | * can be enable with `jdk.xml.dsig.secureValidationPolicy` 54 | 55 | ## Links 56 | 57 | * [JDK 17 Jeps](https://openjdk.java.net/projects/jdk/17/) 58 | * [Consolidated JDK 17 Release Notes](https://www.oracle.com/java/technologies/javase/17all-relnotes.html) 59 | 60 | -------------------------------------------------------------------------------- /projects/valhalla/PrimitiveValueNullabilityExample.java: -------------------------------------------------------------------------------- 1 | /** 2 | * To run: `javac -XDenablePrimitiveClasses --source 20 --target 20 PrimitiveValueNullabilityExample.java && java -XX:+EnablePrimitiveClasses PrimitiveValueNullabilityExample` 3 | */ 4 | public class PrimitiveValueNullabilityExample { 5 | public static void main(String[] args) { 6 | var superman = new Hero("Superman", new Power("fly, strength, laser beam", 10)); 7 | System.out.println(superman); 8 | 9 | // we cannot assign null to primitive value 10 | // error: incompatible types: cannot be converted to Power 11 | // var batman = new Hero("Batman", null); 12 | var batman = new Hero("Batman", Power.default); 13 | System.out.println(batman); 14 | 15 | // using Power.ref we can use it like a normal object reference 16 | var humanBatman = new HumanHero("Batman", null); 17 | System.out.println(humanBatman); 18 | 19 | // infers Power 20 | var supermanPower = superman.getPower(); 21 | 22 | // infers Power.ref 23 | var powerRef = humanBatman.getPower(); 24 | 25 | // explicit value object conversion (Power to Power.ref) 26 | Power.ref power1 = superman.getPower(); 27 | 28 | // implicit primitive value converson (Power.ref to Power) - can occurr NPE 29 | Power power2 = power1; 30 | 31 | try { 32 | // error: NPE Cannot cast to null-free type "QPower;" 33 | Power power = humanBatman.getPower(); 34 | } catch (NullPointerException ex) { 35 | ex.printStackTrace(); 36 | } 37 | 38 | // array of Power will initialize each element with Power.default 39 | var powers = new Power[3]; 40 | System.out.println("Array with default powers:"); 41 | for (var p : powers) { 42 | System.out.println(p); 43 | } 44 | 45 | // array of Power.ref will initialize with null 46 | var refPowers = new Power.ref[3]; 47 | System.out.println("Array with ref powers:"); 48 | for (var p : refPowers) { 49 | System.out.println(p); 50 | } 51 | 52 | // we can assign subtypes of array 53 | Object[] arr1 = refPowers; 54 | // we can set a null because it is Power.ref[] 55 | arr1[0] = null; 56 | 57 | arr1 = powers; 58 | // we cannot set null because it is Power[], occurrs a NPE during primitive value conversion 59 | // error: Cannot store to object array because "" is null or is a null-free array and there's an attempt to store null in it 60 | arr1[0] = null; 61 | } 62 | } 63 | 64 | primitive class HumanHero { 65 | private String name; 66 | private Power.ref power; 67 | 68 | public HumanHero(String name, Power.ref power) { 69 | this.name = name; 70 | this.power = power; 71 | } 72 | 73 | public Power.ref getPower() { 74 | return power; 75 | } 76 | 77 | public String toString() { 78 | return "[name=%s, powers=%s]".formatted(name, power); 79 | } 80 | } 81 | 82 | primitive class Hero { 83 | private String name; 84 | // null-free type 85 | private Power power; 86 | 87 | public Hero(String name, Power power) { 88 | this.name = name; 89 | this.power = power; 90 | } 91 | 92 | public Power getPower() { 93 | return power; 94 | } 95 | 96 | public String toString() { 97 | return "[name=%s, powers=%s]".formatted(name, power); 98 | } 99 | } 100 | 101 | primitive class Power { 102 | private String powers; 103 | private int value; 104 | 105 | public Power(String powers, int value) { 106 | this.powers = powers; 107 | this.value = value; 108 | } 109 | 110 | public String toString() { 111 | return "[powers=%s, value=%d]".formatted(powers, value); 112 | } 113 | } 114 | --------------------------------------------------------------------------------