diff --git a/README.md b/README.md index 599eef3..9c531ee 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,8 @@ * Section 26: [JAVA 8] Streams API * Section 27: [JAVA 8] Optional to deal with nulls in Java * Section 28: MultiThreading in Java -* Section 28: Other prominent new features from Java 22 +* Section 29: Java 22, 23 and 24 new features +* Section 30: Java 25 new features ## Important Links - Online jshell - https://tryjshell.org @@ -45,7 +46,7 @@ - IntelliJ IDEA installation - https://www.jetbrains.com/idea/ - IntelliJ Debugging - https://www.jetbrains.com/help/idea/debugging-code.html - Java Documentation - https://docs.oracle.com/en/java/ -- Java 21 Documentation - https://docs.oracle.com/en/java/javase/21/docs/api/index.html +- Java 25 Documentation - https://docs.oracle.com/en/java/javase/25/docs/api/index.html - Javadoc tutorial - https://www.oracle.com/in/technical-resources/articles/java/javadoc-tool.html - IntelliJ Javadoc reference - https://www.jetbrains.com/help/idea/javadocs.html diff --git a/section3/HelloWorld/.gitignore b/section3/HelloWorld/.gitignore index f68d109..13275f1 100644 --- a/section3/HelloWorld/.gitignore +++ b/section3/HelloWorld/.gitignore @@ -2,6 +2,7 @@ out/ !**/src/main/**/out/ !**/src/test/**/out/ +.kotlin ### Eclipse ### .apt_generated diff --git a/section3/HelloWorld/README.md b/section3/HelloWorld/README.md index 5b2a64c..f246153 100644 --- a/section3/HelloWorld/README.md +++ b/section3/HelloWorld/README.md @@ -1,9 +1,10 @@ # Getting Started with Java in IntelliJ IDEA -Welcome to our Java course! In this guide, we'll walk you through creating your first Java class using IntelliJ IDEA, a powerful integrated development environment (IDE) for Java development. +Welcome to our Java course! In this guide, we'll walk you through creating your first Java class using IntelliJ IDEA, a powerful +integrated development environment (IDE) for Java development. ### Prerequisites Before getting started, ensure that you have the following installed on your system: -- IntelliJ IDEA (Community or Ultimate edition) https://www.jetbrains.com/idea/download/?section=windows -- Java Development Kit (JDK) installed on your machine https://docs.aws.amazon.com/corretto/latest/corretto-21-ug/downloads-list.html +- IntelliJ IDEA (Community or Ultimate edition) https://www.jetbrains.com/idea/download/ +- Java Development Kit (JDK) installed on your machine https://docs.aws.amazon.com/corretto/latest/corretto-25-ug/downloads-list.html ### Steps to Create Your First Java Class 1. #### Open IntelliJ IDEA : Launch IntelliJ IDEA on your system. 2. #### Create a New Project : @@ -13,7 +14,7 @@ Before getting started, ensure that you have the following installed on your sys - Choose a Project Location where you want to save your project files. - Select the Language as Java. - Build system as IntelliJ. - - Add JDK as corretto-21 or click on New... and locate your JDK installation directory. + - Add JDK as corretto-25 or click on New... and locate your JDK installation directory. - Click on Create to create the project. 4. #### Create a Java Class : - In the Project tool window (usually located on the left-hand side), right-click on the src folder. @@ -38,5 +39,174 @@ public class HelloWorld { - Click on the green Run icon next to the main method or right-click anywhere inside the main method and select Run 'HelloWorld.main()'. 7. #### View Output : - You should see the output "Hello Madan" printed in the Run tool window at the bottom of the IntelliJ IDEA window. - + +## Launch Single-File & Multi-File Source-Code Programs + +The Single-File Source-Code Program feature, introduced in `Java 11`, allows developers to run Java programs directly from a source file without the need for separate compilation. + +This was later enhanced in `Java 22` to support Multi-File Source-Code Programs, enabling the execution of Java applications that span across multiple `.java` files โ€” still without explicit compilation. + +### โš™๏ธ Traditional Java (Before Java 11) + +Prior to `Java 11`, you had to compile your Java code before running it: + +### ๐Ÿงพ Example +```java +public class Hello { + public static void main(String[] args) { + System.out.println("Hello World..."); + } +} +``` + +โ–ถ๏ธ Commands +``` +javac Hello.java # Compilation +java Hello # Execution +``` +Two distinct steps were required โ€” compile first, then run. + +### ๐Ÿš€ From Java 11 โ€” Single-File Source Programs + +Starting in Java 11, you can execute a Java program directly from its source file using a single command. + +### ๐Ÿงพ Example +```java +public class Hello { + public static void main(String[] args) { + System.out.println("Hello World..."); + } +} +``` + +โ–ถ๏ธ Command +``` +java Hello.java +``` +โœ… The JVM automatically compiles and runs the file in one step. + +**โš ๏ธ Limitation :** Works only if all the code is within a single file. +If your logic spans multiple source files, Java 11 cannot handle it. + + +### ๐Ÿงฑ From Java 22 โ€” Multi-File Source Programs + +Java 22 extends this functionality โ€” now you can run Java programs that use multiple source files (with dependencies) without manual compilation. + +### ๐Ÿงพ Example +```java +public class Hello { + public static void main(String[] args) { + Greetings.sayHello(); + } +} + +public class Greetings { + public static void sayHello() { + System.out.println("Hello World..."); + } +} +``` + +โ–ถ๏ธ Command +``` +java Hello.java +``` + +โœ… Even though Hello depends on another class (Greetings), `Java 22` automatically detects and compiles both files before execution. + +### ๐Ÿง  How It Works + +| Java Version | Behavior | +| ------------------ | ----------------------------------------------------------------------------- | +| **Before Java 11** | Must compile manually using `javac` before running. | +| **Java 11** | Can run a **single file** directly (`java Hello.java`). | +| **Java 22** | Can run **multi-file source programs** โ€” dependencies included automatically. | + +### ๐Ÿ’ก Key Benefits + +- **Faster Prototyping :** No need to compile separately. + +- **Simpler Workflow :** Run `.java` files directly like scripts. + +- **Multi-File Support :** `Java 22` expands usability to larger projects. + +- **Perfect for Demos, Learning, and Automation Scripts**. + +### ๐Ÿงพ Compilation & Execution Summary +| Step | Before Java 11 | From Java 11 | From Java 22 | +| --------------------------- | ------------------ | ------------------------- | ------------------------- | +| **Compile** | `javac Hello.java` | *(Handled automatically)* | *(Handled automatically)* | +| **Execute** | `java Hello` | `java Hello.java` | `java Hello.java` | +| **Supports Multiple Files** | โŒ | โŒ | โœ… | +| **Ease of Use** | Manual | Simplified | Seamless | + +## Compact Source Files & Instance Main Methods + +The Compact Source Files and Instance Main Methods features introduced in Java 25 make Java simpler and more approachable for beginners, while still being powerful for experienced developers. + +These features reduce boilerplate and let you start coding Java applications without needing to define classes or static methods. + +### ๐Ÿ’ป Traditional vs. Compact Example +๐Ÿงพ Before (Classic Java Program) +```java +public class HelloWorld { + public static void main(String[] args) { + System.out.println("Hello World!"); + } +} +``` + +โœ… After (Compact Source File in Java 25) +```java +void main() { + IO.println("Hello World!"); +} +``` + +### ๐Ÿง  Explanation + +- Compact Source Files remove the need for explicit class definitions in simple programs. +- Instance Main Methods allow main() to be defined without the static keyword. +- This keeps code concise, beginner-friendly, and ideal for quick prototypes or lightweight scripts. + +๐Ÿ’ก The Java compiler automatically creates an implicit top-level class for compact source files. + +### โš™๏ธ Instance Main Method Explained + +Traditionally, Java required main() to be static: +```java + +public static void main(String[] args) { } +``` + +Now, in Java 25, the `main()` method can be non-static โ€” the JVM automatically instantiates the implicit class to execute it. + +๐Ÿงพ Allowed Variations of main() in Compact Source Files +```java +void main() {} +public void main() {} +static void main() {} +public static void main() {} +public void main(String[] args) {} +public static void main(String[] args) {} +``` +๐Ÿงฉ If both a `main(String[] args)` and a no-argument `main()` exist, the JVM prefers `main(String[] args)` as the programโ€™s entry point. + +### ๐Ÿ’ฌ Why It Matters + +- Beginner-Friendly: No need to understand classes, objects, or static context before writing your first program. +- Less Boilerplate: Write quick experiments, demos, or simple utilities faster. +- Flexible for Experts: Enables rapid prototyping before scaling into larger applications. + + + +### ๐Ÿ”– Summary +| Feature | Description | +| ------------------------- | ------------------------------------------------- | +| **Compact Source Files** | Write Java code without explicit class declarations. | +| **Instance Main Methods** | Define `main()` without `static`. JVM handles instantiation. | +| **Goal** | Simplify Java for beginners and enable quick prototyping. | +| **Status** | Available in Java 25 | + Congratulations! You've successfully created and executed your first Java class using IntelliJ IDEA. diff --git a/section3/HelloWorld/src/HelloWorld.java b/section3/HelloWorld/src/HelloWorld.java index 212aa5d..5a47826 100644 --- a/section3/HelloWorld/src/HelloWorld.java +++ b/section3/HelloWorld/src/HelloWorld.java @@ -1,7 +1,8 @@ public class HelloWorld { public static void main(String[] args) { - System.out.println("Hello Madan"); + System.out.println("Hello World"); + IO.println("Hi World"); } } diff --git a/section3/HelloWorld/src/Main.java b/section3/HelloWorld/src/Main.java new file mode 100644 index 0000000..38e0d67 --- /dev/null +++ b/section3/HelloWorld/src/Main.java @@ -0,0 +1,4 @@ +void main() { + IO.println("Hello Madan"); + System.out.print("Hi Java"); +} \ No newline at end of file diff --git a/section7/src/ArithmeticOperatorsDemo.java b/section7/src/ArithmeticOperatorsDemo.java index 9924378..943d6a3 100644 --- a/section7/src/ArithmeticOperatorsDemo.java +++ b/section7/src/ArithmeticOperatorsDemo.java @@ -29,10 +29,10 @@ public static void main(String[] args) { byte num11 = -(-9); int num12 = 42; - num12 += 3.3; // num12 = (int) num12 + 3.3; + num12 += 3.3; // num12 = (int) (num12 + 3.3); int num13 = 42; - num13 -= 3.3; // num13 = (int) num13 - 3.3; + num13 -= 3.3; // num13 = (int) (num13 - 3.3); String str = "Hello"; str += 9; diff --git a/section_29/src/com/eazybytes/java23/MarkDownComments.java b/section_29/src/com/eazybytes/java23/MarkDownComments.java new file mode 100644 index 0000000..f7581a5 --- /dev/null +++ b/section_29/src/com/eazybytes/java23/MarkDownComments.java @@ -0,0 +1,53 @@ +package com.eazybytes.java23; + +/// **This class contains methods for performing basic math operations** +/// @author Eazybytes + /// @version 1.0 +public class MarkDownComments { + + + /// | Input | Output | + /// |-------|-------| + /// | 2,3 | 5 | + /// | 9,2 | 11 | + /// | 25,75 | 100 | + /// **This method adds two numbers** + /// @param a first number + /// @param b second number + /// @return sum of the two numbers + public static int add(int a, int b) { + return a + b; + } + + /// ## This method subtract two numbers + /// - 5,3 = 2 + /// - 9,2 = 7 + /// @param a first number + /// @param b second number + /// @return ***subtraction of the two numbers*** + public static int subtract(int a, int b) { + return a - b; + } + + /// --- + /// # This method multiply two numbers + /// @param a first number + /// @param b second number + /// @return ***multiplication of the two numbers*** + public static int multiply(int a, int b) { + return a * b; + } + + /// # This method divide two numbers + /// ``` + /// @Override + /// public void division() ... + /// ``` + /// @param a first number + /// @param b second number + /// @return ***division of the two numbers*** + public static int divide(int a, int b) { + return a / b; + } + +} diff --git a/section_29/src/com/eazybytes/java24/A_HelloGatherer.java b/section_29/src/com/eazybytes/java24/A_HelloGatherer.java new file mode 100644 index 0000000..039bf56 --- /dev/null +++ b/section_29/src/com/eazybytes/java24/A_HelloGatherer.java @@ -0,0 +1,16 @@ +package com.eazybytes.java24; + +import java.util.List; +import java.util.stream.Gatherer; + +public class A_HelloGatherer { + + public static void main(String[] args) { + var strings = List.of("one", "two", "three","four", "five", "six", "seven", + "eight", "nine", "ten"); + Gatherer gatherer = () -> (state, element, downstream) -> + downstream.push(element.toUpperCase()); + var result = strings.stream().gather(gatherer).toList(); + System.out.println(result); + } +} diff --git a/section_29/src/com/eazybytes/java24/B_DevFriendlyGatherer.java b/section_29/src/com/eazybytes/java24/B_DevFriendlyGatherer.java new file mode 100644 index 0000000..8503995 --- /dev/null +++ b/section_29/src/com/eazybytes/java24/B_DevFriendlyGatherer.java @@ -0,0 +1,17 @@ +package com.eazybytes.java24; + +import java.util.List; +import java.util.stream.Gatherer; + +public class B_DevFriendlyGatherer { + + public static void main(String[] args) { + var strings = List.of("One", "Two", "Three","Four", "Five", "Six", "Seven", + "Eight", "Nine", "Ten"); + Gatherer gatherer = Gatherer.of((_, element, downstream) -> + downstream.push(element.toUpperCase())); + var result = strings.stream().gather(Gatherer.of((_, element, downstream) -> + downstream.push(element.toLowerCase()))).toList(); + System.out.println(result); + } +} diff --git a/section_29/src/com/eazybytes/java24/C_MapFilterGatherer.java b/section_29/src/com/eazybytes/java24/C_MapFilterGatherer.java new file mode 100644 index 0000000..e68aa94 --- /dev/null +++ b/section_29/src/com/eazybytes/java24/C_MapFilterGatherer.java @@ -0,0 +1,21 @@ +package com.eazybytes.java24; + +import java.util.stream.Gatherer; +import java.util.stream.Stream; + +public class C_MapFilterGatherer { + + public static void main(String[] args) { + Gatherer filterAndMapGatherer = Gatherer.of( + (_, element, downstream) -> { + if(element.startsWith("a")) { + return downstream.push(element.toUpperCase()); + } + return true; + } + ); + var result = Stream.of("apple", "banana", "avocado").gather(filterAndMapGatherer).toList(); + System.out.println(result); + + } +} diff --git a/section_29/src/com/eazybytes/java24/D_MutableStateGatherer.java b/section_29/src/com/eazybytes/java24/D_MutableStateGatherer.java new file mode 100644 index 0000000..c86faf0 --- /dev/null +++ b/section_29/src/com/eazybytes/java24/D_MutableStateGatherer.java @@ -0,0 +1,21 @@ +package com.eazybytes.java24; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Gatherer; +import java.util.stream.Stream; + +public class D_MutableStateGatherer { + + public static void main(String[] args) { + // Input - 10, 20, 30, 40 + // Output - 10, 30, 60, 100 + Gatherer cumulativeSum = Gatherer. + ofSequential(AtomicInteger::new, + (state,number,downstream) -> { + int updated = state.addAndGet(number); + return downstream.push(updated); + }); + var result = Stream.of(10, 20, 30, 40).gather(cumulativeSum).toList(); + System.out.println(result); + } +} diff --git a/section_29/src/com/eazybytes/java24/E_FinisherGatherer.java b/section_29/src/com/eazybytes/java24/E_FinisherGatherer.java new file mode 100644 index 0000000..277c5e9 --- /dev/null +++ b/section_29/src/com/eazybytes/java24/E_FinisherGatherer.java @@ -0,0 +1,34 @@ +package com.eazybytes.java24; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Gatherer; +import java.util.stream.Stream; + +public class E_FinisherGatherer { + + public static void main(String[] args) { + // Input - [1, 2, 3, 4, 5, 6, 7] + // Output - [[1, 2, 3], [4, 5, 6], [7]] + Gatherer, List> batchGatherer = + Gatherer.ofSequential(ArrayList::new, + (buffer, item, downstream) -> { + buffer.add(item); + if (buffer.size() == 3) { + downstream.push(new ArrayList<>(buffer)); // emit a full batch + buffer.clear(); // clear buffer + } + return true; + }, (buffer, downstream) -> { + if (!buffer.isEmpty()) { + downstream.push(new ArrayList<>(buffer)); // flush leftover items + } + }); + var result = Stream.of(1, 2, 3, 4, 5, 6, 7) + .map(input -> input*2) + .gather(batchGatherer).toList(); + System.out.println(result); + + } +} diff --git a/section_29/src/com/eazybytes/java24/F_ParallelGatherer.java b/section_29/src/com/eazybytes/java24/F_ParallelGatherer.java new file mode 100644 index 0000000..3312de8 --- /dev/null +++ b/section_29/src/com/eazybytes/java24/F_ParallelGatherer.java @@ -0,0 +1,33 @@ +package com.eazybytes.java24; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Gatherer; +import java.util.stream.Stream; + +public class F_ParallelGatherer { + + public static void main(String[] args) { + Gatherer parallelSum = + Gatherer.of(AtomicInteger::new, + (sum, number, downstream) -> { + System.out.printf("[Integrator] Thread: %s | number: %d%n", + Thread.currentThread().getName(), number); + sum.addAndGet(number); + return true; + }, + (s1,s2) -> { + System.out.printf("[Combiner] Thread: %s | combining %d + %d%n", + Thread.currentThread().getName(), s1.get(), s2.get()); + s1.addAndGet(s2.get()); // combiner + return s1; + }, + (sum,downstream) -> { + System.out.printf("[Finisher] Thread: %s | result: %d%n", + Thread.currentThread().getName(), sum.get()); + downstream.push(sum.get()); + }); + + var result = Stream.of(10, 20, 30, 40, 50, 60).parallel().gather(parallelSum).toList(); + System.out.println(result); + } +} diff --git a/section_29/src/com/eazybytes/java24/G_InterruptGatherer.java b/section_29/src/com/eazybytes/java24/G_InterruptGatherer.java new file mode 100644 index 0000000..1a24ecb --- /dev/null +++ b/section_29/src/com/eazybytes/java24/G_InterruptGatherer.java @@ -0,0 +1,26 @@ +package com.eazybytes.java24; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Gatherer; +import java.util.stream.Stream; + +public class G_InterruptGatherer { + + public static void main(String[] args) { + List largeList = Stream.iterate(1, i -> i + 1) + .limit(1000) + .toList(); // simulate a large list + Gatherer limitGatherer = Gatherer.of( + (_, element, downstream) -> { + System.out.println(element); + downstream.push(element); + return true; + }); + var res = largeList.stream().parallel().gather(limitGatherer).limit(10).toList(); + System.out.println(res); + // Downstream is going to start in non rejecting state + // A downstream can only go from non-rejecting โ†’ rejecting + // The state only changes when you push an element to it + } +} diff --git a/section_29/src/com/eazybytes/java24/H_ChainingGatherer.java b/section_29/src/com/eazybytes/java24/H_ChainingGatherer.java new file mode 100644 index 0000000..5c18f0a --- /dev/null +++ b/section_29/src/com/eazybytes/java24/H_ChainingGatherer.java @@ -0,0 +1,23 @@ +package com.eazybytes.java24; + +import java.util.stream.Gatherer; +import java.util.stream.Stream; + +public class H_ChainingGatherer { + + public static void main(String[] args) { + Gatherer upper = Gatherer.of + ((_, element, downstream) -> downstream.push(element.toUpperCase())); + + Gatherer filter = Gatherer.of((_, element, downstream) -> { + if (element.startsWith("J")) { + downstream.push(element); + } + return true; + }); + + var result = Stream.of("java", "spring", "react").gather(upper.andThen(filter)).toList(); + System.out.println(result); + + } +} diff --git a/section_29/src/com/eazybytes/java24/I_Fold.java b/section_29/src/com/eazybytes/java24/I_Fold.java new file mode 100644 index 0000000..5b4a951 --- /dev/null +++ b/section_29/src/com/eazybytes/java24/I_Fold.java @@ -0,0 +1,22 @@ +package com.eazybytes.java24; + +import java.util.Optional; +import java.util.stream.Gatherers; +import java.util.stream.Stream; + +public class I_Fold { + + public static void main(String[] args) { + Optional totalDigits = Stream.of(10, 200, 3, 45) + .gather( + Gatherers.fold( + () -> 0, + (count, num) -> count + String.valueOf(num).length() + ) + ) + .findFirst(); + + System.out.println(totalDigits); // Output: Optional[8] + + } +} diff --git a/section_29/src/com/eazybytes/java24/J_Scan.java b/section_29/src/com/eazybytes/java24/J_Scan.java new file mode 100644 index 0000000..569ade1 --- /dev/null +++ b/section_29/src/com/eazybytes/java24/J_Scan.java @@ -0,0 +1,20 @@ +package com.eazybytes.java24; + +import java.util.List; +import java.util.stream.Gatherers; +import java.util.stream.Stream; + +public class J_Scan { + + public static void main(String[] args) { + + List runningSums = Stream.of(1, 2, 3, 4) + .gather( + Gatherers.scan(() -> 0, (sum, next) -> sum + next) + ) + .toList(); + + System.out.println(runningSums); // Output: [1, 3, 6, 10] + + } +} diff --git a/section_29/src/com/eazybytes/java24/K_MapConcurrent.java b/section_29/src/com/eazybytes/java24/K_MapConcurrent.java new file mode 100644 index 0000000..39263e3 --- /dev/null +++ b/section_29/src/com/eazybytes/java24/K_MapConcurrent.java @@ -0,0 +1,30 @@ +package com.eazybytes.java24; + +import java.util.List; +import java.util.stream.Gatherers; + +public class K_MapConcurrent { + + public static void main(String[] args) { + List articles = List.of( + "Java is a high-level, class-based, object-oriented programming language.", + "Spring Boot makes it easy to create stand-alone, production-grade applications.", + "Microservices architecture enables better scalability and maintainability.", + "Text processing is a common use case for functional programming.", + "Streams in Java provide a modern way to process collections efficiently." + ); + + // Count words concurrently using mapConcurrent + List wordCounts = articles.parallelStream() + .gather(Gatherers.mapConcurrent(10, article -> + article.split("\\s+").length + )) + .toList(); + + + for (int i = 0; i < articles.size(); i++) { + System.out.printf("Article %d word count: %d%n", i + 1, wordCounts.get(i)); + } + + } +} diff --git a/section_29/src/com/eazybytes/java24/L_WindowFixed.java b/section_29/src/com/eazybytes/java24/L_WindowFixed.java new file mode 100644 index 0000000..2e6cb38 --- /dev/null +++ b/section_29/src/com/eazybytes/java24/L_WindowFixed.java @@ -0,0 +1,14 @@ +package com.eazybytes.java24; + +import java.util.stream.Gatherers; +import java.util.stream.Stream; + +public class L_WindowFixed { + + public static void main(String[] args) { + var output = Stream.of(1, 2, 3, 4, 5, 6) + .gather(Gatherers.windowFixed(2)) + .toList(); + System.out.println(output); + } +} diff --git a/section_29/src/com/eazybytes/java24/M_WindowSliding.java b/section_29/src/com/eazybytes/java24/M_WindowSliding.java new file mode 100644 index 0000000..19d917d --- /dev/null +++ b/section_29/src/com/eazybytes/java24/M_WindowSliding.java @@ -0,0 +1,15 @@ +package com.eazybytes.java24; + +import java.util.List; +import java.util.stream.Gatherers; +import java.util.stream.Stream; + +public class M_WindowSliding { + + public static void main(String[] args) { + List> result = + Stream.of(1,2,3,4,5,6,7,8) + .gather(Gatherers.windowSliding(2)).toList(); + System.out.println(result); + } +} diff --git a/section_30/.gitignore b/section_30/.gitignore new file mode 100644 index 0000000..13275f1 --- /dev/null +++ b/section_30/.gitignore @@ -0,0 +1,30 @@ +### IntelliJ IDEA ### +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ +.kotlin + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/section_30/README.md b/section_30/README.md new file mode 100755 index 0000000..8a04713 --- /dev/null +++ b/section_30/README.md @@ -0,0 +1,606 @@ +# ๐Ÿงฉ **Java 25 Features** + +## **Module Import Declarations** + +### ๐Ÿ“˜ Definition +The **Module Import Declarations** feature introduced in **Java 25** allows importing entire modules directly within a source file. +Instead of importing individual packages or classes, developers can use a single statement such as: +```java +import module java.base; +``` +This automatically includes all the packages exported by that module (for example, java.util, java.io, etc.), removing the need for +multiple import statements. +### ๐Ÿ’ป Code Example + +๐Ÿงพ Before (Traditional Imports) +```java +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class ImportModule { + public static void main(String[] args) { + // your logic here + } +} +``` +โœ… After (Using import module) +```java +import module java.base; + +public class ImportModule { + public static void main(String[] args) { + // your logic here + } +} +``` +### ๐Ÿง  Code Explanation + +- import module `java.base` โ†’ Imports the entire `java.base` module, making all exported packages available. +- Removes the need to explicitly import every class or package individually. +- Works perfectly for modular and single-file Java programs. + +### โš ๏ธ Ambiguous Imports +When importing multiple modules, you might encounter classes with the same simple name (for example, java.util.Date +and java.sql.Date), causing ambiguity. + +Example โ€” Ambiguous Import + +```java +import module java.base; // exports java.util.Date +import module java.sql; // exports java.sql.Date + +import java.util.Date; + +Date d = new Date(); // โŒ Error: Ambiguous name! +``` +Solution โ€” Use a Single-Type Import +```java +import module java.base; // exports java.util.Date +import module java.sql; // exports java.sql.Date +import java.sql.Date; // resolves the ambiguity + +Date d = new Date(); // โœ… Now refers to java.sql.Date +``` + +๐Ÿงฉ Use single-type imports when multiple modules export classes with the same simple name. + + +### โš™๏ธ Additional Details +๐Ÿ”น **Performance Impact** + +Whether you import a specific class, or an entire package, or an entire module, only the classes that your code actually uses are +loaded at runtime. + +โžก๏ธ So, thereโ€™s no performance overhead with module imports. + +๐Ÿ”น **Compact Source File** + +The java.base module is automatically imported on demand in a compact source file, reducing the boilerplate and keeping your code +clean and minimal. + +๐Ÿ”น **Unnamed Module** + +The import module statement requires a module name. Hence, packages from the unnamed module (i.e., classpath code) cannot be +imported using this feature. + +## **Compact Source Files & Instance Main Methods** + +Java 25 introduces Compact Source Files and Instance Main Methods to make Java more approachable and beginner-friendly. +These features simplify how you write, compile, and run Java code โ€” reducing boilerplate and allowing programs to start without +explicit class declarations or traditional main static methods. + +### ๐Ÿ’ป Classic vs. Compact Example +๐Ÿงพ Before (Traditional HelloWorld) +```java +public class HelloWorld { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +} +``` + +โœ… After (Compact Source File in Java 25) +```java +void main() { + IO.println("Hello, World!"); +} +``` +### ๐Ÿง  Code Explanation + +- **No class declaration needed :** +The compiler automatically creates an implicit top-level class behind the scenes. +- **No static keyword required :** +The main method can now be an instance method โ€” Java will automatically create an instance to run it. +- **Automatic module import :** +All public types from the java.base module (like List, Math, IO, etc.) are available automatically. + +### ๐Ÿงฉ Key Features +#### ๐Ÿงฑ Implicit Class + +When you write a compact source file: + +- The compiler generates a final, top-level class automatically. +- The class extends `java.lang.Object` and has no explicit constructor or interfaces. +- All methods and fields in the file become members of that implicit class. +- It must include a launchable main method, or it will fail to compile. + +#### โš™๏ธ Automatic Module Import +In compact source files, Java automatically imports everything from the `java.base` module. + +```java + +void main() { + var list = List.of("Alice", "Bob", "Charlie"); + for (var name : list) { + IO.println("Hello, " + name); + } +} +``` +โžก๏ธ No need to write import `java.util.List` + +#### ๐Ÿ’ก Instance Main Method Variants + +The following method signatures are allowed: +```java +void main() {} +public void main() {} +static void main() {} +public static void main() {} +public static void main(String[] args) {} +``` + +When both `main(String[] args)` and `main()` exist, Java prioritizes `main(String[] args)`. + +#### ๐Ÿ–ฅ๏ธ Console Interaction Simplified +A new utility class โ€” `java.lang.IO` โ€” allows simpler input/output: +```java +void main() { + var name = IO.readln("Enter your name: "); + IO.println("Hello, " + name); +} +``` +- No need for Scanner or System.out.println. +- Makes interactive console programs beginner-friendly. + +### ๐Ÿ“ How It Works + +Compact source files: +- Are compiled directly (no class keyword required). +- Automatically import java.base. +- Must have a valid `main()` method. +- Are great for quick prototypes, educational purposes, and scripting. + + +## Flexible Constructor Bodies + +The Flexible Constructor Bodies feature in Java 25 relaxes a long-standing rule in Java constructors. Traditionally, the first +statement of any constructor had to be a call to `super(...)` or `this(...)`. +With this enhancement, you can now execute statements before these calls, allowing for argument validation and preprocessing. + +### ๐Ÿ’ป Traditional vs. Flexible Example +๐Ÿงพ Before (Strict Constructor Order) +```java +class Car extends Vehicle { + Car(int speed) { + super(speed); // Must be the first statement + if (speed > 200) throw new IllegalArgumentException("Car too fast!"); + } +} +``` + +โœ… After (Flexible Constructor Bodies in Java 25) +```java +class Car extends Vehicle { + Car(int speed) { + if (speed < 0) throw new IllegalArgumentException("Invalid speed"); + if (speed > 200) throw new IllegalArgumentException("Car too fast!"); + super(speed); // Can now be called later + } +} +``` + +### ๐Ÿง Code Explanation + +- **Before Java 25 :** +The constructor chaining rule enforced `super()` or `this()` as the first statement. Developers had to use static helper methods +to validate or process arguments. +- **Now (Java 25) :** +You can perform validations or compute values before invoking the superclass constructor. This gives you flexibility without breaking +the initialization order. + +### โš™๏ธ Benefits +#### ๐Ÿงฉ 1. Argument Validation +Developers can now check arguments before calling super() +#### ๐Ÿงฉ 2. Improved Code Readability +No need for helper methods or static validators โ€” logic stays within the constructor. +#### ๐Ÿงฉ 3. Safer Initialization +Fixes issues where superclass constructors accidentally access uninitialized subclass fields: +```java + +class Account { + public Account() { check(); } + public void check() {} +} + +class SavingsAccount extends Account { + private String accountNumber; + public SavingsAccount(String number) { + this.accountNumber = number; + super(); // allowed after initialization + } + + @Override + public void check() { + if (accountNumber.isEmpty()) throw new RuntimeException("Invalid account"); + } +} +``` +### โš ๏ธ Restrictions + +While this feature offers flexibility, certain rules still apply: +- โŒ Cannot use this or super before their invocation. +- โŒ Cannot access instance fields or methods before calling `super()` or `this()`. +- โœ… You can assign values to only uninitialized fields. +- โœ… You can perform parameter checks, or static method calls safely. + +### ๐Ÿงช Example โ€” Invalid Use +```java +class Book extends Page { + String title; + int pages = 100; + + Book() { + System.out.println(this); // โŒ Not allowed (implicit this) + title = "Java 25"; // โœ… Allowed (uninitialized field) + pages = 200; // โŒ Error (already initialized) + super(); // Constructor call + } +} +``` +### Example โ€” Executing Statements Before `this()` +```java +class Course { + String courseName; + int duration; + + public Course(String name, int duration) { + this.courseName = name; + this.duration = duration; + } + + public Course(String prefix, String name, int duration) { + Objects.requireNonNull(prefix); + Objects.requireNonNull(name); + if (duration <= 0) throw new IllegalArgumentException("Invalid duration"); + this(prefix + name, duration); // โœ… Safe delegation + } +} +``` + +## Scoped Values + +The Scoped Values feature introduced in Java 25 provides a new, safer, and faster mechanism to share immutable data between +methods and threads without explicit parameter passing. + +It acts as a modern alternative to `ThreadLocal` โ€” easier to reason about, more efficient, and less prone to memory leaks. + +### ๐Ÿ’ก Why Scoped Values? + +In traditional Java applications, contextual data (like UserContext, Locale, or Transaction) is often passed as method parameters +or stored in ThreadLocal variables. + +Both approaches have limitations: + +- **Parameter Passing Hell** โ€” every method needs a context argument, even if unused. +- **ThreadLocal Problems** โ€” mutable, requires manual cleanup, and may cause memory leaks. + +### ๐Ÿ’ป Example โ€“ Parameter Passing Hell +```java +public class OrderService { + + public void processOrder(Order order, UserContext context) { + validateOrder(order, context); + calculatePrice(order, context); + saveOrder(order, context); + } + + private void validateOrder(Order order, UserContext context) { + checkUserPermissions(context); + } + + private void calculatePrice(Order order, UserContext context) { + applyUserDiscount(order, context); + } +} +``` +โŒ Problem: The context parameter must be passed around everywhere, even to methods that donโ€™t use it. + +### ๐Ÿงฉ ThreadLocal Approach +```java +public class OrderService { + private static final ThreadLocal CONTEXT = new ThreadLocal<>(); + + public void processOrder(Order order, UserContext context) { + CONTEXT.set(context); // Set context + try { + validateOrder(order); + calculatePrice(order); + saveOrder(order); + } finally { + CONTEXT.remove(); // โ— Must be cleaned up manually + } + } + + private void validateOrder(Order order) { + UserContext context = CONTEXT.get(); // Get context + checkUserPermissions(context); + } +} +``` + +### โš ๏ธ Problems with ThreadLocal + +- **Unconstrained Mutability** โ€” any code can modify the context. +- **Unbounded Lifetime** โ€” forgetting `remove()` causes memory leaks. +- **Expensive Inheritance** โ€” copying all `ThreadLocals` to child threads increases memory overhead. + +### โœ… Scoped Values โ€“ The Modern Solution + +`ScopedValue` addresses all these issues by: +- Storing immutable data that canโ€™t be changed once set. +- Being automatically destroyed after its scope ends. +- Having no cleanup responsibilities for the developer. + +### ๐Ÿ’ป Example โ€“ Scoped Values in Action +```java +public class OrderService { + + private static final ScopedValue CONTEXT = + ScopedValue.newInstance(); + + public void processOrder(Order order, UserContext context) { + ScopedValue.where(CONTEXT, context).run(() -> { + validateOrder(order); + calculatePrice(order); + saveOrder(order); + }); + // Context automatically destroyed here + } + + private void validateOrder(Order order) { + UserContext context = CONTEXT.get(); // Read context + checkUserPermissions(context); + } +} +``` +### โœ… Key Points +- Scoped values are immutable โ€” once set, they canโ€™t be modified. +- They are automatically cleaned up after the run() block ends. +- They work seamlessly with virtual threads and concurrent code. + +### ๐Ÿงช Simple Example +```java +public class SimpleExample { + + private static final ScopedValue USERNAME = + ScopedValue.newInstance(); + + public void doWork() { + ScopedValue.where(USERNAME, "Alice").run(() -> { + processTask(); // Can access USERNAME + }); + // USERNAME no longer accessible here + } + + private void processTask() { + String user = USERNAME.get(); // Returns "Alice" + System.out.println("Processing for: " + user); + callAnotherMethod(); + } + + private void callAnotherMethod() { + String user = USERNAME.get(); // Still returns "Alice" + System.out.println("Still processing for: " + user); + } +} +``` + +### ๐Ÿง  Understanding Dynamic Scope + +Scoped values follow dynamic scoping, not lexical scoping. That means they are accessible only during the lifetime of the run() block +and within any method invoked from it. +```java + +public void methodA() { + ScopedValue.where(NAME, "John").run(() -> { + methodB(); // NAME accessible here + }); + // NAME not accessible here +} + +public void methodB() { + methodC(); // Still within dynamic scope +} + +public void methodC() { + String name = NAME.get(); // Returns "John" +} +``` +๐Ÿ”„ Scoped values propagate dynamically across call chains during runtime + +### ๐Ÿ” Rebinding (Nested Scopes) +Scoped values can be rebound โ€” meaning you can assign a new value temporarily within a nested scope. +```java +private static final ScopedValue LEVEL = + ScopedValue.newInstance(); + +public void outerMethod() { + ScopedValue.where(LEVEL, "Level 1").run(() -> { + System.out.println(LEVEL.get()); // Level 1 + innerMethod(); + System.out.println(LEVEL.get()); // Level 1 + }); +} + +public void innerMethod() { + System.out.println(LEVEL.get()); // Level 1 + ScopedValue.where(LEVEL, "Level 2").run(() -> { + System.out.println(LEVEL.get()); // Level 2 + deepMethod(); + }); + System.out.println(LEVEL.get()); // Back to Level 1 +} + +public void deepMethod() { + System.out.println(LEVEL.get()); // Level 2 +} +``` +Each `ScopedValue.where()` call defines a new nested scope. Once the inner scope ends, the value automatically reverts to its +outer context. + + +### ๐Ÿš€ Conclusion + +Scoped Values modernize context sharing in Java by replacing ThreadLocal with a more efficient, safer, and immutable alternative. +They make context handling: +- Cleaner ๐Ÿงผ +- Faster โšก +- Safer ๐Ÿ”’ +- Perfectly aligned with virtual threads and structured concurrency. + +Java 25โ€™s Scoped Values = Simpler, safer, and smarter context propagation ๐ŸŒ + +## Ahead-of-Time (AOT) Class Loading and Linking + +The Ahead-of-Time (AOT) feature in Java 25 significantly improves application startup time by allowing the JVM to preload, +prelink, and cache classes before execution. + +Instead of performing class loading, verification, and linking every time the JVM starts, AOT does this once during a training run +and reuses the cached results for subsequent runs. + +Think of AOT as meal prepping for your JVM โ€” instead of cooking from scratch every day (JIT), you cook once and reheat quickly +when needed ๐Ÿฑโšก. + +### ๐Ÿš€ Traditional Java Startup (JIT Compilation) + +When you run: +``` +java MyApp +``` +The JVM performs these steps: + +**1**. Starts the JVM. +**2**. Reads JAR files from disk. +**3**. Parses all class files. +**4**. Loads classes into memory. +**5**. Links classes together (verifies and resolves references). +**6**. Runs static initializers. +**7**. Finally, starts your application. + +โžก๏ธ This happens every single time the application starts. + +### ๐Ÿ’ก Ahead-of-Time (AOT) Approach + +Instead of doing all this work during startup, AOT performs it once ahead-of-time and caches the results for reuse. + +#### ๐Ÿ” Workflow Overview +Training Run (Recording Phase): +- Run your app once. +- The JVM records all classes loaded during execution. +- It saves that information in a configuration file. +Production Run (Execution Phase): +- JVM loads preprocessed classes directly from the cache. +- Application starts almost instantly. + +**Result :** ๐Ÿš€ Drastically faster startup times! + +### ๐Ÿ’ป Step-by-Step โ€” AOT in Action +#### ๐Ÿงพ Step 1: Training Run (Record) +Run your app once to record what classes it loads. +``` +java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf \ + -cp app.jar com.example.App +``` + +- JVM monitors the applicationโ€™s class loading. +- Saves all loaded classes to a config file app.aotconf. + +#### ๐Ÿงฑ Step 2: Create AOT Cache + +Generate the prelinked and preverified cache. +``` +java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf \ + -XX:AOTCache=app.aot -cp app.jar +``` + +This processes and stores prelinked class metadata into the cache file app.aot. + +#### โšก Step 3: Production Run (Use the Cache) + +Finally, run your app using the cached data. +``` +java -XX:AOTCache=app.aot -cp app.jar com.example.App +``` +โœ… Classes are instantly loaded from cache โ€” no parsing, linking, or verification needed! + +### ๐Ÿงฉ Simplified One-Step AOT Command (Java 25 Enhancement) + +In JDK 25, the AOT process is streamlined into a single command, eliminating multiple steps. + +โœ… One-Step Cache Creation +``` +java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App +``` +Then, run the app normally using: +``` +java -XX:AOTCache=app.aot -cp app.jar com.example.App +``` + +### ๐Ÿ’ช Benefits of the New Command + +- **Simpler :** Only one command (training + creation combined). +- **Cleaner :** No leftover configuration files. +- **Automation-Friendly :** Perfect for CI/CD and build pipelines. + +### ๐Ÿง  Whatโ€™s Inside an AOT Cache? +**โœ… Classes That Can Be Cached** +- **JDK Classes :** String, ArrayList, HashMap, etc. +- **Application Classes :** Your appโ€™s compiled classes and JARs. +- **Library Classes :** Frameworks like Spring, Hibernate, etc. +- Classes must be loaded by built-in classloaders. + +โŒ Classes That Cannot Be Cached +- Classes loaded via custom classloaders. +- Signed classes (restricted for security). +- Old bytecode requiring legacy verification. +- Dynamically generated classes at runtime. + +### ๐Ÿงฎ Whatโ€™s Precomputed and Cached? + +AOT precomputes: + +- โœ… Parsed bytecode โ†’ ready-to-use class structures. +- โœ… Resolved references โ†’ all links between classes established. +- โœ… Verified code โ†’ bytecode verified once. +- โœ… Loaded metadata โ†’ class, field, and method details stored. + +This makes runtime startup instant โ€” JVM just reads from the cache instead of redoing work. + +### ๐Ÿ’ผ Using AOT in Spring Boot Applications + +**Step 1: Build your Spring Boot JAR** +``` +mvn clean package +``` +**Step 2: Create an AOT cache (Java 25 style)** +``` +java -XX:AOTCacheOutput=myapp.aot -jar target/myapp.jar +``` +**Step 3: Deploy and run with AOT cache** +``` +java -XX:AOTCache=myapp.aot -jar target/myapp.jar +``` +โœ… The Spring Boot app now starts up significantly faster โ€” ideal for serverless deployments and microservices. \ No newline at end of file diff --git a/section_30/src/HelloWorld.java b/section_30/src/HelloWorld.java new file mode 100644 index 0000000..83af5f7 --- /dev/null +++ b/section_30/src/HelloWorld.java @@ -0,0 +1,17 @@ +String greeting = "Hello, World!"; + +String greeting() { + return "Hello, World!"; +} + +void main() { + var name = IO.readln("Enter your name:"); + IO.println("Hello :" +name); + IO.println(greeting()); + + var authors = List.of("James", "Bill", "Guy", "Alex", "Dan", "Gavin"); + for (var author : authors) { + IO.println(author + ": " + author.length()); + } + +} \ No newline at end of file diff --git a/section_30/src/com/eazybytes/java25/flexconstructor/Account.java b/section_30/src/com/eazybytes/java25/flexconstructor/Account.java new file mode 100644 index 0000000..1758023 --- /dev/null +++ b/section_30/src/com/eazybytes/java25/flexconstructor/Account.java @@ -0,0 +1,13 @@ +package com.eazybytes.java25.flexconstructor; + +public class Account { + + public Account() { + check(); // calls subclass's override + } + + public void check() { + + } + +} diff --git a/section_30/src/com/eazybytes/java25/flexconstructor/Car.java b/section_30/src/com/eazybytes/java25/flexconstructor/Car.java new file mode 100644 index 0000000..3082874 --- /dev/null +++ b/section_30/src/com/eazybytes/java25/flexconstructor/Car.java @@ -0,0 +1,18 @@ +package com.eazybytes.java25.flexconstructor; + +public class Car extends Vehicle { + + Car(int speed) { + if (speed < 0) throw new IllegalArgumentException("Invalid speed"); + if (speed > 200) throw new IllegalArgumentException("Car too fast"); + super(speed); // Forced first call + } + + private static int verifySpeed(int speed) { + if (speed < 0) throw new IllegalArgumentException("Invalid speed"); + if (speed > 200) throw new IllegalArgumentException("Car too fast"); + return speed; + } + + +} diff --git a/section_30/src/com/eazybytes/java25/flexconstructor/SavingsAccount.java b/section_30/src/com/eazybytes/java25/flexconstructor/SavingsAccount.java new file mode 100644 index 0000000..b501d51 --- /dev/null +++ b/section_30/src/com/eazybytes/java25/flexconstructor/SavingsAccount.java @@ -0,0 +1,24 @@ +package com.eazybytes.java25.flexconstructor; + +public class SavingsAccount extends Account { + + private String accountNumber; + + public SavingsAccount(String number) { + this.accountNumber = number; + super(); + } + + @Override + public void check() { + if (accountNumber.length() == 0) { + throw new RuntimeException("Invalid account"); + } + } + + public static void main(String[] args) { + SavingsAccount account = new SavingsAccount("1234567890"); + } + + +} diff --git a/section_30/src/com/eazybytes/java25/flexconstructor/Vehicle.java b/section_30/src/com/eazybytes/java25/flexconstructor/Vehicle.java new file mode 100644 index 0000000..9b058f4 --- /dev/null +++ b/section_30/src/com/eazybytes/java25/flexconstructor/Vehicle.java @@ -0,0 +1,12 @@ +package com.eazybytes.java25.flexconstructor; + +public class Vehicle { + + int speed; + + Vehicle(int speed) { + this.speed = speed; + } + + +} diff --git a/section_30/src/com/eazybytes/java25/moduleimport/ImportModuleDemo.java b/section_30/src/com/eazybytes/java25/moduleimport/ImportModuleDemo.java new file mode 100644 index 0000000..d663b7f --- /dev/null +++ b/section_30/src/com/eazybytes/java25/moduleimport/ImportModuleDemo.java @@ -0,0 +1,54 @@ +package com.eazybytes.java25.moduleimport; + +import module java.base; + +public class ImportModuleDemo { + + public static void main(String[] args) { + // java.util.Scanner + Scanner scanner = new Scanner(System.in); + System.out.println("Enter some names (type 'exit' to finish):"); + + // java.util.List, java.util.ArrayList + List names = new ArrayList<>(); + + while (true) { + String input = scanner.nextLine(); + if ("exit".equalsIgnoreCase(input)) { + break; + } + names.add(input); + } + + // java.util.Collections + Collections.sort(names); + + // java.util.Date + Date now = new Date(); + + // java.io.File and FileWriter + File file = new File("names.txt"); + try (FileWriter writer = new FileWriter(file)) { + writer.write("Sorted names (saved on " + now + "):\n"); + for (String name : names) { + writer.write(name + "\n"); + } + System.out.println("Names saved to " + file.getAbsolutePath()); + } catch (IOException e) { + e.printStackTrace(); + } + + // java.io.BufferedReader and FileReader + System.out.println("\nReading names back from the file:"); + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + System.out.println(line); + } + } catch (IOException e) { + e.printStackTrace(); + } + + scanner.close(); + } +} diff --git a/section_30/src/com/eazybytes/java25/scoped/NestedScope.java b/section_30/src/com/eazybytes/java25/scoped/NestedScope.java new file mode 100644 index 0000000..7fcc5e3 --- /dev/null +++ b/section_30/src/com/eazybytes/java25/scoped/NestedScope.java @@ -0,0 +1,33 @@ +package com.eazybytes.java25.scoped; + +public class NestedScope { + + private static final ScopedValue LEVEL = ScopedValue.newInstance(); + + public void outerMethod() { + ScopedValue.where(LEVEL, "Level 1").run(() -> { + System.out.println(LEVEL.get()); // Prints "Level 1" + innerMethod(); + System.out.println(LEVEL.get()); // Still prints "Level 1" + }); + } + + public void innerMethod() { + System.out.println(LEVEL.get()); // Prints "Level 1" + + ScopedValue.where(LEVEL, "Level 2").run(() -> { + System.out.println(LEVEL.get()); // Prints "Level 2" + deepMethod(); + }); + + System.out.println(LEVEL.get()); // Back to "Level 1" + } + + public void deepMethod() { + System.out.println(LEVEL.get()); // Prints "Level 2" + } + + void main() { + new NestedScope().outerMethod(); + } +} diff --git a/section_30/src/com/eazybytes/java25/scoped/SimpleExample.java b/section_30/src/com/eazybytes/java25/scoped/SimpleExample.java new file mode 100644 index 0000000..9e3fed8 --- /dev/null +++ b/section_30/src/com/eazybytes/java25/scoped/SimpleExample.java @@ -0,0 +1,46 @@ +package com.eazybytes.java25.scoped; + +public class SimpleExample { + + private static final ScopedValue USER_NAME = ScopedValue.newInstance(); + private static final ScopedValue TRANSACTION_ID = ScopedValue.newInstance(); + + public void doWork() { + ScopedValue.where(USER_NAME, "Alice").where(TRANSACTION_ID, "12345") + .run(() -> { + processTask(); + }); + if(USER_NAME.isBound()) { + String user = USER_NAME.get(); // Returns "Alice" + IO.println("Testing the scope for the user: " + user); + } + if (TRANSACTION_ID.isBound()) { + String transactionID = TRANSACTION_ID.get(); // Returns "12345" + IO.println("Testing the scope for the transactionID: " + transactionID); + } + } + + private void processTask() { + if(USER_NAME.isBound()) { + String user = USER_NAME.get(); // Returns "Alice" + IO.println("Processing for the user: " + user); + } + if (TRANSACTION_ID.isBound()) { + String transactionID = TRANSACTION_ID.get(); // Returns "12345" + IO.println("Processing for the transactionID: " + transactionID); + } + callAnotherMethod(); + } + + private void callAnotherMethod() { + String user = USER_NAME.get(); // Returns "Alice" + IO.println("Still Processing for the user: " + user); + String transactionID = TRANSACTION_ID.get(); // Returns "12345" + IO.println("Still Processing for the transactionID: " + transactionID); + } + + public static void main(String[] args) { + new SimpleExample().doWork(); + } + +}