From 8d8feb4981e46fd37ff33494903ced6428e0938d Mon Sep 17 00:00:00 2001 From: Hafeezbaig Date: Wed, 9 Oct 2024 23:44:00 +0530 Subject: [PATCH 1/6] sections added for review - 1 --- missing-info.md | 398 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 missing-info.md diff --git a/missing-info.md b/missing-info.md new file mode 100644 index 00000000..9f6d6fa9 --- /dev/null +++ b/missing-info.md @@ -0,0 +1,398 @@ +# Missing Info in Lectures From Github Repo + +## Section 3: Introduction to Java Programming with Jshell using Multiplication Table + +### Step 10 - Printing output to console with Java - Puzzles: + +### Whitespace is ignored by the compiler when used around numeric expressions. + +```java + jshell> System.out.println(24 * 60 * 60) + 86400 + jshell> System.out.println(24 * 60 * 60) + 86400 + jshell> +``` +--- +### Step 14 - Introduction to Variables in Java - Exercises and Puzzles + +### Let's consider another example: + +```java + jshell> int number = "Hello World" + | Error: + | incompatible types: java.lang.String cannot be converted to int + | int number = "Hello World" + |_____________^--------------^ + jshell> +``` + +- number is an int variable, and we are trying to store a String value "Hello World". Not allowed. + +--- + +### Step 16 - How are variables stored in memory? + +### An assignment to a constant literal is not allowed. + +```java + jshell> 20 = var + | Error: + | unexpected type + | required : variable + | found : value + | 20 = var + | ^^ + + jshell> +``` + +--- + +### Additional Coding Exercises: + +### Programming Exercise 1: Multiplication Table for Any Number + +Objective: Allow the user to input any number and display its multiplication table from 1 to 10. + +#### Instructions: + +- Write a program that prompts the user to enter a number. +- Use a loop to display the multiplication table for the entered number from 1 to 10. +- Format the output using System.out.printf() for clean display. + +#### Sample Code: + +```java +import java.util.Scanner; + +public class MultiplicationTable { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + // Prompt user for input + System.out.print("Enter a number to display its multiplication table: "); + int number = scanner.nextInt(); + + // Display multiplication table for the entered number + System.out.println("Multiplication Table for " + number + ":"); + for (int i = 1; i <= 10; i++) { + System.out.printf("%d * %d = %d%n", number, i, number * i); + } + + scanner.close(); + } +} +``` + +#### Expected Output: + +```java +Enter a number to display its multiplication table: 7 +Multiplication Table for 7: +7 * 1 = 7 +7 * 2 = 14 +7 * 3 = 21 +7 * 4 = 28 +7 * 5 = 35 +7 * 6 = 42 +7 * 7 = 49 +7 * 8 = 56 +7 * 9 = 63 +7 * 10 = 70 +``` + +--- + +### Programming Exercise 2: Even Numbers Table + +Objective: Generate and print the multiplication table for all even numbers between 2 and 10. + +#### Instructions: + +- Write a program that generates the multiplication table for all even numbers between 2 and 10. +- Use nested loops to calculate and display each table. +- Format the output using System.out.printf() for clean display. + +#### Sample Code: + +```java +public class EvenMultiplicationTable { + public static void main(String[] args) { + System.out.println("Multiplication Tables for Even Numbers (2 to 10):"); + + // Loop through even numbers from 2 to 10 + for (int number = 2; number <= 10; number += 2) { + System.out.printf("Multiplication Table for %d:%n", number); + for (int i = 1; i <= 10; i++) { + System.out.printf("%d * %d = %d%n", number, i, number * i); + } + System.out.println(); // Print a blank line for better readability + } + } +} +``` + +#### Expected Output: + +```java +Multiplication Tables for Even Numbers (2 to 10): +Multiplication Table for 2: +2 * 1 = 2 +2 * 2 = 4 +2 * 3 = 6 +2 * 4 = 8 +2 * 5 = 10 +2 * 6 = 12 +2 * 7 = 14 +2 * 8 = 16 +2 * 9 = 18 +2 * 10 = 20 + +Multiplication Table for 4: +4 * 1 = 4 +4 * 2 = 8 +4 * 3 = 12 +4 * 4 = 16 +4 * 5 = 20 +4 * 6 = 24 +4 * 7 = 28 +4 * 8 = 32 +4 * 9 = 36 +4 * 10 = 40 + +... (and so on for 6, 8, and 10) +``` + +--- + +## Section 4: Introduction to Java Method with Multiplication Table + +### Step 04 - Introduction to Java Methods - Arguments and Parameters + +### Snippet-5 : Parameter type mismatch + +- Java is a strongly typed language, with strict rules laid out for type compatibility. We saw that with variables, and how they play out with expressions and assignments. + +- The same type compatibility rules are enforced by the compiler, when it needs to match the arguments from method calls with method definition. + +```java + jshell> sayHelloWorld("value") + | Error: + | incompatible types: java.lang.String cannot be converted to int + | sayHelloWorld("value") + | ^-----^ + jshell> sayHelloWorld(4.5) + | Error: + | incompatible types: possibly lossy conversion from double to int + | sayHelloWorld(4.5) + | ^-^ + jshell> +``` + +--- + +### Step 06 - Introduction to Java Method Arguments - Puzzles and Tips + +> **Note**: Step-6 is not present in GitHub repo. + +--- + +## Section 12: Conditionals in Java Programming + +### Step 09: Comparing The if Family, And switch + +Let's compare and contrast these two approaches, to gain some experience on how to choose a conditional. + +First comes an example using the if-else if-else statement. + +#### Snippet-01 : Formatted Output Using if + +#### OperatorChoiceRunner.java + +```java + package com.in28minutes.ifstatement.examples; + + public class OperatorChoiceRunner { + public static void main(String[] args) { + OperatorChoice opChoice = new OperatorChoice(5, 2, 1); + opChoice.operate(); + } + } +``` +#### OperatorChoice.java + +```java + package com.in28minutes.ifstatement.examples; + + public class OperatorChoice { + private int number1; + private int number2; + private int choice; + + public OperatorChoice(int number1, int number2, int choice) { + this.number1 = number1; + this.number2= number2; + this.choice = choice; + } + + public void operate() { + System.out.printf("number1 : %d", number1).println(); + System.out.printf("number2 : %d", number2).println(); + System.out.printf("choice : %d", choice).println(); + + if(choice == 1) { + System.out.printf("result : %d", number1 + number2).println(); + } else if(choice == 2) { + System.out.printf("result : %d", number1 - number2).println(); + } else if(choice == 3) { + System.out.printf("result : %d", number1 * number2).println(); + } else if(choice == 4) { + System.out.printf("result : %d", number1 / number2).println(); + } else { + System.out.println("Invalid Operation"); + } + } + } +``` + +#### Console Output + +```java +number1 : 5 + +number2 : 2 + +choice : 1 + +result : 7 +``` + +Next in line, is an example involving a switch. + +#### Snippet-02 : Formatted Output Using switch + +#### OperatorChoiceRunner.java + +```java + package com.in28minutes.ifstatement.examples; + + public class OperatorChoiceRunner { + public static void main(String[] args) { + OperatorChoice opChoice = new OperatorChoice(5, 2, 1); + opChoice.operateUsingSwitch(); + } + } +``` + +#### OperatorChoice.java + +```java + + package com.in28minutes.ifstatement.examples; + + public class OperatorChoice { + private int number1; + private int number2; + private int choice; + + public OperatorChoice(int number1, int number2, int choice) { + this.number1 = number1; + this.number2= number2; + this.choice = choice; + } + + public void operateUsingSwitch() { + System.out.printf("number1 : %d", number1).println(); + System.out.printf("number2 : %d", number2).println(); + System.out.printf("choice : %d", choice).println(); + + switch(choice) { + case 1: System.out.printf("result : %d", number1 + number2).println(); + break; + case 2: System.out.printf("result : %d", number1 - number2).println(); + break; + case 3: System.out.printf("result : %d", number1 * number2).println(); + break; + case 4: System.out.printf("result : %d", number1 / number2).println(); + break; + default: System.out.printf("result : %d", number1 + number2).println(); + break; + } + } + } +``` + +#### Console Output + +```java +number1 : 5 + +number2 : 2 + +choice : 1 + +result : 7 +``` + +#### Summary + +In this step, we: + +- Observed that the same conditional code could be written using an if-family conditional, or the switch. + +- Learned that an if family conditional is difficult to get wrong, as the rules for it are very strict. It can be used to evaluate only boolean conditions. But it is verbose, and often less readable. + +- Came to know that a switch conditional can be used to check for only integer values. It is very compact, and very readable. + +- However, the relative order of case clauses and default are not fixed, and the usage of break is optional. This can lead to subtle errors in your program. + +--- + +## Section 14: Loops in Java Programming + +### Step 02 - Java For Loop - Exercises Overview and First Exercise Prime Numbers + +> **Note**: Step-2 is not present in GitHub repo. + +### Step 03 - Java For Loop - Exercise - Sum Upto N Numbers and Sum of Divisors + +> **Note**: Step-3 is not present in GitHub repo. + +### Step 04 - Java For Loop - Exercise - Print a Number Triangle + +> **Note**: Step-4 is not present in GitHub repo. + +### Step 05 - While Loop in Java - An Introduction + +> **Note**: Step-5 is not present in GitHub repo. + +### Step 06 - While Loop - Exercises - Cubes and Squares upto limit + +> **Note**: Step-6 is not present in GitHub repo. + +### Step 07 - Do While Loop in Java - An Introduction + +> **Note**: Step-7 is not present in GitHub repo. + +### Step 08 - Do While Loop in Java - An Example - Cube while user enters positive numbers + +> **Note**: Step-8 is not present in GitHub repo. + +### Step 09 - Introduction to Break and Continue + +> **Note**: Step-9 is not present in GitHub repo. + +### Step 10 - Selecting Loop in Java - For vs While vs Do While + +> **Note**: Step-10 is not present in GitHub repo. + +--- + +## Section 16: Reference Types in Java Programming + +### Step 14 - Java Reference Types - Conclusion + +> **Note**: Step-14 is not present in GitHub repo. + +--- From cf490709672aa0111c90c1bf943187a8abee41bc Mon Sep 17 00:00:00 2001 From: Hafeezbaig Date: Sat, 12 Oct 2024 03:15:46 +0530 Subject: [PATCH 2/6] sections added for review - 2 --- missing-info.md | 1213 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1213 insertions(+) diff --git a/missing-info.md b/missing-info.md index 9f6d6fa9..ac9f8e63 100644 --- a/missing-info.md +++ b/missing-info.md @@ -198,6 +198,762 @@ Multiplication Table for 4: --- +### Additional Coding Exercises: + +### Exercise 1: Multiplication Table Generator + +**Objective**: Create a method that prints the multiplication table for any number, up to a specified range. + +**Explanation**: +In this exercise, you’ll write a method that accepts two arguments: + +`number`: The number for which the multiplication table is to be printed. + +`range`: The number of rows in the multiplication table (i.e., how far the table goes). + +For example, calling `generateMultiplicationTable(7, 12);` would print the multiplication table of 7 up to 12. + +#### Code: + +```java +public class MultiplicationTable { + public static void generateMultiplicationTable(int number, int range) { + for (int i = 1; i <= range; i++) { + System.out.printf("%d * %d = %d%n", number, i, number * i); + } + } + + public static void main(String[] args) { + generateMultiplicationTable(7, 12); // Example: prints multiplication table of 7 up to 12 + } +} +``` + +#### Output: + +```java +7 * 1 = 7 +7 * 2 = 14 +7 * 3 = 21 +... +7 * 12 = 84 +``` + +This exercise tests your ability to work with loops, method arguments, and formatted output. + +--- + +### Exercise 2: Reusable Print Statements + +**Objective**: Create a method that prints a custom message a specific number of times. + +**Explanation**: +In this exercise, you’ll write a method that takes two arguments: + +`message`: A string message to print. + +`times`: The number of times to print the message. + +This allows you to reuse the method to print any message, as many times as desired. + +#### Code: + +```java +public class PrintMessageExample { + // Method to print a custom message a specific number of times + public static void printCustomMessage(String message, int times) { + for (int i = 1; i <= times; i++) { + System.out.println(message); + } + } + + public static void main(String[] args) { + // Example usage of the method + printCustomMessage("Java is fun!", 5); // Prints the message 5 times + } +} +``` + +#### Output: + +```java +Java is fun! +Java is fun! +Java is fun! +Java is fun! +Java is fun! +``` + +This exercise reinforces how to use method arguments to allow for flexibility in method behavior, as well as loop control for repeated tasks. + +--- + +## Section 5: Introduction to Java Platform + +### Additional Coding Exercises: + + +### **Exercise 1: Exploring Java Platform Components** + +**Objective**: Understanding the role of the JVM, JRE, and JDK through a practical scenario. + +#### Scenario: +You have written a simple Java program `Greeting.java` that prints "Hello, World!" to the console. You want to share this program with two different friends: + +1. **Friend A** only has the JRE installed. + +2. **Friend B** has the JDK installed. + +**Tasks**: + +1. Explain what each friend needs to do to run your program. + +2. For **Friend A**, you should provide the compiled bytecode (`Greeting.class`), explain why this is necessary, and describe how they can run the program with the JRE. + +3. For **Friend B**, explain the steps they need to follow, starting with the source file (`Greeting.java`), and show how they can compile and run the program using the JDK. + +#### Sample Code for `Greeting.java`: + +```java +public class Greeting { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +} +``` + +#### Expected Outcome: +- Learners should be able to describe the differences between the JRE and JDK and how each is used in different contexts (running bytecode vs. compiling and running source code). + +- They should know how to compile a Java program with the JDK using `javac` and run it using `java`, and explain why the JRE alone is sufficient to run pre-compiled bytecode. + +--- + +### **Exercise 2: Creating and Compiling a Class with a Method** + +**Objective**: Writing and compiling Java code outside of JShell, understanding the use of the `javac` and `java` commands. + +#### Tasks: + +1. Write a Java class named `Car` in a file called `Car.java`. The class should have the following features: + + - A method `start()` that prints `"The car has started."`. + + - A method `stop()` that prints `"The car has stopped."`. + +2. Add a `main` method to the class, where you create an instance of `Car` and call both `start()` and `stop()`. + +3. Compile your `Car.java` file using the `javac` command. + +4. Run the compiled class using the `java` command. + +#### Code for `Car.java`: + +```java +public class Car { + void start() { + System.out.println("The car has started."); + } + + void stop() { + System.out.println("The car has stopped."); + } + + public static void main(String[] args) { + Car myCar = new Car(); + myCar.start(); + myCar.stop(); + } +} +``` + +#### Expected Outcome: + +- The learners will write a basic Java class with methods and a `main` method to execute it. + +- They will compile the code using `javac` and understand how the `.class` file is generated. + +- They will run the compiled bytecode using `java Car`, reinforcing the steps of compiling and running a Java program outside of JShell. + +--- + +## Section 6: Introduction to Eclipse - First Java Programming Project + +### Additional Coding Exercises: + +### **Exercise 1: Creating and Debugging a Java Class in Eclipse** + +**Objective**: Practice creating a Java class in Eclipse, running it, and using the Debug mode to examine its behavior. + +#### Tasks: + +1. **Create a Java class** named `Calculator` with the following methods: + + - `add(int a, int b)`: Returns the sum of `a` and `b`. + + - `subtract(int a, int b)`: Returns the result of `a - b`. + - `multiply(int a, int b)`: Returns the result of `a * b`. + - `divide(int a, int b)`: Returns the result of `a / b`. Ensure you handle division by zero. + +2. **Add a `main()` method** to the class where you create an instance of `Calculator` and call each of the methods with some example values. Print the results of each operation. + +3. **Run the class** using Eclipse’s "Run as --> Java Application" option to see the results in the console. + +4. **Set breakpoints** in each of the methods (`add`, `subtract`, `multiply`, `divide`) and debug the program using Eclipse’s Debug mode. + +At each breakpoint, inspect the values of the variables and step through the program execution. + +#### Code: +```java +public class Calculator { + public int add(int a, int b) { + return a + b; + } + + public int subtract(int a, int b) { + return a - b; + } + + public int multiply(int a, int b) { + return a * b; + } + + public int divide(int a, int b) { + if (b == 0) { + System.out.println("Error: Division by zero"); + return 0; + } + return a / b; + } + + public static void main(String[] args) { + Calculator calc = new Calculator(); + System.out.println("Addition: " + calc.add(10, 5)); + System.out.println("Subtraction: " + calc.subtract(10, 5)); + System.out.println("Multiplication: " + calc.multiply(10, 5)); + System.out.println("Division: " + calc.divide(10, 0)); + } +} +``` + +#### Expected Outcome: + +- Learners will gain hands-on experience creating and running Java classes in Eclipse. + +- They will also learn how to set breakpoints, step through code, and inspect variables using Eclipse’s Debug mode. + +--- + +### **Exercise 2: Using Eclipse to Refactor and Organize Code into Packages** + +**Objective**: Practice organizing Java classes into packages, using Eclipse's refactoring tools, and running a program with multiple classes. + +#### Tasks: + +1. **Create a new Java project** in Eclipse and organize your code into packages: + + - Create a package called `math.operations`. + + - Inside `math.operations`, create two classes: + - `Addition`: A class with a method `add(int a, int b)` that returns the sum of two integers. + + - `Multiplication`: A class with a method `multiply(int a, int b)` that returns the product of two integers. + +2. **Create a separate package** called `main` and inside it, create a class named `MathRunner` with the `main()` method. + + - The `MathRunner` class should import the `Addition` and `Multiplication` classes from the `math.operations` package. + + - In the `main()` method, create instances of `Addition` and `Multiplication` and call their methods, printing the results. + +3. **Use Eclipse’s Refactoring tools** to rename one of the classes (e.g., rename `Addition` to `Sum`). Ensure the code updates correctly throughout the project. + +4. **Run the program** using "Run as --> Java Application" and observe the output. + +#### Code: + +**Addition.java (in `math.operations`)**: +```java +package math.operations; + +public class Addition { + public int add(int a, int b) { + return a + b; + } +} +``` + +**Multiplication.java (in `math.operations`)**: +```java +package math.operations; + +public class Multiplication { + public int multiply(int a, int b) { + return a * b; + } +} +``` + +**MathRunner.java (in `main`)**: +```java +package main; + +import math.operations.Addition; +import math.operations.Multiplication; + +public class MathRunner { + public static void main(String[] args) { + Addition add = new Addition(); + Multiplication multiply = new Multiplication(); + + System.out.println("Sum: " + add.add(10, 5)); + System.out.println("Product: " + multiply.multiply(10, 5)); + } +} +``` + +#### Expected Outcome: + +- Learners will practice using packages to organize classes and gain familiarity with Eclipse’s refactoring tools. + +- They will also understand how to import classes from different packages and run multi-class programs in Eclipse. + +--- + +## Section 9: Introduction To Java Object Oriented Programming + +### Additional Coding Exercises: + +### **Exercise 1: Designing a Simple Banking System Using OOP** + +**Objective**: Practice designing a system with classes, encapsulation, and constructors. + +#### Tasks: + +1. **Create a class `BankAccount`** that models a simple bank account with the following attributes: + + - `accountNumber`: The account number of the bank account (private). + + - `balance`: The current balance in the account (private). + +2. **Add methods** to the `BankAccount` class: + + - `deposit(double amount)`: A method to add money to the balance. + + - `withdraw(double amount)`: A method to withdraw money from the balance. Ensure that the balance does not go below zero. + + - `getBalance()`: A method to retrieve the current balance. + +3. **Add a constructor** to the `BankAccount` class that accepts an account number and an initial balance. + +4. **Create a class `BankAccountRunner`** with the `main()` method where you: + + - Create two instances of `BankAccount` with different account numbers and initial balances. + + - Perform deposit and withdrawal operations and print the balance after each operation. + +#### Code: + +**BankAccount.java**: +```java +public class BankAccount { + private String accountNumber; + private double balance; + + public BankAccount(String accountNumber, double balance) { + this.accountNumber = accountNumber; + this.balance = balance; + } + + public void deposit(double amount) { + if (amount > 0) { + balance += amount; + } + } + + public void withdraw(double amount) { + if (amount > 0 && amount <= balance) { + balance -= amount; + } else { + System.out.println("Insufficient balance or invalid amount."); + } + } + + public double getBalance() { + return balance; + } +} +``` + +**BankAccountRunner.java**: + +```java +public class BankAccountRunner { + public static void main(String[] args) { + BankAccount account1 = new BankAccount("12345", 1000.00); + BankAccount account2 = new BankAccount("67890", 500.00); + + account1.deposit(500.00); + account1.withdraw(200.00); + System.out.println("Account 1 Balance: " + account1.getBalance()); + + account2.deposit(300.00); + account2.withdraw(100.00); + System.out.println("Account 2 Balance: " + account2.getBalance()); + } +} +``` + +#### Output: + +```java +Account 1 Balance: 1300.0 +Account 2 Balance: 700.0 +``` + +**Explanation**: + +- Account 1 starts with a balance of 1000, then deposits 500, and withdraws 200, resulting in a balance of 1300. + +- Account 2 starts with a balance of 500, then deposits 300, and withdraws 100, resulting in a balance of 700. + +#### Expected Outcome: + +- Learners will practice using constructors to initialize objects. + +- They will reinforce the concept of **encapsulation** by using private variables and methods to interact with object state. + +- They will learn how to handle validation in methods, such as ensuring a withdrawal doesn't leave the account with a negative balance. + +--- + +### **Exercise 2: Object-Oriented Inventory Management System** +**Objective**: Practice creating multiple classes and using objects to simulate an inventory management system. + +#### Tasks: + +1. **Create a class `Product`** with the following attributes: + + - `productId`: A unique identifier for the product (private). + + - `productName`: The name of the product (private). + + - `quantity`: The quantity of the product available in stock (private). + +2. **Add methods** to the `Product` class: + + - `increaseStock(int amount)`: A method to increase the stock of a product. + + - `decreaseStock(int amount)`: A method to decrease the stock of a product. Ensure that the quantity doesn't fall below zero. + + - `getQuantity()`: A method to get the current quantity of the product. + + - `getProductName()`: A method to get the product name. + +3. **Create a class `Inventory`** to manage multiple `Product` objects. The class should: + + - Contain a list of products. + + - Have methods `addProduct(Product product)` to add a product to the inventory and `removeProduct(String productId)` to remove a product by ID. + +4. **Create a class `InventoryManager`** with the `main()` method where: + + - You create a few `Product` objects. + + - You add products to the inventory, increase and decrease stock, and display product details. + +#### Code: + +**Product.java**: + +```java +public class Product { + private String productId; + private String productName; + private int quantity; + + public Product(String productId, String productName, int quantity) { + this.productId = productId; + this.productName = productName; + this.quantity = quantity; + } + + public void increaseStock(int amount) { + if (amount > 0) { + quantity += amount; + } + } + + public void decreaseStock(int amount) { + if (amount > 0 && amount <= quantity) { + quantity -= amount; + } else { + System.out.println("Insufficient stock or invalid amount."); + } + } + + public int getQuantity() { + return quantity; + } + + public String getProductName() { + return productName; + } +} +``` + +**Inventory.java**: + +```java +import java.util.ArrayList; + +public class Inventory { + private ArrayList products = new ArrayList<>(); + + public void addProduct(Product product) { + products.add(product); + } + + public void removeProduct(String productId) { + products.removeIf(product -> product.getProductId().equals(productId)); + } + + public void displayInventory() { + for (Product product : products) { + System.out.println("Product: " + product.getProductName() + ", Quantity: " + product.getQuantity()); + } + } +} +``` + +**InventoryManager.java**: + +```java +public class InventoryManager { + public static void main(String[] args) { + Inventory inventory = new Inventory(); + + Product laptop = new Product("101", "Laptop", 10); + Product smartphone = new Product("102", "Smartphone", 20); + + inventory.addProduct(laptop); + inventory.addProduct(smartphone); + + laptop.increaseStock(5); + smartphone.decreaseStock(10); + + inventory.displayInventory(); + } +} +``` + +Output: + +```java +Product: Laptop, Quantity: 15 +Product: Smartphone, Quantity: 10 +``` + +**Explanation**: + +- The Laptop starts with a quantity of 10, and after increasing the stock by 5, its new quantity is 15. + +- The Smartphone starts with a quantity of 20, and after decreasing the stock by 10, its new quantity is 10. + +#### Expected Outcome: + +- Learners will practice object-oriented design by managing relationships between multiple classes (Inventory and Product). + +- They will understand the importance of **code encapsulation** by handling inventory operations through methods. + +- They will explore concepts like managing collections of objects (`ArrayList`). + +--- + +## Section 11: Primitive Data Types And Alternatives in Java Programming + +### Additional Coding Exercises + +### **Exercise 1: Number System Converter** + +**Objective**: Practice working with different number systems (decimal, octal, and hexadecimal) and integer type conversions in Java. + +#### Tasks: + +1. **Create a class `NumberSystemConverter`** that has the following functionalities: + + - Convert a decimal number to its binary, octal, and hexadecimal representations. + + - Convert an octal or hexadecimal number (input as a string) back to decimal. + +2. **Add methods** to the `NumberSystemConverter` class: + - `toBinary(int number)`: Converts a decimal number to its binary representation. + + - `toOctal(int number)`: Converts a decimal number to its octal representation. + + - `toHexadecimal(int number)`: Converts a decimal number to its hexadecimal representation. + + - `fromOctal(String octal)`: Converts an octal number (as a string) back to decimal. + + - `fromHexadecimal(String hex)`: Converts a hexadecimal number (as a string) back to decimal. + +3. **Create a `main()` method** to test these methods by converting values between different number systems. + +#### Code: + +**NumberSystemConverter.java**: + +```java +public class NumberSystemConverter { + public String toBinary(int number) { + return Integer.toBinaryString(number); + } + + public String toOctal(int number) { + return Integer.toOctalString(number); + } + + public String toHexadecimal(int number) { + return Integer.toHexString(number); + } + + public int fromOctal(String octal) { + return Integer.parseInt(octal, 8); + } + + public int fromHexadecimal(String hex) { + return Integer.parseInt(hex, 16); + } +} +``` + +**NumberSystemConverterRunner.java**: + +```java +public class NumberSystemConverterRunner { + public static void main(String[] args) { + NumberSystemConverter converter = new NumberSystemConverter(); + + // Decimal to Binary, Octal, Hexadecimal + int decimal = 255; + System.out.println("Binary of 255: " + converter.toBinary(decimal)); + System.out.println("Octal of 255: " + converter.toOctal(decimal)); + System.out.println("Hexadecimal of 255: " + converter.toHexadecimal(decimal)); + + // Octal and Hexadecimal back to Decimal + String octal = "377"; + String hex = "FF"; + System.out.println("Octal 377 to Decimal: " + converter.fromOctal(octal)); + System.out.println("Hexadecimal FF to Decimal: " + converter.fromHexadecimal(hex)); + } +} +``` + +#### Output: + +```java +Binary of 255: 11111111 +Octal of 255: 377 +Hexadecimal of 255: ff +Octal 377 to Decimal: 255 +Hexadecimal FF to Decimal: 255 +``` + +**Explanation**: + +- The binary representation of 255 is 11111111. + +- The octal representation of 255 is 377. + +- The hexadecimal representation of 255 is ff. + +- The octal number 377 is equivalent to 255 in decimal. + +- The hexadecimal number FF is also equivalent to 255 in decimal. + +#### Expected Outcome: + +- Learners will gain a better understanding of how Java handles different number systems. + +- They will practice working with **string parsing** and **integer conversion** functions in Java. + +--- + +### **Exercise 2: Simple Interest Calculator Using `BigDecimal`** + +**Objective**: Practice handling precise floating-point calculations using `BigDecimal`. + +#### Tasks: + +1. **Create a class `SimpleInterestCalculator`** that performs a simple interest calculation using `BigDecimal`. + + - The class should accept a principal amount and interest rate as `String` inputs. + + - It should calculate the total value after a given number of years using the formula: + `Total Amount = Principal + (Principal * Interest * Number of Years)` + +2. **Add methods** to the `SimpleInterestCalculator` class: + + - `calculateTotalValue(int years)`: Calculates the total value after the given number of years. + +3. **Create a `main()` method** to test the interest calculation with various inputs. + +#### Code: + +**SimpleInterestCalculator.java**: + +```java +import java.math.BigDecimal; + +public class SimpleInterestCalculator { + private BigDecimal principal; + private BigDecimal interestRate; + + public SimpleInterestCalculator(String principal, String interestRate) { + this.principal = new BigDecimal(principal); + this.interestRate = new BigDecimal(interestRate).divide(new BigDecimal("100")); + } + + public BigDecimal calculateTotalValue(int years) { + BigDecimal totalInterest = principal.multiply(interestRate).multiply(new BigDecimal(years)); + return principal.add(totalInterest); + } +} +``` + +**SimpleInterestCalculatorRunner.java**: + +```java +public class SimpleInterestCalculatorRunner { + public static void main(String[] args) { + SimpleInterestCalculator calculator = new SimpleInterestCalculator("5000", "5"); + BigDecimal totalValue = calculator.calculateTotalValue(3); + System.out.println("Total Amount after 3 years: " + totalValue); + } +} +``` + +#### Output: + +```java +Total Amount after 3 years: 5750.00 +``` + +**Explanation**: + +- The principal amount is `5000`. + +- The interest rate is 5%, which, over 3 years, results in a total interest of `750` (`5000 * 0.05 * 3`). +Therefore, the total amount after 3 years is `5750`. + + +#### Expected Outcome: + +- Learners will reinforce the use of the `BigDecimal` class for accurate floating-point arithmetic. + +- They will explore handling **precise calculations**, which is particularly useful in financial applications. + +--- + ## Section 12: Conditionals in Java Programming ### Step 09: Comparing The if Family, And switch @@ -349,6 +1105,231 @@ In this step, we: --- +### Additional Coding Exercises: + +### **Exercise 1: Grade Evaluator Using if-else and switch** + +**Objective**: Create a Java program that evaluates a student's grade based on their score and gives feedback using both `if-else` and `switch` statements. + +#### Task: + +1. Create a class `GradeEvaluator` that performs the following: + + - **If-else version**: Takes an integer input (score between 0 and 100) and prints the corresponding letter grade using `if-else if` logic: + + - 90-100: Grade A + + - 80-89: Grade B + + - 70-79: Grade C + + - 60-69: Grade D + + - 0-59: Grade F + + - **Switch version**: Using integer division, create a `switch` version to achieve the same result. (For example, dividing the score by 10 simplifies the range logic.) + +2. Add a method to print feedback for each grade: + + - A: "Excellent work!" + + - B: "Good job!" + + - C: "You passed." + + - D: "Barely passed." + + - F: "Failed. Try again." + +#### Code: + +**GradeEvaluator.java**: + +```java +public class GradeEvaluator { + + // if-else version + public void evaluateGradeIfElse(int score) { + if (score >= 90 && score <= 100) { + System.out.println("Grade A - Excellent work!"); + } else if (score >= 80 && score < 90) { + System.out.println("Grade B - Good job!"); + } else if (score >= 70 && score < 80) { + System.out.println("Grade C - You passed."); + } else if (score >= 60 && score < 70) { + System.out.println("Grade D - Barely passed."); + } else if (score >= 0 && score < 60) { + System.out.println("Grade F - Failed. Try again."); + } else { + System.out.println("Invalid score."); + } + } + + // switch version + public void evaluateGradeSwitch(int score) { + switch (score / 10) { + case 10: + case 9: + System.out.println("Grade A - Excellent work!"); + break; + case 8: + System.out.println("Grade B - Good job!"); + break; + case 7: + System.out.println("Grade C - You passed."); + break; + case 6: + System.out.println("Grade D - Barely passed."); + break; + default: + System.out.println("Grade F - Failed. Try again."); + } + } +} +``` + +**GradeEvaluatorRunner.java**: + +```java +public class GradeEvaluatorRunner { + public static void main(String[] args) { + GradeEvaluator evaluator = new GradeEvaluator(); + + // Test with different scores + System.out.println("Using if-else:"); + evaluator.evaluateGradeIfElse(85); + + System.out.println("Using switch:"); + evaluator.evaluateGradeSwitch(72); + } +} +``` + +Input (in `GradeEvaluatorRunner.java`): + +```java +evaluator.evaluateGradeIfElse(85); +evaluator.evaluateGradeSwitch(72); +``` + +**Output**: + +```java +Using if-else: +Grade B - Good job! + +Using switch: +Grade C - You passed. +``` + +**Explanation**: + +- For the if-else evaluation with an input of 85, the output is "Grade B - Good job!" because 85 falls in the 80-89 range, which corresponds to a B grade. + +- For the switch evaluation with an input of 72, the output is "Grade C - You passed." because 72 falls in the 70-79 range, which corresponds to a C grade. + +#### Expected Outcome: + +- Learners will understand how to use both `if-else` and `switch` to handle conditional branching. + +- They'll see how range logic can be simplified with integer division for `switch` cases. + +--- + +### **Exercise 2: Tax Bracket Calculator Using Ternary Operator** + +**Objective**: Use the ternary operator to calculate and print tax brackets based on income. + +#### Task: + +1. Create a class `TaxBracketCalculator` that: + + - Takes an integer input representing annual income and calculates the applicable tax rate using the ternary operator. + + - Tax Brackets: + + - Income > 100,000: 30% tax + + - Income between 50,001 and 100,000: 20% tax + + - Income between 30,001 and 50,000: 10% tax + + - Income ≤ 30,000: 5% tax + +2. Add methods: + + - `calculateTaxRate`: Returns the tax rate as a percentage. + + - `calculateTax`: Returns the total tax amount (income * tax rate). + +#### Code: + +**TaxBracketCalculator.java**: + +```java +public class TaxBracketCalculator { + + // Calculate tax rate using the ternary operator + public double calculateTaxRate(int income) { + return (income > 100000) ? 0.30 : + (income > 50000) ? 0.20 : + (income > 30000) ? 0.10 : 0.05; + } + + // Calculate total tax based on income + public double calculateTax(int income) { + double taxRate = calculateTaxRate(income); + return income * taxRate; + } +} +``` + +**TaxBracketCalculatorRunner.java**: + +```java +public class TaxBracketCalculatorRunner { + public static void main(String[] args) { + TaxBracketCalculator calculator = new TaxBracketCalculator(); + + int income = 75000; + double taxRate = calculator.calculateTaxRate(income); + double tax = calculator.calculateTax(income); + + System.out.println("Income: $" + income); + System.out.println("Tax Rate: " + (taxRate * 100) + "%"); + System.out.println("Tax Amount: $" + tax); + } +} +``` + +#### Input (in `TaxBracketCalculatorRunner.java`): + +```java +int income = 75000; +``` + +#### Output: + +```java +Income: $75000 +Tax Rate: 20.0% +Tax Amount: $15000.0 +``` + +**Explanation**: + +- With an income of $75,000, the program calculates the tax rate as 20%, which applies to incomes between $50,001 and $100,000. + +- The tax amount is calculated as 75,000 * 0.20 = 15,000, so the tax to be paid is $15,000. + +#### Expected Outcome: + +- Learners will explore using the ternary operator for compact conditional logic. + +- They'll practice calculating tax rates and amounts based on given inputs. + +--- + ## Section 14: Loops in Java Programming ### Step 02 - Java For Loop - Exercises Overview and First Exercise Prime Numbers @@ -389,6 +1370,14 @@ In this step, we: --- +### Additional Coding Exercises: + +> **Note**: Exercises are based on the Step 1 as other Steps are not present in Github repo for Loops. + +> EXERCISES TO BE ADDED IN NEXT PULL REQUEST - Last Updated - 12th Oct 2024 (03:12 AM) + +--- + ## Section 16: Reference Types in Java Programming ### Step 14 - Java Reference Types - Conclusion @@ -396,3 +1385,227 @@ In this step, we: > **Note**: Step-14 is not present in GitHub repo. --- + +## Section 18: Arrays and ArrayLists in Java Programming + +### Step 01 - Understanding the need and Basics about an Array + +You can use an index to find the specific element from the array. It is done by using the indexing operator, '[]'. + +The expression marks[0] maps to the first array element stored at index 0 of the array marks. + +```java +jshell> marks[0] +$20 ==> 75 + +jshell> marks[1] +$21 ==> 60 + +jshell> marks[2] +$22 ==> 56 +``` + +--- + +### Step 16 - Introduction to Array and ArrayList - Conclusion + +> **Note**: Step-16 is not present in GitHub repo. + +--- + +## Section 20: Java - Oriented Programming Again + +### Step 20 - Java Interface Flyable and Abstract Class Animal - An Exercise + +> Not found in Github repo. + +--- + +### Step 21 - Polymorphism - An introduction + +> Not found in Github repo. + +--- + +## Section 25: Introduction to Functional Programming in Java + +### Step 12 - Optional class in Java - An Introduction + +In an earlier section, we wrote and ran the following code: + +```java + jshell> List.of(23, 12, 34, 53).stream().max((n1, n2) -> Integer.compare(n1, n2)); + Optional[53] + jshell> +``` + +In order to get the result in a form you would appreciate, we modified this code to look like: + +```java +jshell> List.of(23, 12, 34, 53).stream().max((n1, n2) -> Integer.compare(n1, n2)).get(); +53 +jshell> +``` + +`max()` is a stream operation, that needs to consume a stream. It is possible that the input stream is empty. In that case, the maximum value would be null. It is undesirable in FP to encounter an exception during a stream operation. + +It is extremely inelegant if we are asked to handle an exception in an FP code pipeline. + +--- + +## Section 27: Introduction to Threads And Concurrency in Java + +### Step 08 - Need for Controlling the Execution of Threads + +Drawbacks of earlier approaches + +We saw few of the methods for synchronization in the Thread class + +- `start()` +- `join()` +- `sleep()` +- `wait()` + +#### Above approaches have a few drawbacks: + +No Fine-Grained Control: Suppose, for instance , we want Task3 to run after any one of Task1 or Task2 is done. + +#### How do we do it? + +- **Difficult to maintain**: Imagine managing 5-10 threads with code written in earlier examples. It would become very difficult to maintain. + +- **NO Sub-Task Return Mechanism**: With the Thread class or the Runnable interface, there is no way to get the result from a sub-task. + +--- + +### Step 14 - Threads and MultiThreading - Conclusion + +> **Note**: Step-14 is not present in GitHub repo. + +--- + +## Section 28: Introduction to Exception Handling in Java + +### Step 01 - Introduction to Exception Handling - Your Thought Process during Exceptions + +#### Snippet-1 : Exception Condition + +ExceptionHandlingRunner.java + +```java + + package com.in28minutes.exceptionhandling; + + public class ExceptionHandlingRunner { + public static void main(String[] args) { + callMethod(); + System.out.println("callMethod Done"); + } + + static void callMethod() { + String str = null; + int len = str.length(); + System.out.println("String Length Done"); + } + } +``` + +#### Console Output + +```java +java.lang.NullPointerException + +Exception in thread "main" java.lang.NullPointerException + +at com.in28minutes.exceptionhandling.ExceptionHandlingRunner.callMethod (ExceptionHandlingRunner.java:8) + +at com.in28minutes.exceptionhandling.ExceptionHandlingRunner.main (ExceptionHandlingRunner.java:4) +``` + + +#### Snippet-01 Explained + +A java.lang.NullPointerException is thrown by the Java run-time when we called length() on the null reference. + +If an exception is not handled in the entire call chain, including main, the exception is thrown out and the program terminates. + +System.out.println() statements after the exception are never executed. + +The runtime prints the call stack trace onto the console. + +For instance, consider this simple class Test: + +```java + public class Test { + public static void main(String[] args) { + callOne(); + } + + public static void callOne() { + callTwo(); + } + + public static void callTwo() { + callThree(); + } + + public static void callThree() { + String name; + System.out.println("This name is %d characters long", name.length()); + } + } +``` + +However, the code name.length() used in callThree() caused a NullPointerException to be thrown. + +However, this is not handled, and the console coughs up the following display: + +```java +Exception in thread "main" java.lang.NullPointerException + +at Test.callThree(Test.java:13) + +at Test.callTwo(Test.java:9) + +at Test.callOne(Test.java:6) + +at Test.main(Test.java:3) +``` + +This is nothing but a call trace of the stack, frozen in time. + +--- + +### Step 14 - Exception Handling - Conclusion with Best Practices + +> **Note**: Step-14 is not present in GitHub repo. + +--- + +## Section 29: Files and Directories in Java + +### Step 05 - Files - Conclusion + +> Not found in Github repo. + +--- + +## Section 30: More Concurrency with Concurrent Collections and Atomic Operations + +### Step 09 - Conclusion + +> **Note**: Step-9 is not present in GitHub repo. + +--- + +## Section 31: Java Tips + +> **Note**: Section-31 is not present in GitHub repo. + +--- + +## Section 34: Java New Features - Java 10 to Java 16 + +> **Note**: Section-34 is not present in GitHub repo. + +--- From c6a6aaf743bfa44be8fbdb8fa7e9c59c4fce6581 Mon Sep 17 00:00:00 2001 From: Hafeezbaig Date: Thu, 17 Oct 2024 06:57:43 +0530 Subject: [PATCH 3/6] sections added for review - 3 --- coding-exercises.md | 4929 ++++++++++++++++++++++++++++++++++++++++++ java-new-features.md | 1907 ++++++++++++++++ java-tips.md | 2025 +++++++++++++++++ missing-info.md | 3635 +++++++++++++++++++++++++++++-- 4 files changed, 12343 insertions(+), 153 deletions(-) create mode 100644 coding-exercises.md create mode 100644 java-new-features.md create mode 100644 java-tips.md diff --git a/coding-exercises.md b/coding-exercises.md new file mode 100644 index 00000000..b38a3899 --- /dev/null +++ b/coding-exercises.md @@ -0,0 +1,4929 @@ +# Java Coding Exercises + +## Section 7: Java Coding Exercises - Set 1 + +## Introduction To Java Coding Exercises + +In this lecture, we explore the **Java Coding Exercises** feature offered by Udemy. This feature enables you to practice coding directly on the Udemy platform without the need for an IDE or setting up a development environment. + +It is designed to make coding practice more accessible and user-friendly, especially for learners using laptops or desktop computers. + +### Key Benefits of Udemy Coding Exercises + +1. **No IDE Required**: You can code directly in your browser on the Udemy platform. This eliminates the need to set up complex development environments, making it easy to dive into practice. + +2. **Automated Code Testing**: When you write code, Udemy automatically runs tests in the background to check the correctness of your code. You don't need to worry about writing your own test cases or setting up a main method to verify the solution. + +3. **Guided Problem Solving**: + - Each coding exercise comes with clear instructions explaining the problem you need to solve. + + - There are **hints** to help guide you if you're stuck, and there are **solution explanations** if you need a more detailed breakdown of how to solve the exercise. + + - A **solution video** is also provided for many exercises, where you can watch the instructor solve the problem step by step. + +4. **Practice-Oriented Learning**: The best way to learn programming is by solving problems and practicing continuously. The coding exercises help you do just that by providing immediate feedback on your solutions. + +### How the Coding Interface Works + +1. **Starting an Exercise**: When you begin a coding exercise, you will be presented with a coding interface that allows you to type your solution and run tests. + +2. **Running Tests**: After typing your code, you can click the **"Run Tests"** button to run the tests provided for that exercise. The test results will show whether your solution passed or failed. + + - If a test fails, the interface provides detailed error messages. These messages help pinpoint issues, such as compilation errors or incorrect logic in your code. + +3. **Compilation Errors**: If your code has syntax errors (e.g., missing return statements, parentheses), the platform will display the error details, including the exact line where the issue occurred. + +4. **Hints and Solutions**: If you're struggling with an exercise: + - You can click **"Hints"** after running the tests to get additional guidance. + + - If you're still stuck, the **"Solution Explanation"** becomes available, providing a detailed solution. + +5. **Full-Screen Editor**: The interface allows you to expand the editor for a distraction-free coding experience by clicking **"Expand Editor"**. + +6. **Error Handling**: The platform makes it easy to troubleshoot errors by showing clear and precise messages about any compilation issues or test failures. + +### Step-by-Step Example + +In one example exercise, you are asked to modify a method called `hello()` that currently returns `0`. The goal is to make the `hello()` method return `1` instead. Here’s how you solve it: + +1. **Step 1**: Click **"Run Tests"** initially, and observe that the test fails because the method returns `0` instead of `1`. + +2. **Step 2**: Modify the `hello()` method to return `1` instead of `0`, and click **"Run Tests"** again. + +3. **Step 3**: Once the test passes, the exercise is complete. + +### Advantages of Udemy Coding Exercises + +- **Automated Solution Checking**: Your code is automatically checked by the provided tests. You don't need to manually run the program or print out results to verify correctness. + +- **Practice Makes Perfect**: With over 40 coding exercises available, you’ll have ample opportunity to practice solving problems, which is essential for improving your programming skills. + +- **Enhanced Documentation Skills**: Each coding exercise includes clear problem statements, allowing you to practice reading and interpreting requirements. This is a critical skill for working on real-world software projects. + +- **Learn by Doing**: Coding exercises simulate real-world problem-solving scenarios, reinforcing your ability to code through hands-on practice. + +### Best Practices for Using the Interface + +1. **Take Your Time**: Coding exercises are meant to be a learning experience, so don’t rush through them. Carefully read the problem, try to solve it on your own, and use hints only when necessary. + +2. **Avoid Copy-Pasting**: Write the code yourself to internalize the concepts. Avoid copying and pasting the solution directly, as typing out the solution helps reinforce your understanding. + +3. **Review Solutions**: After solving an exercise, watch the accompanying **solution video** to see how the instructor approaches the problem. This can provide additional insights into better coding practices. + +4. **Ask Questions**: If you encounter issues or need further clarification, use the **Q&A forum** to ask questions. Also, feel free to share your success stories or discuss any challenges you encountered. + +--- + +## Solution Video For Coding Exercise: Print Hello World + +In this exercise, you are tasked with creating a simple Java program that prints **Hello World** to the console. Let's walk through the solution step by step. + +### Problem Description: +You need to write a Java program that outputs the message "Hello World" using the `System.out.println()` method in the main method. + +### Step 1: Review the Initial Setup + +- The initial code provided includes the **class declaration** and the **main method**. +- You need to add code inside the main method to print "Hello World." + +```java +public class Exercise { + public static void main(String[] args) { + // Add code to print Hello World + } +} +``` + +### Step 2: Add the Print Statement + +To print the message "Hello World" in Java, you use `System.out.println()`. + +- The `System.out.println()` method prints a line of text to the console. +- It should be written inside the `main` method, and make sure to include the **semicolon (;)** at the end of the statement. + +```java +public class Exercise { + public static void main(String[] args) { + System.out.println("Hello World"); + } +} +``` + +### Step 3: Running the Code + +After writing the print statement, click **Run Tests** to check if the solution is correct. The test will check if "Hello World" is printed exactly as required. + +If the code is correct, you'll see: + +``` +Passed 1 of 1 tests +``` + +### Common Mistakes + +Here are a few common mistakes you might encounter: + +1. **Missing Capital "S" in `System.out.println()`**: + - If you accidentally use `system` with a lowercase "s", the program will not compile. Java is case-sensitive, and the correct syntax uses a capital "S" in `System`. + + Example of incorrect code: + ```java + system.out.println("Hello World"); + ``` + + This will result in a compilation error: + ``` + package system does not exist + ``` + +2. **Missing Semicolon (`;`)**: + - If you forget the semicolon at the end of the print statement, the compiler will throw an error. The semicolon is required to terminate the statement. + + Example of incorrect code: + ```java + System.out.println("Hello World") + ``` + + This will result in an error: + ``` + semicolon expected + ``` + +### Step 4: Correcting Errors + +If you encounter any errors, the coding interface will display the line number and the error message, helping you identify and fix the issue. + +- **Error Message**: If you see an error message like `"package system does not exist"`, check if you have used a capital "S" in `System`. +- **Error Message**: `"semicolon expected"` means you need to add the missing semicolon at the end of the statement. + +### Step 5: Final Test + +Once you have corrected any mistakes, click **Run Tests** again. If everything is correct, the test will pass, and you'll have successfully completed the exercise. + +This is a very simple exercise aimed at familiarizing you with the process of writing and running basic Java programs. Now that you have successfully completed it, you can move on to more challenging exercises. + +--- + +## Solution Video For Coding Exercise: Time Converter + +Let’s now walk through how I would solve the **Time Converter** coding exercise. + +### Problem Description: +You’ve been given a partially implemented `TimeConverter` class. The goal is to complete two static methods: +1. **`convertHoursToMinutes(int hours)`**: This method takes an integer value representing hours and returns the equivalent value in minutes. +2. **`convertDaysToMinutes(int days)`**: This method takes an integer value representing days and returns the equivalent value in minutes. + +Additionally, the problem specifies: +- For invalid cases (where days or hours are less than 0), the method should return **-1**. + +### Step 1: Implement `convertHoursToMinutes` + +Let’s start by focusing on the method that converts hours to minutes. The formula to convert hours to minutes is straightforward: +- **Minutes = Hours * 60** + +However, before performing the calculation, we need to handle the invalid case where the input hours are negative. + +Here’s the code: + +```java +public static int convertHoursToMinutes(int hours) { + if (hours < 0) { + return -1; // Return -1 for invalid cases + } + return hours * 60; // Convert hours to minutes +} +``` + +### Step 2: Implement `convertDaysToMinutes` + +Next, we’ll move on to the method that converts days to minutes. Since one day has 24 hours, and each hour has 60 minutes, we can multiply days by 24 and then by 60 to get the equivalent minutes. We also need to handle the case where the input days are negative. + +Here’s the code: + +```java +public static int convertDaysToMinutes(int days) { + if (days < 0) { + return -1; // Return -1 for invalid cases + } + return days * 24 * 60; // Convert days to minutes +} +``` + +### Step 3: Running the Tests + +At this point, both methods are implemented, and we can now run the tests. Once you click **Run Tests**, you should see that all test cases pass successfully. + +### Step 4: Optimization and Code Simplification + +Now that the code is working, let’s look at how we can make it more concise without sacrificing readability. + +In both methods, we calculate the result and return it immediately. Therefore, creating a local variable to store the result is unnecessary. Instead, we can return the result directly without storing it in a variable first. + +Here’s the optimized code: + +```java +public static int convertHoursToMinutes(int hours) { + if (hours < 0) { + return -1; + } + return hours * 60; // Directly return the calculated value +} + +public static int convertDaysToMinutes(int days) { + if (days < 0) { + return -1; + } + return days * 24 * 60; // Directly return the calculated value +} +``` + +### Conclusion + +With this optimized solution, both methods are concise and easy to read. The key takeaways from this exercise are: +- Handling invalid input conditions first to prevent unnecessary calculations. +- Simplifying the return logic by directly returning calculated values instead of using intermediate variables, which is more efficient when the calculation is straightforward. + +Once you click **Run Tests** again, you should see that all test cases are still passing. + +--- + +## Solution Video For Coding Exercise: Exam Result Checker + +Let’s go through how I would solve the **Exam Result Checker** coding exercise. + +### Problem Description: +You’ve been provided with a partially completed Java class named `ExamResult`, which has a method `isPass(int marks)`. The goal is to complete this method to determine if a student has passed or failed based on their marks. + +#### Passing Criteria: +- A student is considered to have **passed** if their marks are **greater than 50**. +- A student is considered to have **failed** if their marks are **50 or less**. + +### Step 1: Implementing the Logic + +The problem is straightforward. We need to check if the provided marks are greater than 50, and return `true` for a pass, or `false` for a fail. + +Here’s the initial implementation: + +```java +public static boolean isPass(int marks) { + if (marks > 50) { + return true; // Passed + } else { + return false; // Failed + } +} +``` + +### Step 2: Running the Tests + +Once you click **Run Tests**, you should see that all the test cases pass. These tests check various scenarios, such as: +- Marks below 50 (e.g., 49, 0). +- Marks exactly 50. +- Marks above 50 (e.g., 51, 100). +- Negative marks. + +### Step 3: Optimization + +The initial solution works fine, but it can be simplified further. Since the condition `marks > 50` already evaluates to a boolean (`true` or `false`), there’s no need for an `if-else` block. + +We can directly return the result of the expression: + +```java +public static boolean isPass(int marks) { + return marks > 50; +} +``` + +This code is shorter, easier to read, and achieves the same functionality. The expression `marks > 50` will evaluate to `true` if the marks are greater than 50, and `false` otherwise. + +### Step 4: Running Tests Again + +Let’s click **Run Tests** again to verify the solution. All tests should pass successfully with this simplified version. + +### Conclusion: + +In this exercise, we learned how to: +- Use basic comparison operators to implement logic. +- Simplify code by returning boolean expressions directly. + +--- + +## Solution Video For Coding Exercise: Sum of Squares of First N Numbers + +Let’s walk through how I would solve the **Sum of Squares of First N Numbers** exercise. + +### Problem Description: +You are given an integer `n`, and your task is to implement a method called `calculateSumOfSquares` in the class `SumOfSquares`. The method should calculate and return the sum of squares of all positive integers from 1 up to `n`. + +For example, if `n` is 3, the result should be: +\[ 1^2 + 2^2 + 3^2 = 14 \] + +Additionally, if `n` is less than zero, the method should return `-1`. + +### Step 1: Handling Invalid Input + +The first step is to handle invalid input, where `n` is less than 0. In this case, we need to return `-1`. + +```java +if (n < 0) { + return -1; +} +``` + +### Step 2: Calculating the Sum of Squares + +Now, if `n` is greater than or equal to zero, we need to compute the sum of squares. For this, we can loop from 1 to `n`, square each number, and add it to a sum variable. + +We’ll declare a variable `sum` to store the total sum of squares. Since the sum can become large, I’ll use a `long` to avoid overflow. + +Here's the code that implements this logic: + +```java +long sum = 0; // Initialize sum + +for (int i = 1; i <= n; i++) { + sum += i * i; // Add the square of i to the sum +} + +return sum; // Return the total sum +``` + +### Step 3: Testing the Code + +Let’s now run the tests to see if this works as expected. Once the code is implemented, run the test cases, and you should see that the results are successful. + +### Debugging: Checking the Error + +When running the tests, I initially encountered an issue. The expected result for `n = 5` was 55, but I was getting 125. This was because I mistakenly added the square of `n` instead of the square of `i` within the loop. + +The correct statement should be: + +```java +sum += i * i; +``` + +Once I corrected that, the tests passed successfully. + +### Step 4: Final Code + +Here is the final, correct implementation of the `calculateSumOfSquares` method: + +```java +public static long calculateSumOfSquares(int n) { + if (n < 0) { + return -1; // Handle invalid input + } + + long sum = 0; // Initialize sum + + for (int i = 1; i <= n; i++) { + sum += i * i; // Add the square of i to the sum + } + + return sum; // Return the total sum +} +``` + +### Step 5: Final Test + +After fixing the logic, I ran the tests again, and they all passed successfully. The program now correctly calculates the sum of squares for any valid input `n` and handles invalid input (negative numbers) by returning `-1`. + +### Conclusion: + +In this exercise, we learned how to: +1. Loop from 1 to `n` and compute the sum of squares. +2. Handle edge cases such as negative inputs. +3. Debug and correct logic using print statements and careful analysis. + +--- + +## Section 10: Java Coding Exercises - Set 2 + +## Solution Video For Coding Exercise - Inches to Object (Feet, Inches) + +Let's walk through how to solve the **Inches to Object (Feet, Inches)** coding exercise. + +### Problem Overview: +You need to complete the `Dimension` class, which represents a measurement in feet and inches. You're given a constructor that accepts an input in inches, and your task is to convert that value into feet and remaining inches. + +### Requirements: +1. **Constructor**: The constructor takes a parameter `inches` and converts it to feet and inches. + - If the input `inches` is less than zero, both feet and inches should be set to `-1`. +2. **Getters**: There are two getter methods: + - `getFeet()` should return the feet value. + - `getInches()` should return the remaining inches after conversion. + +### Example: +If the input to the constructor is `25` inches: +- 12 inches = 1 foot, so 25 inches equals 2 feet and 1 inch (because 25 divided by 12 equals 2 feet, remainder 1 inch). +- For an invalid input, like `-1`, both feet and inches should be set to `-1`. + +### Step 1: Implementing the Constructor + +We start by implementing the constructor, where we need to: +- Convert inches to feet and inches. +- If the input inches are less than 0, set feet and inches to `-1`. + +Here’s the code to handle the conversion: + +```java +public Dimension(int inches) { + if (inches < 0) { + this.feet = -1; + this.inches = -1; + } else { + this.feet = inches / 12; // Convert inches to feet + this.inches = inches % 12; // Get the remaining inches + } +} +``` + +- **If `inches` is less than 0**: Set both `this.feet` and `this.inches` to `-1`. +- **Otherwise**: + - `inches / 12` gives the number of feet (integer division). + - `inches % 12` gives the remainder (remaining inches). + +### Step 2: Implementing the Getter Methods + +Next, we need to implement the `getFeet()` and `getInches()` methods to return the values stored in the instance variables. + +```java +public int getFeet() { + return this.feet; +} + +public int getInches() { + return this.inches; +} +``` + +### Step 3: Running the Tests + +Now that we've implemented the constructor and the getter methods, we can run the tests. + +Let’s see if the tests pass by running them. + +### Debugging: +If we encounter an issue where the expected output for negative input (like `-1`) is incorrect, it’s likely because we didn’t properly set the member variables (`this.feet` and `this.inches`) to `-1`. This can be fixed by ensuring that we always refer to the member variables using `this`. + +### Final Code: + +```java +public class Dimension { + private int feet; + private int inches; + + public Dimension(int inches) { + if (inches < 0) { + this.feet = -1; + this.inches = -1; + } else { + this.feet = inches / 12; // Convert inches to feet + this.inches = inches % 12; // Get the remaining inches + } + } + + public int getFeet() { + return this.feet; + } + + public int getInches() { + return this.inches; + } +} +``` + +### Step 4: Explanation + +- **Integer Division (`/`)**: This gives the number of whole feet. +- **Modulo (`%`)**: This gives the remainder, which is the number of remaining inches. +- **Handling Negative Input**: If `inches` is less than zero, both feet and inches are set to `-1`, as per the requirement. + +### Step 5: Conclusion + +We’ve successfully implemented the `Dimension` class with the constructor and the getter methods. The tests should now pass, confirming that our implementation works for both valid and invalid inputs. + +--- + +## Solution Video For Coding Exercise - Create a Square Class + +Let’s go through the **Create a Square class** coding exercise. + +### Problem Overview: +In this exercise, you need to implement a class called `Square`. The class models a geometric shape—a square—and handles operations like calculating the area and perimeter. + +### Requirements: +1. **Constructor**: The `Square` class has one private instance variable, `side` (type `int`), which represents the length of the side of the square. The constructor takes an integer argument to initialize the `side` attribute. +2. **calculateArea Method**: + - This method calculates the area using the formula `side * side`. + - If the `side` value is less than or equal to 0, the method should return `-1` to indicate invalid input. +3. **calculatePerimeter Method**: + - This method calculates the perimeter using the formula `4 * side`. + - Similarly, if the `side` value is less than or equal to 0, it should return `-1`. + +### Step 1: Implement the Constructor + +First, let’s implement the constructor to initialize the `side` variable. It will simply set the value passed in through the parameter. + +```java +public class Square { + private int side; + + public Square(int side) { + this.side = side; + } +} +``` + +The constructor takes an integer `side` as input and assigns it to the instance variable `side`. + +### Step 2: Implement the `calculateArea` Method + +The next step is to implement the method to calculate the area. Remember: +- If `side` is less than or equal to 0, return `-1`. +- Otherwise, return the area using the formula `side * side`. + +```java +public int calculateArea() { + if (side <= 0) { + return -1; // Return -1 for invalid side length + } + return side * side; // Return the area (side * side) +} +``` + +### Step 3: Implement the `calculatePerimeter` Method + +Now, let’s implement the method to calculate the perimeter. Similar to `calculateArea`, it must return `-1` if `side` is invalid and otherwise return `4 * side`. + +```java +public int calculatePerimeter() { + if (side <= 0) { + return -1; // Return -1 for invalid side length + } + return 4 * side; // Return the perimeter (4 * side) +} +``` + +### Step 4: Running the Tests + +Once the implementation is complete, we can run the tests to verify if everything is working correctly. + +### Final Code: + +```java +public class Square { + private int side; + + public Square(int side) { + this.side = side; + } + + public int calculateArea() { + if (side <= 0) { + return -1; + } + return side * side; + } + + public int calculatePerimeter() { + if (side <= 0) { + return -1; + } + return 4 * side; + } +} +``` + +### Step 5: Explanation + +- **Constructor**: Initializes the `side` variable. +- **calculateArea**: Validates the `side` value and returns `-1` for invalid input or the calculated area (`side * side`). +- **calculatePerimeter**: Validates the `side` value and returns `-1` for invalid input or the calculated perimeter (`4 * side`). + +### Step 6: Conclusion + +All the tests should pass, confirming that your implementation is correct. This was a straightforward exercise where you learned to create a class with a constructor and simple methods to perform calculations, including handling invalid inputs. + +--- + +## Solution Video For Coding Exercise - Create a Point Class with 2D Coordinates + +Let’s go through the **Create a Point class with 2D coordinates** coding exercise. + +### Problem Overview: +In this exercise, you need to complete the implementation of a `Point` class in Java. The `Point` class represents a point in two-dimensional space with x and y coordinates. You are given a partial implementation, and you need to finish the methods `move` and `distanceTo`. + +### Requirements: +1. **move(dx, dy)**: + - This method adjusts the current position of the point by adding `dx` to `x` and `dy` to `y`. + - Example: If the point is at (3, 4) and `move(1, 2)` is called, the new coordinates should be (4, 6). + +2. **distanceTo(other)**: + - This method calculates and returns the Euclidean distance between the current point and another point, which is passed as a parameter. + - Formula: + \[ + d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2} + \] + - Example: If the point is (3, 4) and the other point is (6, 8), the Euclidean distance should be 5. + +### Step 1: Implement the `move` Method + +Let’s start by implementing the `move` method. This method modifies the current point by adjusting its x and y coordinates based on `dx` and `dy`. + +```java +public void move(int dx, int dy) { + this.x += dx; + this.y += dy; +} +``` + +Here, we simply add `dx` to the current x-coordinate and `dy` to the current y-coordinate. + +### Step 2: Implement the `distanceTo` Method + +Next, we’ll implement the `distanceTo` method, which calculates the Euclidean distance between two points. We will use the distance formula: +\[ +d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2} +\] + +```java +public double distanceTo(Point other) { + int diffX = this.x - other.x; + int diffY = this.y - other.y; + return Math.sqrt(diffX * diffX + diffY * diffY); +} +``` + +- **diffX**: The difference between the x-coordinates of the two points. +- **diffY**: The difference between the y-coordinates of the two points. +- We then calculate the square of `diffX` and `diffY`, sum them up, and return the square root of the result using `Math.sqrt()`. + +### Step 3: Run Tests + +Let’s now run the tests to see if everything works as expected. + +### Final Code: + +```java +public class Point { + private int x; + private int y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public void move(int dx, int dy) { + this.x += dx; + this.y += dy; + } + + public double distanceTo(Point other) { + int diffX = this.x - other.x; + int diffY = this.y - other.y; + return Math.sqrt(diffX * diffX + diffY * diffY); + } +} +``` + +### Step 4: Explanation + +- **Constructor**: Initializes the x and y coordinates. +- **move(dx, dy)**: Adjusts the point’s position by adding `dx` to `x` and `dy` to `y`. +- **distanceTo(Point other)**: Uses the Euclidean distance formula to calculate the distance between the current point and another point. + +### Step 5: Conclusion + +All the tests should now pass, indicating that the implementation is correct. This exercise gave you hands-on practice with manipulating object properties and applying mathematical formulas. + +--- + +## Solution Video For Coding Exercise - RGB Color Class + +In this exercise, we’re going to implement the **RGB Color Class**, a fun and practical problem that involves manipulating color values. + +### Problem Overview: +In the **RGB** (Red, Green, Blue) color model, each color is a combination of the three primary colors—red, green, and blue—each with an intensity value ranging from 0 to 255. This exercise requires us to complete an **RGB Color** class, where: +- You have fields for red, green, and blue values. +- You need to implement getter methods for these values. +- You need to implement a method that **inverts** the color by subtracting each color component from 255. + +### Requirements: +1. **Constructor**: + - Takes three integer arguments representing the red, green, and blue values and initializes the instance variables. + +2. **Getter Methods**: + - `getRed()`: Returns the red component. + - `getGreen()`: Returns the green component. + - `getBlue()`: Returns the blue component. + +3. **invert()**: + - Inverts the color by subtracting the current values of red, green, and blue from 255. + +### Example: +If you create an RGB object like `new RGBColor(255, 0, 0)`, calling `color.invert()` should change the color to (0, 255, 255). + +### Step 1: Implement the Constructor + +The first step is to complete the constructor, which initializes the `red`, `green`, and `blue` values using the passed arguments. + +```java +public RGBColor(int red, int green, int blue) { + this.red = red; + this.green = green; + this.blue = blue; +} +``` + +### Step 2: Implement the Getter Methods + +Next, we implement the getter methods to return the values of red, green, and blue. + +```java +public int getRed() { + return this.red; +} + +public int getGreen() { + return this.green; +} + +public int getBlue() { + return this.blue; +} +``` + +These methods will simply return the corresponding color component. + +### Step 3: Implement the `invert()` Method + +In the `invert()` method, we need to change each color component to its complement by subtracting the current value from 255. + +```java +public void invert() { + this.red = 255 - this.red; + this.green = 255 - this.green; + this.blue = 255 - this.blue; +} +``` + +For example: +- If `red` is 255, the new `red` value will be `255 - 255 = 0`. +- If `green` is 0, the new `green` value will be `255 - 0 = 255`. +- The same logic applies to `blue`. + +### Step 4: Test the Code + +Now that we have implemented the constructor, getter methods, and the `invert()` method, let's run the tests to ensure everything works correctly. + +### Full Code Implementation: + +```java +public class RGBColor { + private int red; + private int green; + private int blue; + + public RGBColor(int red, int green, int blue) { + this.red = red; + this.green = green; + this.blue = blue; + } + + public int getRed() { + return red; + } + + public int getGreen() { + return green; + } + + public int getBlue() { + return blue; + } + + public void invert() { + this.red = 255 - this.red; + this.green = 255 - this.green; + this.blue = 255 - this.blue; + } +} +``` + +### Step 5: Explanation + +- **Constructor**: Initializes the `red`, `green`, and `blue` values. +- **getRed(), getGreen(), getBlue()**: Simple getter methods to return the current values of the red, green, and blue color components. +- **invert()**: Inverts the color by subtracting each color component from 255. + +### Step 6: Conclusion + +After running the tests, everything should pass successfully. This exercise was a great introduction to object-oriented principles, getter methods, and basic operations on class fields. + +--- + +## Section 13: Java Coding Exercises - Set 3 + +## Solution Video For Coding Exercise - Is Valid Triangle + +I hope you had a chance to attempt the **Is Valid Triangle** exercise. If not, give it a try before diving into the solution, as practicing the problem on your own will help you understand it better. + +### Problem Overview: + +In this exercise, you are provided with three integer inputs that represent the angles of a triangle: `angle1`, `angle2`, and `angle3`. You need to implement a method named **`isValidTriangle`**, which checks whether these three angles form a valid triangle. + +### Conditions for a Valid Triangle: +1. **All angles must be positive integers** (greater than 0). +2. **The sum of the three angles must equal 180 degrees**. + +If both conditions are satisfied, the method should return **true**, indicating the angles form a valid triangle. Otherwise, it should return **false**. + +### Step 1: Validate the Angles + +The first step is to check whether each of the angles is a positive integer. If any of the angles is less than or equal to 0, we return **false** because a valid triangle cannot have non-positive angles. + +```java +if (angle1 <= 0 || angle2 <= 0 || angle3 <= 0) { + return false; +} +``` + +### Step 2: Check if the Sum of the Angles Equals 180 + +After validating the angles, the next step is to check if the sum of the three angles equals 180 degrees. If the sum is not equal to 180, the triangle is invalid, so we return **false**. If it is exactly 180, we return **true**. + +```java +int sumOfAngles = angle1 + angle2 + angle3; +return sumOfAngles == 180; +``` + +### Full Code Implementation: + +Here's the full implementation of the `isValidTriangle` method: + +```java +public class TriangleValidator { + + public static boolean isValidTriangle(int angle1, int angle2, int angle3) { + // Step 1: Check if all angles are positive + if (angle1 <= 0 || angle2 <= 0 || angle3 <= 0) { + return false; + } + + // Step 2: Check if the sum of angles equals 180 degrees + int sumOfAngles = angle1 + angle2 + angle3; + return sumOfAngles == 180; + } +} +``` + +### Explanation: + +1. **Validate the Angles**: We check if any of the angles is less than or equal to zero using the condition `angle1 <= 0 || angle2 <= 0 || angle3 <= 0`. If this condition is true, we return **false** because a valid triangle requires all angles to be positive. + +2. **Check the Sum of Angles**: We calculate the sum of the angles using `int sumOfAngles = angle1 + angle2 + angle3`. If the sum equals 180, we return **true**, otherwise, **false**. + +### Step 3: Test the Code + +Let's now run the tests to ensure the solution works correctly. + +- **Test Case 1**: `isValidTriangle(60, 60, 60)` → **true** (Equilateral triangle) +- **Test Case 2**: `isValidTriangle(90, 45, 45)` → **true** (Right-angled triangle) +- **Test Case 3**: `isValidTriangle(0, 90, 90)` → **false** (Invalid, zero angle) +- **Test Case 4**: `isValidTriangle(90, 90, 10)` → **false** (Sum is not 180) + +All tests should pass successfully! + +### Conclusion: + +This was a simple yet practical exercise where we learned to validate inputs and apply conditions to solve a problem. We ensured the angles were positive and checked whether their sum equaled 180 degrees to determine if the inputs formed a valid triangle. + +--- + +## Solution Video For Coding Exercise - Is Right Angled Triangle + +I hope you had a chance to try the "Is Right Angled Triangle" exercise. If you haven’t, take a moment to work through it before jumping into the solution. Practicing on your own will help solidify your understanding. + +### Problem Overview: + +You are given three integer inputs representing the lengths of the sides of a triangle: `side1`, `side2`, and `side3`. Your task is to complete the `isRightAngled` method, which determines whether the triangle formed by these sides is a **right-angled triangle**. The method should return `true` if it is a right-angled triangle and `false` otherwise. + +### Approach: + +To determine if a triangle is a right-angled triangle, we can use the **Pythagorean Theorem**. + +Where the **hypotenuse** is the longest side of the triangle. + +### Step 1: Check Validity of Side Lengths + +First, we ensure that all side lengths are greater than zero. If any side is less than or equal to zero, it’s not a valid triangle, so we return `false`. + +```java +if (side1 <= 0 || side2 <= 0 || side3 <= 0) { + return false; +} +``` + +### Step 2: Check the Pythagorean Theorem + +Next, we use the Pythagorean Theorem to check whether the triangle is right-angled. There are three possible configurations for the hypotenuse (longest side), so we check each possibility: + +1. **Hypotenuse = side3**: Check if \((side1)^2 + (side2)^2 = (side3)^2\) +2. **Hypotenuse = side2**: Check if \((side1)^2 + (side3)^2 = (side2)^2\) +3. **Hypotenuse = side1**: Check if \((side2)^2 + (side3)^2 = (side1)^2\) + +If any of these conditions hold true, we return `true`. If none of them hold, we return `false`. + +### Full Code Implementation: + +```java +public class TriangleValidator { + + public static boolean isRightAngled(int side1, int side2, int side3) { + // Step 1: Validate that all sides are positive + if (side1 <= 0 || side2 <= 0 || side3 <= 0) { + return false; + } + + // Step 2: Check if any combination of sides satisfies the Pythagorean theorem + if (side1 * side1 + side2 * side2 == side3 * side3 || + side2 * side2 + side3 * side3 == side1 * side1 || + side3 * side3 + side1 * side1 == side2 * side2) { + return true; + } + + // If none of the conditions hold, it's not a right-angled triangle + return false; + } +} +``` + +### Explanation: + +1. **Side Validation**: We start by checking if any of the side lengths are zero or negative. If so, we return `false` because it's not a valid triangle. + +2. **Pythagorean Theorem Check**: We check all three possible configurations for the hypotenuse: + - Hypotenuse = `side3`: \((side1)^2 + (side2)^2 = (side3)^2\) + - Hypotenuse = `side2`: \((side1)^2 + (side3)^2 = (side2)^2\) + - Hypotenuse = `side1`: \((side2)^2 + (side3)^2 = (side1)^2\) + + If any of these conditions are met, we return `true`. If none are met, the triangle is not right-angled, so we return `false`. + +### Step 3: Test the Code + +Let’s test the solution with different inputs: + +- **Test Case 1**: `isRightAngled(3, 4, 5)` → **true** (Pythagorean triplet) +- **Test Case 2**: `isRightAngled(5, 12, 13)` → **true** (Pythagorean triplet) +- **Test Case 3**: `isRightAngled(1, 2, 3)` → **false** (Not a valid triangle) +- **Test Case 4**: `isRightAngled(6, 8, 10)` → **true** (Pythagorean triplet) +- **Test Case 5**: `isRightAngled(0, 4, 5)` → **false** (Invalid side length) + +### Conclusion: + +This was a great exercise to reinforce our understanding of the Pythagorean Theorem and to practice condition-based logic. By checking multiple configurations for the hypotenuse, we ensure our method works for any input. + +--- + +## Solution Video For Coding Exercise - Is Leap Year + +I hope you've had the opportunity to try out the "Is Leap Year" exercise. If you haven't yet, pause here, give it a shot, and then come back to check out the solution. This will reinforce your learning and help you get comfortable with logical conditions and control structures. + +### Problem Overview: + +In this exercise, you're tasked with determining whether a given year is a leap year based on a set of rules. The method `isLeapYear` takes an integer representing the year, and it should return `true` if the year is a leap year and `false` otherwise. + +### Rules for Identifying a Leap Year: + +1. **Divisibility by 4**: A year is a leap year if it is divisible by 4. +2. **Divisibility by 100**: If a year is divisible by 100, it is **not** a leap year, unless... +3. **Divisibility by 400**: If a year is divisible by 400, it **is** a leap year (overriding the divisibility by 100 rule). + +### Example Breakdown: + +- **2041**: Not divisible by 4, so it is **not** a leap year. +- **2048**: Divisible by 4, and not divisible by 100, so it **is** a leap year. +- **2000**: Divisible by 4 and 100, but also divisible by 400, so it **is** a leap year. +- **2100**: Divisible by 4 and 100, but **not** divisible by 400, so it is **not** a leap year. + +Now, let's implement this logic step by step in the `isLeapYear` method. + +### Step-by-Step Solution: + +### Step 1: Handling the Edge Case (Year ≤ 0) + +The Gregorian calendar does not have a year 0 or negative years, so we first check whether the year is less than or equal to zero. If so, we return `false` immediately. + +```java +if (year <= 0) { + return false; +} +``` + +### Step 2: Check if Year is Divisible by 4 + +If the year is not divisible by 4, it cannot be a leap year. + +```java +if (year % 4 != 0) { + return false; +} +``` + +### Step 3: Handling Years Divisible by 100 + +If the year is divisible by 4, we next check whether it is divisible by 100. If the year is divisible by 100 but **not** divisible by 400, it is not a leap year. + +```java +if (year % 100 == 0 && year % 400 != 0) { + return false; +} +``` + +### Step 4: If None of the Above, It's a Leap Year + +If all the previous conditions fail, the year is a leap year. + +```java +return true; +``` + +### Full Code Implementation: + +```java +public class LeapYearChecker { + + public static boolean isLeapYear(int year) { + // Step 1: Check for invalid year + if (year <= 0) { + return false; + } + + // Step 2: Check if the year is divisible by 4 + if (year % 4 != 0) { + return false; + } + + // Step 3: Check if the year is divisible by 100 but not by 400 + if (year % 100 == 0 && year % 400 != 0) { + return false; + } + + // If none of the above conditions match, it's a leap year + return true; + } +} +``` + +### Explanation of the Code: + +1. **Year Validation**: We first check if the year is less than or equal to zero. If it is, we return `false` because such a year is not valid in the Gregorian calendar. + +2. **Divisibility by 4**: If the year is not divisible by 4, it is not a leap year, so we return `false`. + +3. **Divisibility by 100**: If the year is divisible by both 100 and 4, we check if it is divisible by 400. If it’s not divisible by 400, it is not a leap year, so we return `false`. + +4. **Leap Year**: If none of the previous conditions match, it means the year is a leap year, and we return `true`. + +### Testing the Solution: + +Let’s test the solution with different inputs: + +- **Year 2041**: Not divisible by 4 → **false** +- **Year 2048**: Divisible by 4 and not divisible by 100 → **true** +- **Year 2000**: Divisible by 4, 100, and 400 → **true** +- **Year 2100**: Divisible by 4 and 100 but not 400 → **false** +- **Year 0**: Invalid year → **false** + +### Conclusion: + +This exercise was a good demonstration of using multiple logical conditions to solve a real-world problem like determining leap years. Handling special cases (like divisibility rules and invalid years) is crucial for creating robust solutions. + +--- + +## Solution Video For Coding Exercise - Is Perfect Number + +It's time to solve another coding exercise, and this one is called **Is Perfect Number**. Let’s walk through the problem and its solution step by step. + +### Problem Overview: + +In this exercise, you are tasked with implementing a method in the `PerfectNumberChecker` class that checks whether a given number is a **perfect number**. + +### What is a Perfect Number? + +A perfect number is a positive integer that is equal to the sum of all its positive divisors, **excluding itself**. For example: +- **6** is a perfect number because its divisors (excluding itself) are 1, 2, and 3, and 1 + 2 + 3 = 6. +- **28** is a perfect number because its divisors (excluding itself) are 1, 2, 4, 7, and 14, and 1 + 2 + 4 + 7 + 14 = 28. + +### Task: +The method should return `true` if the number is a perfect number and `false` otherwise. + +### Additional Instructions: +- A perfect number is always a **positive integer**. +- If the number is less than or equal to zero, return `false` immediately. + +### Plan: + +1. First, check if the number is less than or equal to zero. If so, return `false`. +2. Loop through all numbers from 1 to `number - 1`, checking for divisors. +3. Sum up all divisors. +4. If the sum of divisors equals the original number, return `true`. Otherwise, return `false`. + +### Step-by-Step Solution: + +### Step 1: Validate Input + +We start by checking if the number is less than or equal to zero. If that's the case, we know it's not a perfect number. + +```java +if (number <= 0) { + return false; +} +``` + +### Step 2: Loop to Find Divisors + +We need to loop through numbers from 1 to `number - 1` and check if each number is a divisor of the given number. We use the modulo (`%`) operator to find the divisors. + +```java +int sum = 0; +for (int i = 1; i < number; i++) { + if (number % i == 0) { + sum += i; + } +} +``` + +Here, for each divisor `i` (where `number % i == 0`), we add `i` to the `sum`. + +### Step 3: Check if the Sum Equals the Original Number + +At the end of the loop, if the sum of the divisors is equal to the original number, it's a perfect number. + +```java +return sum == number; +``` + +### Full Code Implementation: + +```java +public class PerfectNumberChecker { + + public static boolean isPerfectNumber(int number) { + // Step 1: Handle the case where the number is less than or equal to 0 + if (number <= 0) { + return false; + } + + // Step 2: Find divisors and calculate their sum + int sum = 0; + for (int i = 1; i < number; i++) { + if (number % i == 0) { + sum += i; // Add divisor to sum + } + } + + // Step 3: Check if the sum of divisors equals the original number + return sum == number; + } +} +``` + +### Explanation of the Code: + +1. **Input Validation**: We first check if the number is less than or equal to zero. Since a perfect number must be positive, we return `false` in this case. + +2. **Finding Divisors**: We loop through all numbers from 1 to `number - 1`. For each number `i` that divides `number` evenly (i.e., `number % i == 0`), we add `i` to the `sum`. + +3. **Returning the Result**: After calculating the sum of divisors, we compare it with the original number. If they are equal, the number is a perfect number, and we return `true`. Otherwise, we return `false`. + +### Testing the Solution: + +Let’s test the solution with different inputs: + +- **6**: Divisors are 1, 2, 3, and 1 + 2 + 3 = 6 → **true** (Perfect number). +- **28**: Divisors are 1, 2, 4, 7, 14, and 1 + 2 + 4 + 7 + 14 = 28 → **true** (Perfect number). +- **12**: Divisors are 1, 2, 3, 4, 6, and 1 + 2 + 3 + 4 + 6 = 16 → **false** (Not a perfect number). +- **0**: Not a valid number for checking a perfect number → **false**. + +### Conclusion: + +In this exercise, we implemented a method to determine if a number is a perfect number by: +1. Validating the input. +2. Summing the divisors of the number (excluding the number itself). +3. Returning `true` if the sum equals the original number, otherwise `false`. + +--- + +## Solution Video For Coding Exercise - Student Grades A to F based on Marks + +In this exercise, we will write a program that assigns a grade (A to F) to a student based on their marks. Let's walk through the problem step by step and solve it. + +### Problem Overview: + +You're tasked with implementing the functionality of a `Student` class that calculates and assigns the student's grade based on the provided marks. + +### Grading Criteria: + +- **Marks >= 90**: Grade A +- **Marks >= 80**: Grade B +- **Marks >= 70**: Grade C +- **Marks >= 60**: Grade D +- **Marks >= 50**: Grade E +- **Marks < 50**: Grade F +- If the marks are less than 0 or greater than 100, return 'X' to indicate invalid marks. + +### Steps to Solve: + +1. **Constructor**: We will initialize the student's marks using the constructor. +2. **Assign Grade Method**: We will implement the logic to assign grades based on the criteria mentioned above. + +### Step-by-Step Solution: + +### Step 1: Constructor + +We start by implementing the constructor to initialize the `marks` instance variable. + +```java +public class Student { + int marks; + + // Constructor + public Student(int marks) { + this.marks = marks; + } +} +``` + +Here, the constructor initializes the `marks` with the value passed as an argument. + +### Step 2: Assign Grade Logic + +Now, let's implement the `assignGrade` method that returns the appropriate grade based on the marks. + +#### 2.1: Invalid Marks Case + +First, we check if the marks are invalid. Marks must be between 0 and 100. If the marks are outside this range, we return 'X'. + +```java +if (marks > 100 || marks < 0) { + return 'X'; // Invalid marks +} +``` + +#### 2.2: Grade A to F + +Next, we implement the grading logic based on the marks ranges: + +- If marks are greater than or equal to 90, return 'A'. +- If marks are greater than or equal to 80, return 'B'. +- If marks are greater than or equal to 70, return 'C'. +- If marks are greater than or equal to 60, return 'D'. +- If marks are greater than or equal to 50, return 'E'. +- Otherwise, return 'F' (for marks less than 50). + +Here’s the code: + +```java +public char assignGrade() { + if (marks > 100 || marks < 0) { + return 'X'; // Invalid marks + } + if (marks >= 90) { + return 'A'; + } + if (marks >= 80) { + return 'B'; + } + if (marks >= 70) { + return 'C'; + } + if (marks >= 60) { + return 'D'; + } + if (marks >= 50) { + return 'E'; + } + return 'F'; // Marks less than 50 +} +``` + +### Full Code Implementation: + +```java +public class Student { + int marks; + + // Constructor + public Student(int marks) { + this.marks = marks; + } + + // Method to assign grade based on marks + public char assignGrade() { + if (marks > 100 || marks < 0) { + return 'X'; // Invalid marks + } + if (marks >= 90) { + return 'A'; + } + if (marks >= 80) { + return 'B'; + } + if (marks >= 70) { + return 'C'; + } + if (marks >= 60) { + return 'D'; + } + if (marks >= 50) { + return 'E'; + } + return 'F'; // Marks less than 50 + } +} +``` + +### Explanation: + +1. **Input Validation**: We first check if the marks are valid. Marks should be between 0 and 100. If the marks are not within this range, we return 'X' for invalid input. + +2. **Grading Logic**: + - We check the conditions in descending order from the highest grade (A) to the lowest grade (F). + - Each condition is evaluated in sequence, and the correct grade is returned based on the marks range. + +3. **Efficiency**: The program checks each condition one at a time, returning the appropriate grade as soon as the condition is met. If no condition is met, it returns 'F' for marks less than 50. + +### Testing the Solution: + +Let’s test the solution with various inputs: + +- **Marks = 95**: Should return 'A'. +- **Marks = 85**: Should return 'B'. +- **Marks = 75**: Should return 'C'. +- **Marks = 65**: Should return 'D'. +- **Marks = 55**: Should return 'E'. +- **Marks = 45**: Should return 'F'. +- **Marks = -10**: Should return 'X' (invalid input). +- **Marks = 105**: Should return 'X' (invalid input). + +### Running the Tests: + +After implementing the solution, we run the test cases, and the solution successfully passes all of them. + +- Test for grade 'A', 'B', 'C', 'D', 'E', 'F', and invalid grade 'X'. +- All the tests pass successfully. + +### Conclusion: + +In this exercise, we implemented a `Student` class that assigns grades to students based on their marks. We handled various conditions for valid and invalid marks and used simple if-statements to determine the correct grade. + +--- + +## Solution Video For Coding Exercise - Weather Advisor + +In this exercise, we're going to implement a class that provides advice on what to wear based on the current temperature. Let's go over the problem step by step. + +### Problem Overview: + +You are tasked with implementing a method called `provideWeatherAdvisory` inside the `WeatherAdvisor` class. The method takes a temperature as input and returns a string containing advice on what to wear based on the given temperature. + +### Temperature Ranges and Corresponding Advice: + +- **Temperature < 0**: Return `"It's freezing! Stay inside!"` +- **Temperature between 0 and 10 (inclusive)**: Return `"It's cold! Bundle up."` +- **Temperature between 11 and 20 (inclusive)**: Return `"It's cool! A light jacket will do."` +- **Temperature > 20**: Return `"It's warm! Enjoy the day."` + +### Step-by-Step Solution: + +### Step 1: Skeleton Code + +The provided skeleton includes the method signature and the task is to fill in the logic for determining the appropriate weather advice based on the temperature. + +We have the method: +```java +public class WeatherAdvisor { + public String provideWeatherAdvisory(int temperature) { + // TODO: Implement the logic here + } +} +``` + +### Step 2: Implementing the Logic + +We will write conditional statements to check the temperature and return the appropriate advice. + +1. **Temperature less than 0**: We return `"It's freezing! Stay inside!"` +2. **Temperature between 0 and 10 (inclusive)**: We return `"It's cold! Bundle up."` +3. **Temperature between 11 and 20 (inclusive)**: We return `"It's cool! A light jacket will do."` +4. **Temperature greater than 20**: We return `"It's warm! Enjoy the day."` + +Here’s the implementation: + +```java +public class WeatherAdvisor { + public String provideWeatherAdvisory(int temperature) { + if (temperature < 0) { + return "It's freezing! Stay inside!"; + } + if (temperature <= 10) { + return "It's cold! Bundle up."; + } + if (temperature <= 20) { + return "It's cool! A light jacket will do."; + } + return "It's warm! Enjoy the day."; + } +} +``` + +### Explanation: + +- **First Condition**: If the temperature is less than 0, we return `"It's freezing! Stay inside!"` +- **Second Condition**: If the temperature is between 0 and 10 (inclusive), we return `"It's cold! Bundle up."` +- **Third Condition**: If the temperature is between 11 and 20 (inclusive), we return `"It's cool! A light jacket will do."` +- **Final Condition**: If the temperature is greater than 20, we return `"It's warm! Enjoy the day."` + +### Step 3: Optimizing the Code + +We can simplify the code by removing the unnecessary `else` statements. Since each `if` block either returns a value or continues to the next condition, there is no need for the `else`. + +Here’s the optimized version: + +```java +public class WeatherAdvisor { + public String provideWeatherAdvisory(int temperature) { + if (temperature < 0) { + return "It's freezing! Stay inside!"; + } + if (temperature <= 10) { + return "It's cold! Bundle up."; + } + if (temperature <= 20) { + return "It's cool! A light jacket will do."; + } + return "It's warm! Enjoy the day."; + } +} +``` + +### Testing the Solution: + +Let’s test the solution with a few inputs: + +- **Temperature = -5**: Should return `"It's freezing! Stay inside!"` +- **Temperature = 5**: Should return `"It's cold! Bundle up."` +- **Temperature = 15**: Should return `"It's cool! A light jacket will do."` +- **Temperature = 25**: Should return `"It's warm! Enjoy the day."` + +### Running the Tests: + +After running the tests, all the test cases pass successfully. + +### Conclusion: + +In this exercise, we successfully implemented a `WeatherAdvisor` class that provides advice based on the temperature. The conditions were straightforward, and we optimized the code for readability and simplicity. + +--- + +## Solution Video For Coding Exercise - Switch with Char: Is a Vowel or Not + +Let's dive into another exercise—this time, it's about using a **switch statement** with a `char` type to determine whether a character is a vowel or not. We're going to implement a method inside the `MyChar` class that checks if the given character is a vowel (either uppercase or lowercase). + +### Problem Overview: + +We need to implement the method `isVowel` in the `MyChar` class. This method accepts a character as input and returns `true` if the character is a vowel (`A`, `E`, `I`, `O`, `U`—both uppercase and lowercase) and `false` otherwise. + +### Step-by-Step Solution: + +### Step 1: Skeleton Code + +The provided skeleton contains the following: + +```java +public class MyChar { + public boolean isVowel(char ch) { + switch (ch) { + // TODO: Implement the switch cases + } + return false; + } +} +``` + +Our task is to implement the switch cases for the vowels (both lowercase and uppercase) inside the `isVowel` method. + +### Step 2: Implementing the Switch Statement + +To start, we'll write a switch statement that checks for both lowercase (`a`, `e`, `i`, `o`, `u`) and uppercase (`A`, `E`, `I`, `O`, `U`) vowels. If the character matches any of these cases, we return `true`; otherwise, we return `false`. + +Here’s how we can start: + +```java +public class MyChar { + public boolean isVowel(char ch) { + switch (ch) { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + case 'A': + case 'E': + case 'I': + case 'O': + case 'U': + return true; + default: + return false; + } + } +} +``` + +### Explanation: + +- **Case 'a'**: If the input character is lowercase `a`, it returns `true`. +- We handle other vowels (`e`, `i`, `o`, `u` and their uppercase counterparts) in the same way by listing them in the switch cases. +- **Default**: If the character does not match any of the vowels, we return `false`. + +### Step 3: Test and Run + +Let’s test the solution with a few characters: + +- Input: `'A'` should return `true`. +- Input: `'b'` should return `false`. +- Input: `'E'` should return `true`. +- Input: `'F'` should return `false`. + +### Running the Tests: + +All test cases should pass successfully. + +### Step 4: Code Optimization + +We can further simplify the code. Since multiple cases in our switch statement return the same value (`true` for vowels), we can leverage **fall-through** behavior. Instead of writing a return statement for each vowel, we group them together like this: + +```java +public class MyChar { + public boolean isVowel(char ch) { + switch (ch) { + case 'a', 'e', 'i', 'o', 'u': + case 'A', 'E', 'I', 'O', 'U': + return true; + default: + return false; + } + } +} +``` + +### Explanation of the Optimization: + +- We combined all the lowercase vowels into a single case: `'a', 'e', 'i', 'o', 'u'`. +- Similarly, we combined all the uppercase vowels into one line: `'A', 'E', 'I', 'O', 'U'`. +- The `switch` statement now directly returns `true` for any of these cases and `false` for everything else. + +### Final Code: + +```java +public class MyChar { + public boolean isVowel(char ch) { + switch (ch) { + case 'a', 'e', 'i', 'o', 'u': + case 'A', 'E', 'I', 'O', 'U': + return true; + default: + return false; + } + } +} +``` + +### Conclusion: + +We successfully implemented the method to check whether a character is a vowel using a `switch` statement, and optimized the code to handle multiple cases efficiently. All test cases pass, and the code is easy to read and maintain. + +--- + +## Section 15: Java Coding Exercises - Set 4 + +## Solution Video For Coding Exercise - Calculate Factorial Of a Number + +Welcome back! In this exercise, we will calculate the factorial of a given number using Java. This is a common coding problem, and the logic behind it is straightforward once we understand the concept of a factorial. + +### Problem Overview: + +A **factorial** of a non-negative integer `N`, denoted as `N!`, is the product of all positive integers less than or equal to `N`. For example: + +- `4! = 4 * 3 * 2 * 1 = 24` +- `3! = 3 * 2 * 1 = 6` +- `2! = 2 * 1 = 2` +- `1! = 1` + +If the input is **negative**, we are required to return `-1` as factorials are not defined for negative numbers. + +### Step-by-Step Solution: + +### Step 1: Understanding the Skeleton + +We have a class called `FactorialCalculator` with a method `calculateFactorial` that accepts an integer `number` as input. Our job is to implement this method to compute the factorial or return `-1` if the input is negative. + +Here’s the starting skeleton code: + +```java +public class FactorialCalculator { + public int calculateFactorial(int number) { + // TODO: Implement the method to calculate factorial + return -1; + } +} +``` + +### Step 2: Add Input Validation for Negative Numbers + +The first thing we need to do is handle invalid input. If the number is negative, the method should return `-1`. This can be done with a simple `if` check: + +```java +if (number < 0) { + return -1; +} +``` + +### Step 3: Initialize a Variable for the Factorial Calculation + +Next, we initialize a variable `factorial` with a value of `1`. This variable will store the result of the factorial as we multiply values from 2 up to `number`. Initializing it as `1` ensures that any number multiplied by it will retain its value (since multiplying by zero would result in zero, which is incorrect for factorials). + +```java +int factorial = 1; +``` + +### Step 4: Loop to Calculate the Factorial + +We now need to loop through all the numbers from `2` to `number`, multiplying them together and storing the result in the `factorial` variable. Here's how we can do that: + +```java +for (int i = 2; i <= number; i++) { + factorial *= i; +} +``` + +### Step 5: Return the Final Result + +Finally, after the loop finishes, we return the `factorial` variable, which contains the calculated factorial of the input number. + +```java +return factorial; +``` + +### Complete Code: + +Here is the complete implementation of the `calculateFactorial` method: + +```java +public class FactorialCalculator { + public int calculateFactorial(int number) { + if (number < 0) { + return -1; + } + + int factorial = 1; + + for (int i = 2; i <= number; i++) { + factorial *= i; + } + + return factorial; + } +} +``` + +### Step 6: Test the Code + +Let’s run the code with some test cases: + +- Input: `4` should return `24` (since `4! = 4 * 3 * 2 * 1 = 24`) +- Input: `3` should return `6` (since `3! = 3 * 2 * 1 = 6`) +- Input: `2` should return `2` +- Input: `1` should return `1` +- Input: `0` should return `1` (since `0!` is defined as `1`) +- Input: `-5` should return `-1` (invalid input) + +### Run the Tests: + +After running the tests, all of them pass successfully. The code correctly handles positive numbers and the special case of negative input. + +### Conclusion: + +In this solution, we started by validating the input and then used a simple loop to calculate the factorial of a given number. The logic was straightforward—multiplying all integers from `2` to `number` to compute the factorial. + +--- + +## Solution Video For Coding Exercise - Find Last Digit Of A Number + +In this coding exercise, we are going to implement a method that retrieves the last digit of a given number. This exercise is simple, but it forms the basis for more complex tasks, so it's important to get it right. + +### Problem Overview + +We are tasked with completing the implementation of the `NumberUtils` class in Java, where we need to write a method to find the last digit of a number. Here are the specific rules: + +1. **For positive numbers**, return the last digit. + - Example: For `2345`, the last digit is `5`. + - For `90`, the last digit is `0`. +2. **For zero**, return `0` as the last digit. + - Example: For `0`, the last digit is `0`. +3. **For negative numbers**, return `-1` to indicate that we do not handle negative inputs. + - Example: For `-67`, return `-1`. + +### Step-by-Step Approach + +### Step 1: Check for Negative Numbers + +The first step is to handle negative inputs. If the number is negative, we need to return `-1` immediately. We can easily do this with an `if` condition: + +```java +if (number < 0) { + return -1; +} +``` + +### Step 2: Find the Last Digit + +For non-negative numbers, we can find the last digit using the **modulo operation**. The expression `number % 10` gives us the remainder when the number is divided by 10, which is exactly the last digit. + +For example: +- `2345 % 10` gives `5` +- `90 % 10` gives `0` +- `9 % 10` gives `9` + +Thus, to get the last digit, we simply return `number % 10`. + +### Complete Code + +Here is the complete implementation of the `findLastDigit` method in the `NumberUtils` class: + +```java +public class NumberUtils { + public int findLastDigit(int number) { + if (number < 0) { + return -1; + } + return number % 10; + } +} +``` + +### Step 3: Test the Code + +Let’s walk through a few test cases to ensure our solution works: + +1. **Positive Number (Example: 1234):** + - The last digit of `1234` is `4`, so the method should return `4`. +2. **Number Ending in Zero (Example: 90):** + - The last digit of `90` is `0`, so the method should return `0`. +3. **Single Digit Number (Example: 9):** + - The last digit of `9` is `9`, so the method should return `9`. +4. **Zero (Example: 0):** + - The last digit of `0` is `0`, so the method should return `0`. +5. **Negative Number (Example: -67):** + - The input is negative, so the method should return `-1`. + +### Run the Tests + +After running the tests, all of them pass successfully, meaning our solution is correct. + +### Conclusion + +In this exercise, we learned how to find the last digit of a number using the modulo operator and handled different cases like negative numbers and zero. This simple exercise forms the foundation for more complex operations. + +--- + +## Solution Video For Coding Exercise - Find Number of Digits in a Number + +In this exercise, we're going to find the number of digits in a given number. This is a fundamental programming problem, and it’s great practice to improve your logic-building skills. + +### Problem Overview + +The task is to complete the implementation of a method that calculates the number of digits in a given integer. + +- For **positive numbers**, return the total number of digits. + - Example: For `12345`, the number of digits is `5`. + - For `90`, the number of digits is `2`. +- For **zero**, return `1`. Even though it's zero, it's considered to have one digit. + - Example: For `0`, the number of digits is `1`. +- For **negative numbers**, return `-1`. In this problem, we're not counting the digits for negative numbers. + +### Step-by-Step Solution + +Let's break down the steps needed to solve this problem: + +### Step 1: Handle Edge Cases First + +The first thing we want to do is handle the special cases for **zero** and **negative numbers**. The logic is simple: +- If the number is **negative**, we return `-1`. +- If the number is **zero**, we return `1`. + +This is how we can implement the initial conditions: + +```java +if (number < 0) { + return -1; +} + +if (number == 0) { + return 1; +} +``` + +### Step 2: Calculate the Number of Digits for Positive Numbers + +For positive numbers, we can use **integer division** to determine the number of digits. The idea is simple: +- Keep dividing the number by `10` until the number becomes zero. +- Each time you divide by `10`, you count how many times you are able to divide. This will give the total number of digits. + +For example: +- Start with `12345`. Divide by `10` -> `1234`. +- Divide by `10` again -> `123`. +- Continue dividing until the number becomes zero. +- The number of divisions corresponds to the number of digits. + +### Step 3: Implement the Loop + +We will use a `while` loop to keep dividing the number by `10` until it becomes zero. For each division, we increment a counter: + +```java +int numberOfDigits = 0; +while (number > 0) { + number = number / 10; // Integer division + numberOfDigits++; +} +``` + +### Complete Code + +Here is the complete implementation of the `getNumberOfDigits` method in the `NumberUtils` class: + +```java +public class NumberUtils { + public int getNumberOfDigits(int number) { + if (number < 0) { + return -1; // Negative numbers return -1 + } + + if (number == 0) { + return 1; // Zero is considered to have one digit + } + + int numberOfDigits = 0; + + // Divide the number by 10 until it becomes 0, counting how many times + while (number > 0) { + number = number / 10; + numberOfDigits++; + } + + return numberOfDigits; + } +} +``` + +### Step 4: Test the Solution + +Let’s go through a few test cases to ensure the solution works: + +1. **Positive Number (Example: 12345):** + - The number of digits is `5`. +2. **Number Ending in Zero (Example: 90):** + - The number of digits is `2`. +3. **Zero (Example: 0):** + - The number of digits is `1`. +4. **Negative Number (Example: -123):** + - Since the number is negative, the output should be `-1`. + +### Run the Tests + +After running the tests, all of them pass successfully, which confirms that the solution works for all edge cases. + +### Conclusion + +In this exercise, we learned how to find the number of digits in a given number using integer division. We also handled special cases like zero and negative numbers. + +--- + +## Solution Video For Coding Exercise - Calculate Sum of Digits of a Number + +In this exercise, we are tasked with calculating the sum of the digits of a number. This is a common programming challenge that is similar to the exercise where we counted the number of digits in a number. + +### Problem Overview + +In this problem, you need to complete the implementation of the `NumberUtils` class in Java by writing a method called `getSumOfDigits`. This method should: + +- **Return -1** if the input number is negative. +- **Return 0** if the input number is 0. +- For **positive numbers**, calculate and return the sum of its digits. + +### Examples: +- For `1234`, the output should be `1 + 2 + 3 + 4 = 10`. +- For `90`, the output should be `9 + 0 = 9`. +- For `-45` (a negative number), the output should be `-1`. + +### Approach + +Let's break down how we can solve this problem step by step. + +### Step 1: Handle Special Cases +We first handle the edge cases: +- If the number is **negative**, return `-1`. +- If the number is **zero**, return `0`. + +### Step 2: Calculate the Sum of Digits +For positive numbers, we need to extract each digit and sum them. Here's how: +- Use the modulo operator (`%`) to get the last digit of the number. +- Add the last digit to the sum. +- Use integer division (`/`) by 10 to remove the last digit from the number. +- Repeat the process until the number becomes zero. + +### Step 3: Loop Until the Number Becomes Zero +We will use a `while` loop to keep extracting digits and adding them until the number becomes zero. + +### Implementation + +Let's go ahead and implement the solution. + +```java +public class NumberUtils { + public int getSumOfDigits(int number) { + // Step 1: Handle special cases + if (number < 0) { + return -1; + } + + if (number == 0) { + return 0; + } + + // Step 2: Initialize sum of digits + int sumOfDigits = 0; + + // Step 3: Extract digits and calculate the sum + while (number > 0) { + int digit = number % 10; // Get the last digit + sumOfDigits += digit; // Add the digit to the sum + number = number / 10; // Remove the last digit from the number + } + + // Step 4: Return the calculated sum + return sumOfDigits; + } +} +``` + +### How the Code Works + +### Example 1: Input `1234` +- The initial number is `1234`. +- In the first iteration: `1234 % 10 = 4`, so the sum becomes `0 + 4 = 4`. Then, `1234 / 10 = 123`. +- In the second iteration: `123 % 10 = 3`, so the sum becomes `4 + 3 = 7`. Then, `123 / 10 = 12`. +- In the third iteration: `12 % 10 = 2`, so the sum becomes `7 + 2 = 9`. Then, `12 / 10 = 1`. +- In the fourth iteration: `1 % 10 = 1`, so the sum becomes `9 + 1 = 10`. Then, `1 / 10 = 0`, and the loop ends. + +The final sum is `10`. + +### Example 2: Input `90` +- The initial number is `90`. +- First iteration: `90 % 10 = 0`, so the sum becomes `0 + 0 = 0`. Then, `90 / 10 = 9`. +- Second iteration: `9 % 10 = 9`, so the sum becomes `0 + 9 = 9`. Then, `9 / 10 = 0`, and the loop ends. + +The final sum is `9`. + +### Example 3: Input `-45` +- The number is negative, so the method returns `-1` immediately without any further calculation. + +### Test the Solution + +We can test this solution with various test cases to ensure it works for all edge cases: + +1. **Positive Number**: `1234` → Output: `10`. +2. **Single Digit**: `9` → Output: `9`. +3. **Zero**: `0` → Output: `0`. +4. **Negative Number**: `-45` → Output: `-1`. + +### Run the Tests + +After running the tests, all of them passed successfully: + +- 15 test cases, including edge cases like `0`, negative numbers, and different positive numbers, were tested. +- The solution passed all the tests. + +### Conclusion + +In this exercise, we learned how to calculate the sum of the digits of a number by using a simple loop with the modulo and division operations. We also handled special cases for zero and negative numbers. + +--- + +## Solution Video For Coding Exercise - Reverse a Number + +In this problem, we will be working on reversing a number. + +### Problem Overview + +You are tasked with completing the method `reverseNumber` in the `NumberUtils` class. This method takes an integer as input and returns the reversed version of the number. Here are the specific rules: + +- If the input number is **0**, the method should return `0`. +- If the input number is **negative**, the method should return `-1`. +- For any positive number, the method should return the reversed number. + +### Examples: +- Input: `123` → Output: `321` +- Input: `5497` → Output: `7945` +- Input: `-456` → Output: `-1` +- Input: `0` → Output: `0` + +Now that we understand the requirements, let's get started! + +### Approach + +### Step 1: Handle Edge Cases +We need to handle two specific edge cases first: +1. If the number is **negative**, return `-1`. +2. If the number is **zero**, return `0`. + +### Step 2: Reversing the Number +To reverse a number: +1. Extract the digits starting from the rightmost one. We can do this by using the modulo operator (`% 10`). +2. Keep adding the digits to a new number, adjusting the position of each new digit by multiplying the previous result by 10. +3. Continue until all the digits have been extracted. + +### Step 3: Return the Reversed Number +Once all digits are processed, return the reversed number. + +### Code Implementation + +Let's break down how to implement this in Java. + +```java +public class NumberUtils { + public int reverseNumber(int number) { + // Step 1: Handle edge cases + if (number < 0) { + return -1; // Negative number returns -1 + } + if (number == 0) { + return 0; // Zero returns zero + } + + // Step 2: Initialize variables + int reversedNumber = 0; + while (number > 0) { + int digit = number % 10; // Extract the last digit + reversedNumber = reversedNumber * 10 + digit; // Add the digit to the reversed number + number = number / 10; // Remove the last digit + } + + // Step 3: Return the reversed number + return reversedNumber; + } +} +``` + +### Explanation: + +1. **Edge Case Handling**: + - If the number is negative, we return `-1` immediately. + - If the number is `0`, we return `0` immediately. + +2. **Reversing Logic**: + - We initialize `reversedNumber` to `0`. + - We loop through the digits of the number using `number % 10` to get the last digit. + - We then multiply the current `reversedNumber` by `10` and add the digit to it. + - Finally, we remove the last digit from the original number by dividing it by `10`. + +3. **Return**: + - After the loop, we return the `reversedNumber` containing the reversed digits. + +### Test Example + +Let's go through an example: + +### Input: `456` +- Initial number: `456` +- First iteration: + - `digit = 456 % 10 = 6` + - `reversedNumber = 0 * 10 + 6 = 6` + - `number = 456 / 10 = 45` +- Second iteration: + - `digit = 45 % 10 = 5` + - `reversedNumber = 6 * 10 + 5 = 65` + - `number = 45 / 10 = 4` +- Third iteration: + - `digit = 4 % 10 = 4` + - `reversedNumber = 65 * 10 + 4 = 654` + - `number = 4 / 10 = 0` + +At this point, the number becomes `0`, so the loop terminates and we return the `reversedNumber`, which is `654`. + +### Input: `5497` +- Reversed result: `7945` + +### Input: `-456` +- Reversed result: `-1` (since it's negative). + +### Input: `0` +- Reversed result: `0`. + +### Testing the Solution + +After implementing the solution, I ran several tests, including edge cases like `0`, negative numbers, and multi-digit numbers. + +The solution successfully passed all test cases: +- **Input**: `1234` → **Output**: `4321` +- **Input**: `1000` → **Output**: `1` +- **Input**: `0` → **Output**: `0` +- **Input**: `-45` → **Output**: `-1` +- **Input**: `56789` → **Output**: `98765` + +### Conclusion + +In this exercise, we learned how to reverse a number by extracting digits one by one and constructing the reversed number. We also handled special cases for negative numbers and zero. This is a fundamental problem that demonstrates how we can manipulate digits of a number using arithmetic operations. + +--- + +## Solution Video For Coding Exercise - LCM Of A Number + +In this coding exercise, we’ll be tackling a problem where you need to calculate the **Least Common Multiple (LCM)** of two numbers. + +### Problem Overview + +We are given a class `BiNumber` with two integer attributes, `number1` and `number2`. Our task is to implement a method `calculateLCM` that computes the least common multiple of `number1` and `number2`. + +### Rules: +1. If **either** number is negative, the method should return `-1`. +2. If **either** number is zero, the method should return `0`. +3. Otherwise, calculate the LCM using the logic described below. + +### What is LCM? + +The **Least Common Multiple (LCM)** of two numbers is the smallest positive integer that is divisible by both numbers. For example: +- **LCM(6, 8)** = 24 (since 24 is divisible by both 6 and 8, and is the smallest such number). +- **LCM(5, 10)** = 10 (since 10 is divisible by both 5 and 10). + +### Special Conditions: +- If **either** number is negative, return `-1`. +- If **either** number is zero, return `0`. + +### Approach + +### Step 1: Handle Edge Cases +We first check: +1. If either `number1` or `number2` is negative, return `-1`. +2. If either number is zero, return `0`. + +### Step 2: Calculate LCM +To compute the LCM: +1. Use the formula: + \[ + \text{LCM}(a, b) = \frac{|a \times b|}{\text{GCD}(a, b)} + \] + where **GCD** is the **Greatest Common Divisor**. + + - For example, LCM(6, 8) = \(\frac{6 \times 8}{\text{GCD}(6, 8)} = \frac{48}{2} = 24\). + +### Step 3: Implement the Solution + +We'll use the built-in method to find the GCD of two numbers and use it in the formula for calculating LCM. + +### Code Implementation + +```java +public class BiNumber { + private int number1; + private int number2; + + // Constructor + public BiNumber(int number1, int number2) { + this.number1 = number1; + this.number2 = number2; + } + + // Getters for number1 and number2 + public int getNumber1() { + return number1; + } + + public int getNumber2() { + return number2; + } + + // Method to calculate LCM + public int calculateLCM() { + // Step 1: Handle edge cases + if (number1 < 0 || number2 < 0) { + return -1; // Return -1 if either number is negative + } + if (number1 == 0 || number2 == 0) { + return 0; // Return 0 if either number is zero + } + + // Step 2: Calculate LCM using the formula + int gcd = findGCD(number1, number2); // Find GCD of the two numbers + int lcm = Math.abs(number1 * number2) / gcd; // Calculate LCM using the formula + + return lcm; // Return the LCM + } + + // Helper method to find the GCD (Greatest Common Divisor) + private int findGCD(int a, int b) { + // Use the Euclidean algorithm to find GCD + while (b != 0) { + int temp = b; + b = a % b; + a = temp; + } + return a; // Return the GCD + } +} +``` + +### Explanation: + +1. **Edge Case Handling**: + - If either number is less than zero, we return `-1`. + - If either number is zero, we return `0`. + +2. **GCD Calculation**: + - The **Greatest Common Divisor (GCD)** is calculated using the **Euclidean algorithm**. This algorithm uses a simple loop where we replace the larger number with the remainder of the division between the two numbers until one of them becomes zero. + +3. **LCM Calculation**: + - Using the formula \(\text{LCM}(a, b) = \frac{|a \times b|}{\text{GCD}(a, b)}\), we compute the LCM. + +4. **Return the Result**: + - Finally, the method returns the calculated LCM. + +### Test Example + +### Example 1: LCM(6, 8) +- **GCD** of 6 and 8 is 2. +- **LCM** is \(\frac{6 \times 8}{2} = 24\). +- **Output**: 24. + +### Example 2: LCM(5, 10) +- **GCD** of 5 and 10 is 5. +- **LCM** is \(\frac{5 \times 10}{5} = 10\). +- **Output**: 10. + +### Example 3: LCM(0, 8) +- **Output**: 0 (since one of the numbers is zero). + +### Example 4: LCM(-5, 10) +- **Output**: -1 (since one of the numbers is negative). + +### Testing the Solution + +After implementing the solution, I ran tests for a variety of inputs, including edge cases for zero and negative numbers. + +All tests passed successfully: +- **Input**: `6, 8` → **Output**: `24` +- **Input**: `5, 10` → **Output**: `10` +- **Input**: `0, 8` → **Output**: `0` +- **Input**: `-5, 10` → **Output**: `-1` + +### Conclusion + +In this exercise, we learned how to calculate the **Least Common Multiple (LCM)** of two numbers. We used the formula involving the **Greatest Common Divisor (GCD)** to compute the LCM efficiently. Additionally, we handled special cases for negative and zero values. + +--- + +## Solution Video For Coding Exercise - GCD of a Number + +In this coding exercise, we’ll be solving the problem of finding the **Greatest Common Divisor (GCD)** of two numbers. + +### Problem Overview + +You are given a class `BiNumber` with two integer attributes, `number1` and `number2`. The task is to complete the method `calculateGCD` that calculates the GCD of `number1` and `number2`. + +### What is GCD? + +The **Greatest Common Divisor (GCD)** of two numbers is the largest number that divides both numbers without leaving a remainder. + +For example: +- **GCD(48, 18)** = 6 (since 6 is the largest number that divides both 48 and 18). +- **GCD(56, 98)** = 14. + +### Edge Cases: +1. If **either** number is zero, return `0`. +2. If **either** number is negative, return `1`. +3. If both numbers are equal, return `number1` or `number2`, as their GCD is the number itself. + +### Approach + +### Step 1: Handle Edge Cases +We first handle the following: +1. If either number is zero, return `0`. +2. If either number is negative, return `1`. +3. If both numbers are equal, return one of them, as the GCD of two equal numbers is the number itself. + +### Step 2: Calculate GCD +To calculate the GCD, we can use the **Euclidean algorithm**: +1. The GCD of two numbers `a` and `b` can be found by replacing `a` with `b` and `b` with `a % b`, and repeating the process until `b` becomes zero. +2. When `b` becomes zero, `a` will hold the GCD. + +### Step 3: Implement the Solution + +### Code Implementation + +```java +public class BiNumber { + private int number1; + private int number2; + + // Constructor + public BiNumber(int number1, int number2) { + this.number1 = number1; + this.number2 = number2; + } + + // Getters for number1 and number2 + public int getNumber1() { + return number1; + } + + public int getNumber2() { + return number2; + } + + // Method to calculate GCD + public int calculateGCD() { + // Step 1: Handle edge cases + if (number1 == 0 || number2 == 0) { + return 0; // GCD with zero is zero + } + if (number1 < 0 || number2 < 0) { + return 1; // GCD for negative numbers is 1 + } + if (number1 == number2) { + return number1; // GCD of equal numbers is the number itself + } + + // Step 2: Use Euclidean algorithm to calculate GCD + int a = number1; + int b = number2; + + // Euclidean algorithm: keep replacing a with b, and b with a % b, until b becomes zero + while (b != 0) { + int temp = b; + b = a % b; + a = temp; + } + + return a; // GCD is stored in a + } +} +``` + +### Explanation: + +1. **Edge Case Handling**: + - If either `number1` or `number2` is zero, return `0`. + - If either number is negative, return `1`. + - If the two numbers are equal, return either one, as the GCD of two equal numbers is the number itself. + +2. **Euclidean Algorithm**: + - We use the **Euclidean algorithm** to efficiently compute the GCD. The process involves repeatedly replacing the larger number with the remainder of the division between the two numbers, until one of the numbers becomes zero. The GCD will be the last non-zero number. + +3. **Return the Result**: + - Finally, the method returns the computed GCD. + +### Test Example + +### Example 1: GCD(48, 18) +- Step-by-step: + - \( 48 \mod 18 = 12 \) + - \( 18 \mod 12 = 6 \) + - \( 12 \mod 6 = 0 \) +- **GCD** is 6. + +### Example 2: GCD(56, 98) +- Step-by-step: + - \( 98 \mod 56 = 42 \) + - \( 56 \mod 42 = 14 \) + - \( 42 \mod 14 = 0 \) +- **GCD** is 14. + +### Example 3: GCD(0, 8) +- **Output**: 0 (since one of the numbers is zero). + +### Example 4: GCD(-5, 10) +- **Output**: 1 (since one of the numbers is negative). + +### Testing the Solution + +After implementing the solution, I ran tests for various inputs, including edge cases for zero and negative numbers. + +All tests passed successfully: +- **Input**: `48, 18` → **Output**: `6` +- **Input**: `56, 98` → **Output**: `14` +- **Input**: `0, 8` → **Output**: `0` +- **Input**: `-5, 10` → **Output**: `1` + +### Conclusion + +In this exercise, we learned how to efficiently compute the **Greatest Common Divisor (GCD)** of two numbers using the **Euclidean algorithm**. This approach is efficient and handles edge cases such as zero and negative numbers. + +--- + +## Section 17: Java Coding Exercises - Set 5 + +## Solution Video For Coding Exercise - Count Uppercase Letters in a String + +Welcome to the solution for the coding exercise: **Count Uppercase Letters in a String**. + +### Problem Overview + +Your task is to complete a Java method called `countUppercaseLetters` in the `StringMagic` class. This method takes a string as input and returns the number of uppercase letters in that string. + +### Edge Cases: +- If the string is **empty**, the method should return `0`. +- If the string **does not contain any uppercase letters**, the method should return `0`. + +### Example: +- Input: `"Hello WORld"` + - Uppercase letters: `H`, `W`, `O`, `R`, `L`. + - **Output**: `5`. + +### Approach + +### Step 1: Handle Edge Cases +We will first check if the string is `null` to avoid any `NullPointerException`. If the string is `null`, we return `-1` as an indicator of an invalid input. + +Next, we handle an empty string. If the string is empty, we return `0` since there are no characters to check. + +### Step 2: Loop Through the String +We will iterate through the string character by character and check if each character is uppercase using the `Character.isUpperCase()` method. + +### Step 3: Count Uppercase Letters +For each uppercase letter we encounter, we will increment a counter. Finally, we return the count of uppercase letters. + +### Code Implementation + +```java +public class StringMagic { + + // Method to count uppercase letters in a string + public int countUppercaseLetters(String str) { + // Step 1: Handle null case + if (str == null) { + return -1; // Return -1 for invalid input (null) + } + + // Step 2: Initialize counter for uppercase letters + int count = 0; + + // Step 3: Loop through the string and check for uppercase letters + for (int i = 0; i < str.length(); i++) { + // Get character at current index + char currentChar = str.charAt(i); + + // Step 4: Check if the character is uppercase + if (Character.isUpperCase(currentChar)) { + count++; // Increment count if the character is uppercase + } + } + + // Step 5: Return the total count of uppercase letters + return count; + } +} +``` + +### Explanation: +1. **Null Check**: + - We first check if the input string is `null`. If it is, we return `-1` as an indicator of invalid input. + +2. **Count Initialization**: + - We initialize a counter `count` to `0` which will keep track of the number of uppercase letters found in the string. + +3. **Loop Through the String**: + - We loop through the string using `for (int i = 0; i < str.length(); i++)`. + - For each character, we use `str.charAt(i)` to get the character at the current index. + +4. **Uppercase Check**: + - We use `Character.isUpperCase(currentChar)` to check if the character is uppercase. If it is, we increment the counter. + +5. **Return the Count**: + - Once the loop completes, we return the count of uppercase letters. + +### Test Example + +### Example 1: Input - "Hello WORld" +- Uppercase letters: `H`, `W`, `O`, `R`, `L`. +- **Output**: 5. + +### Example 2: Input - "this is all lowercase" +- No uppercase letters. +- **Output**: 0. + +### Example 3: Input - "THIS IS ALL UPPERCASE" +- Uppercase letters: `T`, `H`, `I`, `S`, `I`, `S`, `A`, `L`, `L`, `U`, `P`, `P`, `E`, `R`, `C`, `A`, `S`, `E`. +- **Output**: 18. + +### Example 4: Input - "" +- An empty string. +- **Output**: 0. + +### Example 5: Input - null +- Input is null. +- **Output**: -1. + +### Testing the Solution + +Once the implementation was complete, I ran the test cases to ensure that all edge cases and normal scenarios were handled properly. All the tests passed successfully: +- **Input**: `"Hello WORld"` → **Output**: `5` +- **Input**: `"this is all lowercase"` → **Output**: `0` +- **Input**: `"THIS IS ALL UPPERCASE"` → **Output**: `18` +- **Input**: `""` → **Output**: `0` +- **Input**: `null` → **Output**: `-1` + +### Conclusion + +In this exercise, we learned how to count the number of uppercase letters in a string by iterating through it and using the `Character.isUpperCase()` method to detect uppercase characters. We also ensured proper handling of edge cases such as null and empty strings. + +--- + +## Solution Video For Coding Exercise - Does a String have Two Consecutive Characters? + +We'll walk through the solution for the coding exercise: **Does a String have two consecutive identical characters?** + +### Problem Overview + +Your task is to implement a method called `hasConsecutiveDuplicates` in the `StringMagic` class. This method will check if the input string contains two consecutive identical characters. The method should return `true` if such a pair exists and `false` otherwise. + +### Example: +- Input: `"Hello"` + - Output: `true` (because of the consecutive `LL`) +- Input: `"World"` + - Output: `false` +- Input: `""` (empty string) + - Output: `false` + +### Edge Cases: +- **Empty string**: Should return `false`. +- **Single character**: Should return `false`. +- **Multiple identical consecutive characters**: Should return `true`. + +### Approach + +### Step 1: Handle Edge Cases +We need to make sure we account for edge cases: +- If the string is `null`, we could handle it by returning `false` or `-1` depending on the situation. +- For an **empty string** or a **single character**, it is clear that there cannot be consecutive identical characters, so we return `false`. + +### Step 2: Loop Through the String +We'll iterate through the string using a loop and check pairs of characters: +- Compare the character at index `i` with the character at index `i + 1`. +- If they are identical, return `true`. +- If no such pair is found, return `false`. + +### Step 3: Prevent Index Out-of-Bounds Errors +Since we're checking the character at `i + 1`, we need to ensure that our loop doesn't go past the second-last character of the string. We'll loop only from `0` to `length - 2` to avoid out-of-bounds errors. + +### Code Implementation + +```java +public class StringMagic { + + // Method to check if a string has consecutive identical characters + public boolean hasConsecutiveDuplicates(String str) { + // Step 1: Handle edge cases for null or very short strings + if (str == null || str.length() < 2) { + return false; // Cannot have consecutive characters + } + + // Step 2: Loop through the string, comparing each character with the next + for (int i = 0; i < str.length() - 1; i++) { + // Get the current character and the next character + char currentChar = str.charAt(i); + char nextChar = str.charAt(i + 1); + + // Step 3: Check if consecutive characters are identical + if (currentChar == nextChar) { + return true; // Found consecutive identical characters + } + } + + // Step 4: If no consecutive duplicates are found, return false + return false; + } +} +``` + +### Explanation: + +1. **Edge Case Handling**: + - If the string is `null` or has a length less than `2`, there can be no consecutive identical characters, so we return `false` in these cases. + +2. **Looping Through the String**: + - We loop through the string, stopping at `str.length() - 2` to compare pairs of characters (`i` and `i + 1`). + - For each iteration, we compare the character at index `i` with the character at `i + 1`. + +3. **Return the Result**: + - If we find consecutive identical characters, we return `true`. + - If the loop completes without finding any, we return `false`. + +### Test Example + +### Example 1: Input - `"Hello"` +- Consecutive identical characters: `"LL"` +- **Output**: `true` + +### Example 2: Input - `"World"` +- No consecutive identical characters. +- **Output**: `false` + +### Example 3: Input - `""` (empty string) +- **Output**: `false` + +### Example 4: Input - `"A"` +- **Output**: `false` + +### Example 5: Input - `"AABBC"` +- Consecutive identical characters: `"AA"` and `"BB"`. +- **Output**: `true` + +### Testing the Solution + +Once the implementation was done, I ran the test cases to ensure that everything was handled correctly. Here are the results: +- **Input**: `"Hello"` → **Output**: `true` +- **Input**: `"World"` → **Output**: `false` +- **Input**: `""` → **Output**: `false` +- **Input**: `"A"` → **Output**: `false` +- **Input**: `"AABBC"` → **Output**: `true` + +All edge cases and normal cases were covered, and the implementation passed successfully. + +### Conclusion + +In this exercise, we learned how to check for consecutive identical characters in a string by looping through the string and comparing adjacent characters. We also handled edge cases like empty strings and single-character strings, where consecutive characters are impossible. + +--- + +## Solution Video For Coding Exercise - Rightmost Digit in a String + +In this video, we will solve the coding exercise **"Rightmost Digit in a String"**. Let's walk through the problem and the solution step by step. + +### Problem Overview + +Your task is to complete the method `getRightmostDigit` in the `StringMagic` class. This method should take a string as an argument and return the **rightmost digit** in the string. If the string contains no digits, the method should return `-1`. + +### Example: + +- **Input**: `"I bought 5 apples, 4 bananas, and 3 oranges"` + - **Output**: `3` (as `3` is the rightmost digit) + +- **Input**: `"No numbers here!"` + - **Output**: `-1` (since there are no digits) + +### Edge Cases: + +- **Empty string**: Should return `-1`. +- **String without digits**: Should return `-1`. + +### Tools: +We can utilize helpful methods from the `Character` class: +- `Character.isDigit(char c)`: This method checks if a character is a digit (0–9). +- `Character.getNumericValue(char c)`: This converts a digit character into its numeric value. + +### Plan + +1. **Edge Case Handling**: First, check if the string is `null` or empty. If it is, return `-1`. +2. **Loop Through the String**: We will scan the string **from right to left** so that the first digit we find will be the rightmost one. +3. **Check Each Character**: For each character in the string, check if it's a digit using `Character.isDigit`. Once we find the rightmost digit, return its numeric value using `Character.getNumericValue`. +4. **Return -1 if No Digits Found**: If the loop completes and no digit is found, return `-1`. + +### Code Implementation + +```java +public class StringMagic { + + public int getRightmostDigit(String str) { + // Step 1: Handle edge cases for null or empty string + if (str == null || str.isEmpty()) { + return -1; // Return -1 for null or empty strings + } + + // Step 2: Loop through the string from right to left + int length = str.length(); + for (int i = length - 1; i >= 0; i--) { + char ch = str.charAt(i); // Get the character at index i + + // Step 3: Check if the character is a digit + if (Character.isDigit(ch)) { + // Step 4: Return the numeric value of the digit + return Character.getNumericValue(ch); + } + } + + // Step 5: If no digit is found, return -1 + return -1; + } +} +``` + +### Explanation: + +1. **Edge Case Handling**: + - We check if the string is `null` or empty and return `-1` in these cases. + +2. **Looping Through the String**: + - We start at the last index (`length - 1`) and move towards the first character (`i >= 0`). + - For each character, we check if it is a digit using `Character.isDigit(ch)`. + +3. **Return the Rightmost Digit**: + - If we find a digit, we immediately return its numeric value using `Character.getNumericValue(ch)`. + +4. **Return -1 if No Digits Found**: + - If the loop completes and no digits are found, we return `-1`. + +### Test Cases + +### Example 1: +- **Input**: `"I bought 5 apples, 4 bananas, and 3 oranges"` +- **Output**: `3` (rightmost digit) + +### Example 2: +- **Input**: `"No numbers here!"` +- **Output**: `-1` (no digits) + +### Example 3: +- **Input**: `""` (empty string) +- **Output**: `-1` (empty string) + +### Example 4: +- **Input**: `"Number is 1000"` +- **Output**: `0` (rightmost digit is `0`) + +### Conclusion + +This exercise helped us to practice string manipulation and working with characters in Java. We used a simple technique to loop from the rightmost character to the left, identifying and returning the rightmost digit. If no digits were found, we returned `-1`. + +--- + +## Section 19: Java Coding Exercises - Set 6 + +## Solution Video For Coding Exercise - Is There a Greater Element + +Welcome back! In this video, we are going to solve the coding exercise **"Is There a Greater Element?"** Let's walk through the problem and the solution step by step. + +### Problem Overview + +You are tasked with completing the method `doesHaveElementGreaterThan()` in the `ArrayMagic` class. This method accepts an integer array and a number as inputs. Your goal is to check whether the array contains any element that is greater than the provided number. + +### Example: + +- **Input**: `array = {1, 2, 3, 4, 5}`, `number = 3` + - **Output**: `true` (since 4 and 5 are greater than 3) + +- **Input**: `array = {1, 2, 3}`, `number = 4` + - **Output**: `false` (since no element is greater than 4) + +### Edge Case: + +- If the array is empty, the method should return `false` because there are no elements in the array. + +### Plan + +1. **Edge Case Handling**: First, check if the array is empty (`length == 0`). If it is, return `false`. +2. **Loop Through the Array**: Traverse through each element in the array. +3. **Check If Any Element is Greater**: For each element, check if it is greater than the provided number. If you find such an element, return `true` immediately. +4. **Return False if No Greater Element Found**: If the loop completes and no element is greater than the number, return `false`. + +### Code Implementation + +```java +public class ArrayMagic { + + public boolean doesHaveElementGreaterThan(int[] array, int number) { + // Step 1: Edge case - if array is empty, return false + if (array.length == 0) { + return false; + } + + // Step 2: Loop through the array + for (int value : array) { + // Step 3: Check if any element is greater than the given number + if (value > number) { + return true; // Return true immediately if found + } + } + + // Step 4: If no element is greater than the number, return false + return false; + } +} +``` + +### Explanation: + +1. **Edge Case Handling**: + - We check if the array is empty (`array.length == 0`). If it is, we return `false` because no element exists that could be greater than the given number. + +2. **Loop Through the Array**: + - We use a **for-each** loop to iterate over each element of the array. + +3. **Check If Any Element is Greater**: + - For each element, we compare it with the given number. If we find any element that is greater, we immediately return `true`. + +4. **Return False if No Greater Element is Found**: + - If we finish looping through the entire array and find no element that is greater, we return `false`. + +### Test Cases + +### Example 1: +- **Input**: `array = {1, 2, 3, 4, 5}`, `number = 3` +- **Output**: `true` (since 4 and 5 are greater than 3) + +### Example 2: +- **Input**: `array = {1, 2, 3}`, `number = 4` +- **Output**: `false` (since no element is greater than 4) + +### Example 3: +- **Input**: `array = {}`, `number = 10` (empty array) +- **Output**: `false` + +### Example 4: +- **Input**: `array = {10, 9, 8}`, `number = 9` +- **Output**: `true` (since 10 is greater than 9) + +### Conclusion + +This was a simple but important exercise to practice looping through arrays and using conditionals. We learned how to handle edge cases such as an empty array, and how to terminate a loop early when a condition is satisfied (i.e., when we find an element greater than the given number). + +--- + +## Solution Video For Coding Exercise - Find Second Largest Element + +In this video, we'll solve the exercise **"Find Second Largest Element"**. Let's break down the problem and walk through the solution step by step. + +### Problem Overview + +You're tasked with completing the method `findSecondLargestElement()` in the `ArrayMagic` class. This method accepts an integer array as input and returns the **second largest element** from the array. If there are fewer than two distinct elements in the array, the method should return `-1`. + +### Example 1: + +- **Input**: `array = {9, 7, 9}` + - **Output**: `7` (The largest element is 9, but we want the second largest, which is 7) + +### Example 2: + +- **Input**: `array = {1, 1, 1, 1}` + - **Output**: `-1` (All elements are the same, so there's no second largest element) + +### Example 3: + +- **Input**: `array = {5}` + - **Output**: `-1` (There’s only one element, so no second largest element exists) + +### Plan + +1. **Edge Case Handling**: Check if the array has fewer than two elements. If it does, return `-1`. +2. **Find Largest and Second Largest**: + - Traverse through the array and keep track of both the largest and second largest elements. + - If a new largest element is found, update both the largest and second largest elements. + - If the current element is not the largest but is greater than the current second largest, update the second largest. +3. **Return Second Largest or `-1`**: If no valid second largest element is found, return `-1`. + +### Code Implementation + +```java +public class ArrayMagic { + + public int findSecondLargestElement(int[] array) { + // Step 1: Edge case - if array has fewer than two elements, return -1 + if (array.length < 2) { + return -1; + } + + // Step 2: Initialize variables for largest and second largest elements + int largest = Integer.MIN_VALUE; + int secondLargest = Integer.MIN_VALUE; + + // Step 3: Traverse the array + for (int value : array) { + // If we find a new largest element + if (value > largest) { + // Update second largest before largest + secondLargest = largest; + largest = value; + } + // If the current value is not equal to the largest but greater than second largest + else if (value > secondLargest && value != largest) { + secondLargest = value; + } + } + + // Step 4: If second largest is still MIN_VALUE, it means there was no valid second largest + return (secondLargest == Integer.MIN_VALUE) ? -1 : secondLargest; + } +} +``` + +### Explanation: + +1. **Edge Case Handling**: + - We check if the array has fewer than two elements (`array.length < 2`). If it does, return `-1` because it's impossible to have a second largest element. + +2. **Track Largest and Second Largest**: + - We initialize two variables, `largest` and `secondLargest`, to `Integer.MIN_VALUE`. This helps to ensure any number in the array will be larger than the initial values. + - As we loop through the array: + - If we encounter a number larger than the current `largest`, we update `secondLargest` to be the previous `largest`, then update `largest` to the current number. + - If the number is not the largest but is larger than `secondLargest` and different from `largest`, we update `secondLargest`. + +3. **Final Check**: + - After the loop, if `secondLargest` is still `Integer.MIN_VALUE`, it means we did not find a valid second largest element, so we return `-1`. Otherwise, we return the value of `secondLargest`. + +### Test Cases + +### Example 1: +- **Input**: `array = {9, 7, 9}` +- **Output**: `7` + +### Example 2: +- **Input**: `array = {1, 1, 1, 1}` +- **Output**: `-1` + +### Example 3: +- **Input**: `array = {5}` +- **Output**: `-1` + +### Example 4: +- **Input**: `array = {4, 6, 1, 2, 6}` +- **Output**: `4` (6 is the largest, so 4 is the second largest) + +### Conclusion + +This exercise involved finding the second largest element from an array, which required careful handling of edge cases and keeping track of two values simultaneously (largest and second largest). We ensured that if the array doesn’t have a second largest element, we return `-1`. + +--- + +## Solution Video For Coding Exercise - Are Sum of Arrays Equal + +In this video, we’ll be solving the exercise **"Are Sum of Arrays Equal?"**. In this task, you’re required to compare the sum of two integer arrays and determine if their sums are equal. + +### Problem Overview + +You are given two integer arrays, `array1` and `array2`, inside a class called `BiArray`. Your task is to implement a method that: + +1. Calculates the sum of each array. +2. Compares the sums and returns `true` if they are equal, or `false` otherwise. + +We also need to implement a helper method to calculate the sum of the elements in an array. + +### Example 1: + +- **Input**: + - `array1 = {1, 2}` + - `array2 = {4, -2, 1}` +- **Output**: `true` (Both arrays sum to 3) + +### Example 2: + +- **Input**: + - `array1 = {5, 10, 15}` + - `array2 = {1, 9, 20}` +- **Output**: `true` (Both arrays sum to 30) + +### Example 3: + +- **Input**: + - `array1 = {-1, -1, -1}` + - `array2 = {-2, 1}` +- **Output**: `false` (One sums to -3, the other to -1) + +### Plan + +1. **Helper Method**: Create a method `calculateSum()` that computes the sum of an array. + - Initialize a `sum` variable to zero. + - Use a **for-each loop** to iterate through each element of the array and add it to `sum`. + - Return the final value of `sum`. + +2. **Comparison Method**: Implement the method `areSumsEqual()`: + - Call `calculateSum()` for both arrays. + - Compare the sums and return `true` if they are equal, otherwise return `false`. + +### Code Implementation + +```java +public class BiArray { + + // Method to calculate the sum of elements in an array + public int calculateSum(int[] array) { + int sum = 0; // Initialize sum to zero + + // Use an enhanced for loop to sum all elements in the array + for (int element : array) { + sum += element; // Add each element to sum + } + + return sum; // Return the calculated sum + } + + // Method to compare sums of two arrays and check if they are equal + public boolean areSumsEqual(int[] array1, int[] array2) { + // Calculate the sum of both arrays using calculateSum() + int sum1 = calculateSum(array1); + int sum2 = calculateSum(array2); + + // Return true if the sums are equal, otherwise return false + return sum1 == sum2; + } +} +``` + +### Explanation: + +1. **`calculateSum()` Method**: + - We initialize `sum` to zero. + - We loop through each element of the array, adding it to `sum`. + - After processing all elements, we return the value of `sum`. + +2. **`areSumsEqual()` Method**: + - We call `calculateSum()` for both `array1` and `array2` to get their sums. + - We compare the two sums using `==` (equality operator). + - If the sums are equal, we return `true`. Otherwise, we return `false`. + +### Test Cases + +### Example 1: +- **Input**: `array1 = {1, 2}`, `array2 = {4, -2, 1}` +- **Output**: `true` (Both arrays sum to 3) + +### Example 2: +- **Input**: `array1 = {5, 10, 15}`, `array2 = {1, 9, 20}` +- **Output**: `true` (Both arrays sum to 30) + +### Example 3: +- **Input**: `array1 = {-1, -1, -1}`, `array2 = {-2, 1}` +- **Output**: `false` (Sums are -3 and -1, respectively) + +### Conclusion + +In this exercise, we successfully implemented a method to compare the sum of two arrays. By breaking down the problem into smaller pieces, we were able to: +- Create a helper method `calculateSum()` that focuses solely on calculating the sum of an array. +- Implement the `areSumsEqual()` method to compare the two sums and return whether they are equal. + +This approach ensures clean, readable code with well-defined responsibilities for each method. + +--- + +## Solution Video For Coding Exercise - Check if an Array is Sorted + +In this exercise, we’re going to solve the problem **“Check if an Array is Sorted.”** + +### Problem Overview + +You are given an incomplete Java method called `isSorted` inside a class called `ArrayMagic`. The method takes an array of integers as input and should return `true` if the array is sorted in ascending order, or `false` if it is not. + +### Example: + +- **Input**: `[1, 2, 3, 4]` + - **Output**: `true` (Array is sorted in ascending order) + +- **Input**: `[5, 4, 3, 2, 1]` + - **Output**: `false` (Array is sorted in descending order, not ascending) + +### Edge Cases: +- An empty array or an array with only one element is considered sorted, so the method should return `true` in those cases. +- The array may contain negative numbers, zero, or duplicate elements. + +### Plan + +We’ll break the problem down into the following steps: + +1. **Edge Case**: + - If the array length is 0 or 1, it’s already sorted. We return `true` immediately in these cases. + +2. **Loop through the Array**: + - For each element, compare it to the next element. + - If at any point, the next element is smaller than the current one, return `false` because the array is not sorted in ascending order. + - If we loop through all elements and don’t find any violations, return `true` since the array is sorted. + +### Code Implementation + +```java +public class ArrayMagic { + + // Method to check if the array is sorted in ascending order + public boolean isSorted(int[] array) { + // Edge case: If the array has 0 or 1 element, it's considered sorted + if (array.length <= 1) { + return true; + } + + // Loop through the array from the start to the second last element + for (int i = 0; i < array.length - 1; i++) { + // If the current element is greater than the next element, return false + if (array[i] > array[i + 1]) { + return false; + } + } + + // If we get through the entire array without finding a problem, it's sorted + return true; + } +} +``` + +### Explanation: + +1. **Edge Case**: + - If the array is empty or has just one element, it is trivially sorted. So, we return `true` for arrays with length 0 or 1. + +2. **Loop through the Array**: + - We use a traditional `for` loop starting from the first element to the second-to-last element (`array.length - 1`). + - At each iteration, we compare the current element (`array[i]`) with the next element (`array[i + 1]`). + - If we find any element where the next element is smaller than the current element, we return `false`. + - If no such pair is found, we return `true` at the end. + +### Test Cases + +### Example 1: +- **Input**: `[1, 2, 3, 4]` + - **Output**: `true` (Array is sorted) + +### Example 2: +- **Input**: `[5, 4, 3, 2, 1]` + - **Output**: `false` (Array is sorted in descending order) + +### Example 3: +- **Input**: `[1, 3, 2, 4]` + - **Output**: `false` (Array is not sorted) + +### Example 4: +- **Input**: `[-1, 0, 1, 2]` + - **Output**: `true` (Array with negative and positive numbers is sorted) + +### Example 5: +- **Input**: `[]` (Empty array) + - **Output**: `true` (Empty array is considered sorted) + +### Conclusion + +In this solution, we efficiently check if an array is sorted by comparing each element with its next neighbor. If any element is found to be greater than the next, we know the array is not sorted, and we can return `false` immediately. If we get through all the comparisons without issues, we return `true`. + +--- + +## Solution Video For Coding Exercise - Reverse an Array + +In this coding exercise, we’ll be solving the problem **“Reverse an Array.”** + +### Problem Overview + +You are required to complete a method called `reversedArray` inside a class `ArrayMagic`. This method takes an array as input and returns a new array where the elements are in reverse order. + +### Example: + +- **Input**: `[1, 2, 3, 4]` + - **Output**: `[4, 3, 2, 1]` + +- **Input**: `[5, -10, 15, -20]` + - **Output**: `[-20, 15, -10, 5]` + +### Edge Cases: +- If the input array is empty, return an empty array. +- If the input array contains one element, return that array as is (since it is already reversed). + +### Plan + +We’ll implement the solution by using the following steps: + +1. **Edge Cases**: + - If the array is empty or contains only one element, return the array as is. + +2. **Two-Pointer Approach**: + - We’ll use two pointers: one starting at the beginning of the array (`start`) and one at the end of the array (`end`). + - Swap the elements at the `start` and `end` positions. + - Increment the `start` pointer and decrement the `end` pointer, and continue swapping until `start` is greater than or equal to `end`. + +### Code Implementation + +```java +public class ArrayMagic { + + // Method to reverse the array + public int[] reversedArray(int[] array) { + // Edge case: if the array is empty or has one element, return it as is + if (array.length <= 1) { + return array; + } + + // Two pointers for the start and end of the array + int start = 0; + int end = array.length - 1; + + // Create a new array to hold the reversed elements + int[] reversedArray = new int[array.length]; + + // Loop through the array, swapping elements from the start and end + while (start <= end) { + // Swap the elements at start and end + reversedArray[start] = array[end]; + reversedArray[end] = array[start]; + // Move the pointers + start++; + end--; + } + + // Return the reversed array + return reversedArray; + } +} +``` + +### Explanation: + +1. **Edge Case Handling**: + - If the array has a length of `0` or `1`, we directly return the input array because it is either empty or already reversed. + +2. **Two-Pointer Technique**: + - We initialize two pointers: `start` at the beginning (`0`) and `end` at the last index (`array.length - 1`). + - In each iteration, we swap the elements at these positions and then move the `start` pointer to the right and the `end` pointer to the left. + - We stop when `start` exceeds `end`, which means the entire array has been reversed. + +3. **Swapping Elements**: + - As we go through the array, the first element is swapped with the last, the second element with the second-last, and so on, until the array is fully reversed. + +### Test Cases + +### Example 1: +- **Input**: `[1, 2, 3, 4]` + - **Output**: `[4, 3, 2, 1]` + +### Example 2: +- **Input**: `[5, -10, 15, -20]` + - **Output**: `[-20, 15, -10, 5]` + +### Example 3: +- **Input**: `[]` (Empty array) + - **Output**: `[]` (Empty array) + +### Example 4: +- **Input**: `[10]` + - **Output**: `[10]` (Single element remains unchanged) + +### Conclusion + +In this solution, we used the two-pointer technique to reverse an array efficiently. By swapping the elements from both ends and moving towards the center, we can reverse the array in `O(n)` time complexity where `n` is the length of the array. + +--- + +## Solution Video For Coding Exercise - Return Factors Of A Number in an ArrayList + +In this exercise, we’ll tackle the problem of **finding factors of a number** and returning them in an `ArrayList`. + +### Problem Overview + +You are tasked with completing a Java method that returns all the factors of a given integer in an `ArrayList`. The method is part of a class named `NumberMagic`. The factors of a number are defined as the numbers that divide the given number without leaving a remainder. The output must include both 1 and the number itself. + +### Example: +- **Input**: `6` + - **Output**: `[1, 2, 3, 6]` + +- **Input**: `12` + - **Output**: `[1, 2, 3, 4, 6, 12]` + +- **Input**: `15` + - **Output**: `[1, 3, 5, 15]` + +### Edge Cases: +- If the input number is `0` or negative, return an empty list. + +### Plan + +Here’s the step-by-step breakdown of the approach: + +1. **Edge Case Handling**: + - If the input number is `0` or less, return an empty `ArrayList` because factors do not apply in these cases. + +2. **Finding Factors**: + - Loop through all numbers starting from `1` up to the input number. + - Check if the current number divides the input number perfectly (i.e., no remainder). + - If it does, add it to the `ArrayList`. + +3. **Return Result**: + - After the loop, return the `ArrayList` containing all factors. + +### Code Implementation + +```java +import java.util.ArrayList; +import java.util.List; + +public class NumberMagic { + + // Method to return the factors of a number + public List determineFactors(int number) { + // Edge case: if the number is less than or equal to zero, return an empty list + List factors = new ArrayList<>(); + if (number <= 0) { + return factors; + } + + // Loop from 1 to the number itself to find all factors + for (int i = 1; i <= number; i++) { + // If the number is divisible by i, it's a factor + if (number % i == 0) { + factors.add(i); + } + } + + // Return the list of factors + return factors; + } +} +``` + +### Explanation: + +1. **Edge Case Handling**: + - We first check if the input number is less than or equal to zero. If true, we return an empty `ArrayList` as there are no valid factors for such numbers. + +2. **Finding Factors**: + - We use a `for` loop to iterate from `1` up to the input number. + - For each iteration, we check if the number is divisible by the current value of `i` (i.e., `number % i == 0`). + - If it divides evenly, we add `i` to the `factors` list. + +3. **Returning the List**: + - After collecting all factors, we return the `factors` list. + +### Test Cases + +### Example 1: +- **Input**: `6` + - **Output**: `[1, 2, 3, 6]` + - **Explanation**: The factors of 6 are 1, 2, 3, and 6. + +### Example 2: +- **Input**: `12` + - **Output**: `[1, 2, 3, 4, 6, 12]` + - **Explanation**: The factors of 12 are 1, 2, 3, 4, 6, and 12. + +### Example 3: +- **Input**: `0` + - **Output**: `[]` + - **Explanation**: Since 0 has no factors, we return an empty list. + +### Example 4: +- **Input**: `-5` + - **Output**: `[]` + - **Explanation**: Negative numbers do not have factors, so an empty list is returned. + +### Example 5: +- **Input**: `15` + - **Output**: `[1, 3, 5, 15]` + - **Explanation**: The factors of 15 are 1, 3, 5, and 15. + +### Conclusion + +In this solution, we implemented a method to find the factors of a number and return them in an `ArrayList`. By checking for edge cases and iterating through potential factors, we can efficiently solve this problem. + +--- + +## Solution Video For Coding Exercise - Return ArrayList with Multiples of a Number + +In this exercise, we’ll solve the problem of returning an `ArrayList` containing multiples of a given number up to a specified limit. + +### Problem Overview + +You are tasked with completing a method named `determineMultiples` inside the `NumberMagic` class. This method takes two inputs: +1. `number` - the number whose multiples you want to find. +2. `limit` - the upper bound, meaning the multiples should be less than this value. + +The goal is to return a list of multiples of the given number that are less than the limit. + +### Examples: +- **Input**: `number = 3`, `limit = 20` + - **Output**: `[3, 6, 9, 12, 15, 18]` + +- **Input**: `number = 5`, `limit = 1` + - **Output**: `[]` (No multiples of 5 are less than 1) + +### Edge Cases: +- If either the number or the limit is less than or equal to `0`, return an empty list. +- The multiples list should include all multiples of the number, but they must be less than the given limit. + +### Plan + +Here’s the breakdown of the approach: + +1. **Edge Case Handling**: + - If the `number` or `limit` is less than or equal to `0`, return an empty `ArrayList` since no valid multiples exist. + +2. **Generating Multiples**: + - Start from `1` and generate multiples of the `number` by multiplying it with a counter (`i`). + - Keep adding these multiples to the list until the multiple exceeds the `limit`. + +3. **Return Result**: + - Once all valid multiples are generated, return the `ArrayList`. + +### Code Implementation + +```java +import java.util.ArrayList; +import java.util.List; + +public class NumberMagic { + + // Method to return the multiples of a number less than a limit + public List determineMultiples(int number, int limit) { + // Create an empty list to store the multiples + List multiples = new ArrayList<>(); + + // Edge case: if the number or limit is less than or equal to 0, return an empty list + if (number <= 0 || limit <= 0) { + return multiples; + } + + // Loop to generate multiples of the number + for (int i = 1; number * i < limit; i++) { + multiples.add(number * i); // Add each valid multiple to the list + } + + // Return the list of multiples + return multiples; + } +} +``` + +### Explanation: + +1. **Edge Case Handling**: + - If either the `number` or `limit` is less than or equal to `0`, we return an empty `ArrayList` because no valid multiples exist in such cases. + +2. **Generating Multiples**: + - We use a `for` loop where `i` starts at `1` and increments by `1` on each iteration. We multiply `number * i` and check if the result is less than the `limit`. + - If the product is less than the `limit`, we add it to the `multiples` list. + - The loop continues until the product exceeds the `limit`. + +3. **Returning the List**: + - After generating all valid multiples, the `multiples` list is returned. + +### Test Cases + +### Example 1: +- **Input**: `number = 3`, `limit = 20` + - **Output**: `[3, 6, 9, 12, 15, 18]` + - **Explanation**: The multiples of 3 that are less than 20 are 3, 6, 9, 12, 15, and 18. + +### Example 2: +- **Input**: `number = 5`, `limit = 1` + - **Output**: `[]` + - **Explanation**: There are no multiples of 5 that are less than 1. + +### Example 3: +- **Input**: `number = 7`, `limit = 50` + - **Output**: `[7, 14, 21, 28, 35, 42, 49]` + - **Explanation**: The multiples of 7 less than 50 are 7, 14, 21, 28, 35, 42, and 49. + +### Example 4: +- **Input**: `number = 10`, `limit = 100` + - **Output**: `[10, 20, 30, 40, 50, 60, 70, 80, 90]` + - **Explanation**: The multiples of 10 less than 100 are 10, 20, 30, 40, 50, 60, 70, 80, and 90. + +### Example 5: +- **Input**: `number = -3`, `limit = 20` + - **Output**: `[]` + - **Explanation**: Since the number is negative, the output is an empty list. + +### Conclusion + +In this solution, we implemented a method that finds multiples of a number up to a given limit and returns them in an `ArrayList`. We handled edge cases like negative numbers and limits, and ensured that the correct multiples were included in the output list. + +--- + +## Section 21: Java Coding Exercises - Set 7 + +## Solution Video For Coding Exercise - Arithmetic Operations + +In this exercise, we’ll solve a simple problem that involves performing basic arithmetic operations using interfaces in Java. The goal is to implement addition, subtraction, and division operations using the `Operation` interface. + +### Problem Overview + +You are provided with an `Operation` interface that contains a method `perform(int x, int y)`, and your task is to create classes that implement this interface for the following operations: +1. **Addition**: Add two numbers and return the result. +2. **Subtraction**: Subtract the second number from the first and return the result. +3. **Division**: Divide the first number by the second, but handle the edge case where division by zero occurs. If the second number (`y`) is zero, return `-1`. + +### Edge Case: +- For the division operation, you need to check if the divisor (`y`) is zero. If it is, return `-1` instead of throwing an exception. + +### Approach + +1. **Operation Interface**: + - The `Operation` interface has an abstract method `perform(int x, int y)`. This will be implemented by the `Add`, `Subtract`, and `Divide` classes. + +2. **Add Class**: + - This class will implement the `perform` method and return the sum of `x` and `y`. + +3. **Subtract Class**: + - This class will implement the `perform` method and return the result of `x - y`. + +4. **Divide Class**: + - This class will implement the `perform` method. It will check if `y` is zero. If `y` is zero, return `-1`; otherwise, return `x / y`. + +### Code Implementation + +```java +// Define the Operation interface +interface Operation { + // Abstract method to perform the operation + int perform(int x, int y); +} + +// Implement the Add class +class Add implements Operation { + // Implement the perform method to add two numbers + public int perform(int x, int y) { + return x + y; + } +} + +// Implement the Subtract class +class Subtract implements Operation { + // Implement the perform method to subtract two numbers + public int perform(int x, int y) { + return x - y; + } +} + +// Implement the Divide class +class Divide implements Operation { + // Implement the perform method to divide two numbers + // Handle the edge case of division by zero + public int perform(int x, int y) { + if (y == 0) { + return -1; // Return -1 if trying to divide by zero + } + return x / y; + } +} +``` + +### Explanation: + +1. **Operation Interface**: + - The `Operation` interface defines an abstract method `perform(int x, int y)` that each operation class must implement. + +2. **Add Class**: + - This class implements the `Operation` interface and provides a concrete implementation for the `perform` method, which simply adds `x` and `y`. + +3. **Subtract Class**: + - This class also implements the `Operation` interface and provides the subtraction logic in the `perform` method. + +4. **Divide Class**: + - In this class, before performing the division, we check if the divisor `y` is zero. If it is, we return `-1` to handle division by zero. Otherwise, we return the result of `x / y`. + +### Example Walkthrough: + +1. **Addition Example**: + - **Input**: `Add.perform(5, 3)` + - **Output**: `8` + - **Explanation**: The `Add` class's `perform` method simply returns `5 + 3`, which is `8`. + +2. **Subtraction Example**: + - **Input**: `Subtract.perform(10, 4)` + - **Output**: `6` + - **Explanation**: The `Subtract` class's `perform` method returns `10 - 4`, which is `6`. + +3. **Division Example**: + - **Input**: `Divide.perform(10, 2)` + - **Output**: `5` + - **Explanation**: The `Divide` class checks if `y` is zero (it isn’t), so it performs the division `10 / 2` and returns `5`. + +4. **Division by Zero Example**: + - **Input**: `Divide.perform(10, 0)` + - **Output**: `-1` + - **Explanation**: Since `y` is `0`, the `Divide` class returns `-1` to handle the division by zero case. + +### Test Cases + +### Example 1: Addition +- **Input**: `Add.perform(7, 5)` + - **Output**: `12` + - **Explanation**: Adds `7 + 5`. + +### Example 2: Subtraction +- **Input**: `Subtract.perform(15, 8)` + - **Output**: `7` + - **Explanation**: Subtracts `15 - 8`. + +### Example 3: Division +- **Input**: `Divide.perform(20, 5)` + - **Output**: `4` + - **Explanation**: Divides `20 / 5`. + +### Example 4: Division by Zero +- **Input**: `Divide.perform(10, 0)` + - **Output**: `-1` + - **Explanation**: Handles division by zero by returning `-1`. + +### Conclusion + +In this exercise, we implemented three basic arithmetic operations: addition, subtraction, and division using an interface in Java. The division operation had an edge case where we handled division by zero by returning `-1`. This is a simple demonstration of how interfaces can be used to create flexible, reusable code for different mathematical operations. + +--- + +## Solution Video For Coding Exercise - Shapes and Area + +In this coding exercise, we will explore abstract classes and inheritance in Java. Specifically, we are tasked with creating subclasses for different shapes and implementing methods to calculate their area. + +### Problem Overview + +You are provided with an abstract class `Shape` that includes an abstract method `calculateArea()`. Your task is to create two subclasses, `Circle` and `Rectangle`, that extend `Shape`. Each subclass must implement the `calculateArea()` method to compute the area for that specific shape. The shapes must calculate their areas as follows: +- **Circle**: The area is calculated using the formula: \( \pi \times r^2 \), where `r` is the radius of the circle. +- **Rectangle**: The area is calculated using the formula: \( \text{length} \times \text{width} \). + +### Key Requirements: +1. **Circle Class**: + - A `Circle` must have a private `radius` attribute. + - It must implement the `calculateArea()` method, which uses the formula \( \pi \times r^2 \). +2. **Rectangle Class**: + - A `Rectangle` must have `length` and `width` attributes. + - It must implement the `calculateArea()` method using the formula \( \text{length} \times \text{width} \). +3. **Edge Cases**: + - The values for the radius, length, and width are always positive. You don’t need to handle negative or zero values. + +### Steps to Implement + +### 1. Abstract Class `Shape` +The `Shape` class is abstract, and it has an abstract method `calculateArea()` that each subclass must implement. + +```java +abstract class Shape { + private String name; + + public Shape(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public abstract double calculateArea(); +} +``` + +### 2. Circle Class +The `Circle` class extends `Shape` and implements the `calculateArea()` method using the formula \( \pi \times r^2 \). + +```java +class Circle extends Shape { + private double radius; + + public Circle(String name, double radius) { + super(name); // Call the superclass constructor to set the name + this.radius = radius; + } + + @Override + public double calculateArea() { + return Math.PI * radius * radius; + } + + public double getRadius() { + return radius; + } +} +``` + +- **Constructor**: The constructor takes a `name` and a `radius`, setting the name using the superclass's constructor (`super()`). +- **calculateArea()**: The area is calculated using \( \pi \times r^2 \) and returned. + +### 3. Rectangle Class +The `Rectangle` class extends `Shape` and implements the `calculateArea()` method using the formula \( \text{length} \times \text{width} \). + +```java +class Rectangle extends Shape { + private double length; + private double width; + + public Rectangle(String name, double length, double width) { + super(name); // Call the superclass constructor to set the name + this.length = length; + this.width = width; + } + + @Override + public double calculateArea() { + return length * width; + } + + public double getLength() { + return length; + } + + public double getWidth() { + return width; + } +} +``` + +- **Constructor**: The constructor accepts a `name`, `length`, and `width`, and initializes these values. +- **calculateArea()**: The area is calculated using \( \text{length} \times \text{width} \). + +### Test Cases + +### Example 1: Circle +- **Input**: `Circle("Circle A", 5)` +- **Expected Output**: Area is \( \pi \times 5^2 = 78.54 \) + +### Example 2: Rectangle +- **Input**: `Rectangle("Rectangle A", 10, 5)` +- **Expected Output**: Area is \( 10 \times 5 = 50 \) + +### Example 3: Circle with Large Radius +- **Input**: `Circle("Circle B", 10)` +- **Expected Output**: Area is \( \pi \times 10^2 = 314.16 \) + +### Example 4: Rectangle with Equal Length and Width +- **Input**: `Rectangle("Square A", 5, 5)` +- **Expected Output**: Area is \( 5 \times 5 = 25 \) + +### Conclusion + +In this exercise, we used abstract classes and inheritance to create specific shape classes like `Circle` and `Rectangle`. By extending the abstract `Shape` class, we were able to provide concrete implementations of the `calculateArea()` method for each shape. This approach allows us to define common behavior in the abstract class while delegating the implementation details to each subclass. + +--- + +## Section 23: Java Coding Exercises - Set 8 + +## Solution Video For Coding Exercise - Anagram Checker + +In this exercise, we are tasked with determining whether two strings are anagrams of each other. Let's dive into the details of how we solve this problem. + +### Problem Overview + +You are given two strings, `str1` and `str2`. Your task is to determine if these two strings are anagrams. + +### What is an Anagram? + +An anagram is a word or phrase formed by rearranging the letters of another word or phrase, using all the original letters exactly once. For example: +- "listen" is an anagram of "silent" +- "hello" is an anagram of "olelh" + +### Requirements: +1. The method should return **true** if `str1` and `str2` are anagrams. +2. The comparison should be **case insensitive**. +3. If either `str1` or `str2` is **null**, the method should return **false**. +4. If the lengths of the two strings are not the same, the method should return **false**. + +### Steps to Implement + +### 1. Edge Case Handling +We need to handle some edge cases upfront: +- If either `str1` or `str2` is **null**, return **false**. +- If the lengths of the two strings are not equal, return **false**. + +```java +if (str1 == null || str2 == null) { + return false; +} + +if (str1.length() != str2.length()) { + return false; +} +``` + +### 2. Convert Strings to Lowercase +Since we need to ignore the case, we should convert both strings to lowercase before further processing. This ensures that case differences do not affect the anagram comparison. + +```java +String lowercaseStr1 = str1.toLowerCase(); +String lowercaseStr2 = str2.toLowerCase(); +``` + +### 3. Convert Strings to Character Arrays +Once the strings are converted to lowercase, the next step is to break them down into character arrays. This allows us to manipulate and compare the characters easily. + +```java +char[] charArray1 = lowercaseStr1.toCharArray(); +char[] charArray2 = lowercaseStr2.toCharArray(); +``` + +### 4. Sort the Character Arrays +We can now sort both character arrays. If two strings are anagrams, sorting their characters will result in identical arrays. + +```java +Arrays.sort(charArray1); +Arrays.sort(charArray2); +``` + +### 5. Compare the Sorted Arrays +Finally, we use `Arrays.equals()` to compare the two sorted arrays. If they are equal, the strings are anagrams. + +```java +return Arrays.equals(charArray1, charArray2); +``` + +### Complete Solution + +Here is the complete implementation of the `areAnagrams` method: + +```java +public boolean areAnagrams(String str1, String str2) { + // Step 1: Handle null values and unequal lengths + if (str1 == null || str2 == null) { + return false; + } + + if (str1.length() != str2.length()) { + return false; + } + + // Step 2: Convert both strings to lowercase + String lowercaseStr1 = str1.toLowerCase(); + String lowercaseStr2 = str2.toLowerCase(); + + // Step 3: Convert strings to character arrays + char[] charArray1 = lowercaseStr1.toCharArray(); + char[] charArray2 = lowercaseStr2.toCharArray(); + + // Step 4: Sort the character arrays + Arrays.sort(charArray1); + Arrays.sort(charArray2); + + // Step 5: Compare the sorted arrays + return Arrays.equals(charArray1, charArray2); +} +``` + +### 6. Run Tests + +Let's run the tests to ensure everything is working as expected. The solution should pass various test cases, including: +- Anagrams with different letter cases. +- Anagrams with single characters. +- Strings of different lengths (which should return **false**). +- Null inputs (which should return **false**). + +When we run the tests, the solution should pass all of them successfully! + +### Conclusion + +In this exercise, we implemented a simple and efficient approach to check if two strings are anagrams by: +1. Handling edge cases (null values and unequal lengths). +2. Converting strings to lowercase for case-insensitive comparison. +3. Sorting the characters of both strings. +4. Comparing the sorted arrays to determine if the strings are anagrams. + +This approach efficiently solves the problem while being easy to understand and maintain. + +--- + +## Solution Video For Coding Exercise - Is Hexadecimal String? + +In this exercise, we will check whether a given string is a valid hexadecimal string. Let’s go through the steps needed to implement this. + +### Problem Overview + +You are given a class `MyString` with a string variable `str` and two methods: `isHexadecimalChar` and `isHexadecimal`. You need to complete these two methods to check if a character or a string is a valid hexadecimal. + +### What is a Hexadecimal String? +A string is considered a valid hexadecimal if it contains: +- Digits **0-9**. +- Letters **A-F** (uppercase or lowercase). + +So, the string can have both uppercase and lowercase characters, but no characters outside this range are allowed. For example: +- **"123F"** is a valid hexadecimal string. +- **"1G2H"** is **not** a valid hexadecimal string because it contains letters outside the A-F range. + +### Task Breakdown + +1. **isHexadecimalChar(char ch)**: This method should return true if the character is a valid hexadecimal character (`0-9`, `a-f`, `A-F`). +2. **isHexadecimal(String str)**: This method should return true if the entire string is a valid hexadecimal string, false otherwise. + +### Step-by-Step Solution + +### 1. Implementing `isHexadecimalChar` +The goal of this method is to check if a given character is either a digit or a valid hexadecimal letter (A-F or a-f). + +```java +public boolean isHexadecimalChar(char ch) { + return (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); +} +``` + +Here, we check if the character falls between 'a' and 'f' (lowercase) or 'A' and 'F' (uppercase). If it does, it’s a valid hexadecimal letter. + +### 2. Implementing `isHexadecimal` +In this method, we need to check whether the entire string is composed of valid hexadecimal characters. + +#### Step-by-step plan: +- Handle edge cases: If the string is null or empty, return false. +- Convert the string to a character array and iterate through each character. +- For each character, check if it is either a digit or a valid hexadecimal letter using `Character.isDigit` and `isHexadecimalChar`. +- If we encounter an invalid character, return false. +- If all characters are valid, return true. + +```java +public boolean isHexadecimal(String str) { + // Edge case: check for null or empty string + if (str == null || str.equals("")) { + return false; + } + + // Loop through the characters of the string + for (char ch : str.toCharArray()) { + // Check if it's neither a hexadecimal char nor a digit + if (!isHexadecimalChar(ch) && !Character.isDigit(ch)) { + return false; // Invalid character found + } + } + + return true; // All characters are valid +} +``` + +### Detailed Explanation: + +1. **Edge Case Handling**: + - We first check if the string is null or empty. If it is, the string is not valid, so we return false. + +2. **Iterate through the Characters**: + - We convert the string into a character array using `str.toCharArray()` and then use a `for-each` loop to iterate through each character. + +3. **Character Validation**: + - For each character, we check if it’s a valid hexadecimal character using `isHexadecimalChar`. + - We also check if the character is a digit using `Character.isDigit(ch)`. + +4. **Return the Result**: + - If any character is not a valid hexadecimal character or digit, we return false. + - If the loop completes without finding any invalid characters, we return true. + +### Full Code Solution: + +```java +public class MyString { + public boolean isHexadecimalChar(char ch) { + return (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); + } + + public boolean isHexadecimal(String str) { + // Edge case: null or empty string + if (str == null || str.equals("")) { + return false; + } + + // Check each character + for (char ch : str.toCharArray()) { + if (!isHexadecimalChar(ch) && !Character.isDigit(ch)) { + return false; // Invalid character found + } + } + + return true; // All characters are valid + } +} +``` + +### 3. Run Tests +Let’s now run the tests and ensure that everything works as expected. The solution should pass various test cases, including: +- Valid hexadecimal strings with uppercase and lowercase letters. +- Strings with invalid characters. +- Edge cases like null and empty strings. + +When we run the tests, all 16 test cases should pass successfully! + +### Conclusion + +In this exercise, we implemented a method to check whether a string is a valid hexadecimal string by: +1. Handling edge cases (null and empty strings). +2. Using `isHexadecimalChar` to check if each character is a valid hexadecimal character. +3. Using a loop to iterate through each character in the string and validate it. + +This solution is simple and efficient. + +--- + +## Solution Video For Coding Exercise - Word Reverser + +In this exercise, we are going to reverse the individual words in a sentence while maintaining the original order of the words. Let’s go step-by-step through the solution. + +### Problem Overview + +You need to write a method called `reverseWords` inside a `StringMagic` class. This method will take a sentence as input and return a string in which each word in the sentence is reversed, but the order of the words remains the same. + +### Example: +- Input: `"Hello world"` +- Output: `"olleH dlrow"` + +So, in this example: +- The word "Hello" is reversed to "olleH." +- The word "world" is reversed to "dlrow." +- The order of the words remains the same. + +### Edge Conditions: +- If the input is null, return `"Invalid"`. +- If the input is an empty string, return an empty string. + +### Step-by-Step Solution + +### 1. Handle Edge Cases + +The first step is to handle the edge cases where the input string is either `null` or empty: +- If the input is `null`, return `"Invalid"`. +- If the input is an empty string, return an empty string. + +### 2. Split the Sentence into Words + +To reverse each word, we need to split the sentence into individual words. We can use the `split()` method in Java with space (`" "`) as the delimiter. + +### 3. Reverse Each Word + +Once we have each word, we reverse it using `StringBuilder`. The `StringBuilder` class in Java has a built-in method `reverse()` that can reverse the sequence of characters in a string. + +### 4. Construct the Final Result + +After reversing each word, append it to a `StringBuilder` and add a space between words. At the end, you may have an extra space, which you can remove using the `trim()` method. + +### Full Code Solution + +```java +public class StringMagic { + + public String reverseWords(String sentence) { + // Step 1: Handle edge cases for null and empty string + if (sentence == null) { + return "Invalid"; + } + if (sentence.equals("")) { + return ""; + } + + // Step 2: Split the sentence into words + String[] words = sentence.split(" "); + StringBuilder reversedSentence = new StringBuilder(); + + // Step 3: Reverse each word and append it to the result + for (String word : words) { + StringBuilder reversedWord = new StringBuilder(word).reverse(); + reversedSentence.append(reversedWord).append(" "); + } + + // Step 4: Return the reversed sentence, trimming the extra space at the end + return reversedSentence.toString().trim(); + } +} +``` + +### Explanation: + +1. **Handling Edge Cases**: + - We check if the sentence is `null`, and if so, we return `"Invalid"`. + - If the sentence is an empty string, we return an empty string directly. + +2. **Splitting the Sentence**: + - We use `split(" ")` to split the sentence into words based on spaces. This creates an array of words. + +3. **Reversing Each Word**: + - We loop through each word in the array, reverse it using `StringBuilder.reverse()`, and append the reversed word to `reversedSentence`. + +4. **Trimming the Result**: + - Since we add a space after each word, the last word will also have a trailing space. We use `trim()` to remove the extra space at the end. + +### Running the Tests + +Now let’s run the tests and verify the output: +- For input `"Hello world"`, the output will be `"olleH dlrow"`. +- For input `"Java is fun"`, the output will be `"avaJ si nuf"`. +- For null input, it will return `"Invalid"`. +- For an empty string, it will return an empty string. + +All tests should pass successfully! + +### Conclusion + +In this exercise, we implemented a method to reverse the individual words of a sentence while keeping the word order intact. We used: +1. String splitting to break the sentence into words. +2. StringBuilder to reverse the characters of each word. +3. Proper handling of edge cases like null and empty strings. + +This approach is both simple and efficient. + +--- + +## Section 26: Java Coding Exercises - Set 9 + +## Solution Video For Coding Exercise - Filter Odd Numbers + +In this coding exercise, we will use functional programming in Java to filter out odd numbers from a list of integers. Let's dive into the details of this exercise and see how we can implement it using the **Java Stream API**. + +### Problem Overview + +You are given a list of integers, and your task is to filter out **only the odd numbers** from this list using the Java Stream API. The order of the numbers in the output list should be the same as the order in the input list. + +### Input: +- A list of integers that may contain positive, negative, and zero values. +- The list may also be empty. + +### Output: +- A list of integers containing only odd numbers from the input list, in the same order. + +### Example: +1. **Input:** `[1, 2, 3, 4, 5]` + **Output:** `[1, 3, 5]` + +2. **Input:** `[6, 7, 8, 9, 10]` + **Output:** `[7, 9]` + +3. **Input:** `[-3, -2, -1, 0, 1, 2, 3]` + **Output:** `[-3, -1, 1, 3]` + +### Approach + +We will make use of the **Java Stream API** to solve this problem. The steps are as follows: +1. Convert the input list into a stream. +2. Use a **filter** to keep only the odd numbers. +3. Collect the filtered numbers back into a list. + +### Edge Cases: +- If the input list is empty, return an empty list. +- Handle negative numbers and zero appropriately. + +### Step-by-Step Implementation + +### Step 1: Convert the List to a Stream +We start by converting the list of numbers into a stream using the `.stream()` method. + +### Step 2: Filter Odd Numbers +We use the `.filter()` method with a lambda expression to filter out only the odd numbers. We check if a number is odd using the modulus operator (`n % 2 != 0`). This works for both positive and negative numbers: +- An odd number will have a remainder that is not zero when divided by 2. + +### Step 3: Collect the Filtered Numbers +Finally, we use the `.collect()` method to collect the filtered odd numbers into a list using `Collectors.toList()`. + +### Full Code Implementation + +```java +import java.util.List; +import java.util.stream.Collectors; + +public class NumberMagic { + + public List filterOddNumbers(List numbers) { + // Convert the list to a stream, filter the odd numbers, collect them back into a list + return numbers.stream() + .filter(n -> n % 2 != 0) // Filtering odd numbers + .collect(Collectors.toList()); // Collecting the filtered stream back to a list + } +} +``` + +### Explanation: + +1. **Stream Conversion:** + `numbers.stream()` converts the list of integers into a stream. + +2. **Filter Condition:** + `.filter(n -> n % 2 != 0)` filters the stream, keeping only numbers where `n % 2` is not zero, i.e., odd numbers. + +3. **Collecting the Results:** + `.collect(Collectors.toList())` collects the filtered numbers into a new list and returns it. + +### Edge Case with Negative Numbers + +In the initial solution, we filtered numbers by checking if `n % 2 == 1`, but this condition failed for negative odd numbers (e.g., `-3 % 2` gives `-1` instead of `1`). By changing the condition to `n % 2 != 0`, we handle both positive and negative odd numbers correctly. + +### Running the Tests + +Let’s run some test cases: +- **Input:** `[1, 2, 3, 4, 5]` + **Output:** `[1, 3, 5]` + +- **Input:** `[-3, -2, -1, 0, 1, 2, 3]` + **Output:** `[-3, -1, 1, 3]` + +- **Input:** `[6, 7, 8, 9, 10]` + **Output:** `[7, 9]` + +All the test cases should pass successfully! + +### Conclusion + +In this exercise, we used **Java Streams** to filter out odd numbers from a list. We learned how to: +- Convert a list into a stream. +- Use the `.filter()` method with a lambda expression to filter out elements. +- Collect the filtered elements back into a list using `.collect(Collectors.toList())`. + +This approach is clean, simple, and leverages the power of functional programming in Java. + +--- + +## Solution Video For Coding Exercise - Get Cubes of First N Numbers + +In this task, we're going to generate the cubes of the first N natural numbers using Java Streams. Let’s go step by step and solve the problem. + +### Problem Overview + +You’re given an integer `N`, and your task is to generate a list of cubes of the first `N` natural numbers. For example: +- If `N = 5`, the output should be `[1, 8, 27, 64, 125]`. +- If `N = 3`, the output should be `[1, 8, 27]`. +- If `N = 0`, the output should be an empty list. + +### Input: +- A single integer `N`, where `N >= 0`. + +### Output: +- A list of integers representing the cubes of the first `N` natural numbers. + +### Example: +1. **Input:** `N = 5` + **Output:** `[1, 8, 27, 64, 125]` + +2. **Input:** `N = 3` + **Output:** `[1, 8, 27]` + +3. **Input:** `N = 0` + **Output:** `[]` + +### Approach + +We will utilize **Java Streams** and functional programming to solve this problem. The key steps are: +1. **Generate a sequence of numbers from 1 to N.** +2. **Map each number to its cube.** +3. **Convert the stream of cubes into a list.** + +### Key Functions: +- **IntStream.rangeClosed(1, N)**: Generates a sequence of integers from `1` to `N`. We use `rangeClosed(1, N)` to include both the start and the end points. +- **map(number -> number * number * number)**: Maps each number in the stream to its cube. +- **boxed()**: Converts an `IntStream` into a `Stream`, which is needed to collect the results into a list. +- **collect(Collectors.toList())**: Collects the stream into a list. + +### Step-by-Step Implementation + +### Step 1: Generate a Sequence of Numbers +We use `IntStream.rangeClosed(1, N)` to generate numbers from 1 to N. This ensures that we get the first N natural numbers. + +### Step 2: Map Each Number to Its Cube +We then use the `.map()` function to take each number and calculate its cube using the expression `number * number * number`. + +### Step 3: Collect the Cubes into a List +To convert the stream of cubes into a list, we use `.boxed()` followed by `.collect(Collectors.toList())`. + +### Full Code Implementation + +```java +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class FunctionalProgrammingMagic { + + public List getCubesOfFirstNNumbers(int N) { + // Generate a stream of numbers from 1 to N, map each to its cube, and collect into a list + return IntStream.rangeClosed(1, N) + .map(number -> number * number * number) // Cubing each number + .boxed() // Convert IntStream to Stream + .collect(Collectors.toList()); // Collect to List + } +} +``` + +### Explanation: + +1. **Stream Generation:** + `IntStream.rangeClosed(1, N)` generates a sequence of numbers from 1 to N. + +2. **Mapping to Cubes:** + `.map(number -> number * number * number)` computes the cube of each number. + +3. **Collecting the Result:** + `.boxed()` converts the `IntStream` into a `Stream`, and `.collect(Collectors.toList())` collects the cubes into a list. + +### Edge Case: +- If `N = 0`, `IntStream.rangeClosed(1, 0)` will result in an empty stream, so an empty list will be returned. + +### Running the Tests + +Let’s run the solution against some test cases: +- **Input:** `N = 5` + **Output:** `[1, 8, 27, 64, 125]` + +- **Input:** `N = 3` + **Output:** `[1, 8, 27]` + +- **Input:** `N = 0` + **Output:** `[]` + +All tests should pass successfully! + +### Conclusion + +In this exercise, we used functional programming in Java to solve the problem of generating cubes of the first N natural numbers. We learned how to: +- Use **IntStream** to generate sequences of numbers. +- Use the **map()** function to transform each number in the stream. +- Collect the transformed numbers into a list using **Collectors.toList()**. + +This approach is clean, efficient, and makes good use of Java's Stream API. + +--- + +## Solution Video For Coding Exercise - Length of Course Names + +Welcome back to another coding exercise solution! In this task, we are working on functional programming in Java, specifically focusing on getting the length of course names. + +### Problem Overview + +You need to complete a method called `getCourseNameCharacterCount` that takes in a list of course names and returns a list of integers representing the character count for each course name. + +### Input: +- A list of strings, where each string is a course name (e.g., "Math", "English"). +- The input can also be `null` or an empty list. + +### Output: +- A list of integers representing the length of each course name in the same order. +- If the input is `null` or empty, return an empty list. + +### Examples: + +1. **Input:** `["Math", "English", "History", "Physics"]` + **Output:** `[4, 7, 7, 7]` + Explanation: + - "Math" has 4 characters. + - "English" has 7 characters. + - "History" has 7 characters. + - "Physics" has 7 characters. + +2. **Input:** `[]` + **Output:** `[]` + +3. **Input:** `null` + **Output:** `[]` + +### Approach + +We'll break this down into a simple, step-by-step solution using **Java Streams**: +1. **Handle Edge Cases**: If the input list is `null`, we should return an empty list. +2. **Stream Processing**: + - Convert the list of course names into a stream. + - Use the `.map()` function to transform each course name into its length. + - Collect the transformed data back into a list. +3. **Return the Result**. + +### Key Functions: +- **courses.stream()**: Converts the list of course names into a stream for processing. +- **map(String::length)**: Transforms each course name into its length using a method reference. +- **collect(Collectors.toList())**: Collects the resulting stream into a list. + +### Full Code Implementation + +```java +import java.util.List; +import java.util.stream.Collectors; + +public class FunctionalProgrammingMagic { + + public List getCourseNameCharacterCount(List courses) { + // Edge case: If courses is null, return an empty list + if (courses == null) { + return List.of(); + } + + // Convert the list into a stream, map each course name to its length, and collect into a list + return courses.stream() + .map(String::length) // Map each course to its character count + .collect(Collectors.toList()); // Collect into a list + } +} +``` + +### Explanation: + +1. **Handle Edge Case for Null Input**: + We check if the input list is `null`. If it is, we return an empty list using `List.of()`. + +2. **Stream Processing**: + - `courses.stream()` converts the list into a stream. + - `.map(String::length)` applies a method reference that calculates the length of each course name. + - `.collect(Collectors.toList())` collects the results into a list of integers. + +### Edge Cases: +- **Null Input**: If `courses` is `null`, return an empty list. +- **Empty List**: If `courses` is an empty list, return an empty list. + +### Running the Tests + +Let’s test the solution with the provided examples: +1. **Input:** `["Math", "English", "History", "Physics"]` + **Output:** `[4, 7, 7, 7]` + +2. **Input:** `[]` + **Output:** `[]` + +3. **Input:** `null` + **Output:** `[]` + +All test cases should pass successfully! + +### Conclusion + +In this exercise, we demonstrated how to use Java's **Stream API** to process a list of strings and return a list of their lengths. This approach is clean, concise, and makes great use of functional programming techniques in Java. + +--- + +## Solution Video For Coding Exercise - Sum of Squares + +This exercise is about functional programming, where we’ll calculate the sum of squares of integers in a list using Java Streams. + +### Problem Overview + +You need to implement a function called `sumOfSquares` that takes a list of integers as input and returns the sum of the squares of these integers. + +### Key Considerations: +- If the input list is `null`, return `0`. +- If the input list is empty, return `0`. +- Each integer in the list should be squared, and then all the squares should be summed up. +- The result should be returned as a `long`. + +### Examples: + +1. **Input:** `[1, 2, 3]` + **Output:** `14` + Explanation: + \( 1^2 + 2^2 + 3^2 = 1 + 4 + 9 = 14 \) + +2. **Input:** `[]` + **Output:** `0` + +3. **Input:** `null` + **Output:** `0` + +### Approach + +We will break down the solution into the following steps: +1. **Handle Edge Cases**: If the input list is `null` or empty, return `0`. +2. **Use Java Streams**: + - Convert the list to a stream. + - Use the `mapToLong()` function to square each integer and ensure the result is a `long`. + - Use the `sum()` function to sum all the squared values. +3. **Return the Result**: The result should be a `long` value representing the sum of squares. + +### Key Functions: +- **numbers.stream()**: Converts the list of integers into a stream for processing. +- **mapToLong()**: Maps each integer to its square as a `long` value. +- **sum()**: Calculates the sum of the squared values in the stream. + +### Full Code Implementation + +```java +import java.util.List; + +public class FunctionalProgrammingMagic { + + public long sumOfSquares(List numbers) { + // Handle edge case: If the list is null, return 0 + if (numbers == null) { + return 0L; + } + + // Convert the list into a stream, map each number to its square, and sum the results + return numbers.stream() + .mapToLong(number -> (long) number * number) // Square each number + .sum(); // Sum the squares + } +} +``` + +### Explanation: + +1. **Edge Case for Null Input**: + If the `numbers` list is `null`, we return `0L` (long `0`). + +2. **Stream Processing**: + - `numbers.stream()` converts the list into a stream. + - `.mapToLong(number -> (long) number * number)` squares each number, making sure the result is a `long` to avoid overflow issues. + - `.sum()` sums all the squared values together. + +3. **Return Result**: The sum of squares is returned as a `long`. + +### Edge Cases: +- **Null Input**: If `numbers` is `null`, return `0`. +- **Empty List**: If `numbers` is an empty list, return `0`. + +### Running the Tests + +Let’s test the solution with the provided examples: +1. **Input:** `[1, 2, 3]` + **Output:** `14` + +2. **Input:** `[]` + **Output:** `0` + +3. **Input:** `null` + **Output:** `0` + +All tests should pass successfully! + +### Conclusion + +In this exercise, we used **Java Streams** to efficiently calculate the sum of squares of a list of integers. This approach is concise, uses functional programming techniques, and handles edge cases like `null` and empty input lists. + +--- + +## Solution Video For Coding Exercise - Find Max Even Number + +Welcome back to another coding exercise solution! In this exercise, we are tasked with finding the **maximum even number** from a list of integers using Java Streams. Let's break down the problem and how we can approach it. + +### Problem Overview + +You are given a list of integers, and your task is to complete the function `findMaxEvenNumber`, which returns the maximum even number from the list. However, if the list: +- Is `null` +- Is empty +- Contains only odd numbers + +In these cases, the function should return `0`. + +### Examples: +1. **Input:** `[3, 5, 12, 78, 13]` + **Output:** `78` + Explanation: 78 is the largest even number. + +2. **Input:** `[1, 3, 5]` + **Output:** `0` + Explanation: There are no even numbers in the list. + +3. **Input:** `[]` + **Output:** `0` + Explanation: The list is empty. + +4. **Input:** `null` + **Output:** `0` + Explanation: The list is null. + +### Approach + +We can solve this problem using Java Streams by following these steps: + +1. **Handle the Edge Case for `null` List**: If the list is `null`, immediately return `0`. +2. **Stream the List**: Use the `stream()` function to convert the list into a stream for further processing. +3. **Filter Even Numbers**: Use the `filter()` method to extract only the even numbers. +4. **Find the Maximum**: Use the `max()` method to find the largest even number. +5. **Handle the Optional Result**: Since there may not be any even numbers, the `max()` function returns an `Optional`. We can use the `orElse()` method to return `0` if no even numbers are found. + +### Code Implementation + +Here’s the code that implements the solution: + +```java +import java.util.List; +import java.util.Optional; + +public class FunctionalProgrammingMagic { + + public int findMaxEvenNumber(List numbers) { + // Edge case: if the list is null, return 0 + if (numbers == null) { + return 0; + } + + // Stream the list, filter even numbers, and find the maximum + Optional maxEven = numbers.stream() + .filter(number -> number % 2 == 0) // Filter only even numbers + .max(Integer::compare); // Find the maximum even number + + // Return the maximum even number, or 0 if no even numbers are found + return maxEven.orElse(0); + } +} +``` + +### Detailed Explanation: + +1. **Check for `null` Input**: + If the list `numbers` is `null`, we immediately return `0`. + +2. **Streaming and Filtering**: + - `numbers.stream()` converts the list into a stream. + - `.filter(number -> number % 2 == 0)` filters out all odd numbers, leaving only the even numbers. + +3. **Finding the Maximum**: + - `.max(Integer::compare)` finds the maximum even number by comparing the filtered even numbers. + +4. **Handling Optional Result**: + - The `max()` function returns an `Optional` because there might not be any even numbers in the list. + - `.orElse(0)` returns the value of the `Optional` if it exists; otherwise, it returns `0`. + +### Edge Cases: +- **Null List**: If the input list is `null`, return `0`. +- **Empty List**: If the input list is empty, return `0`. +- **All Odd Numbers**: If there are no even numbers in the list, return `0`. + +### Running the Tests + +Let’s test the solution with a few examples: + +1. **Input:** `[3, 5, 12, 78, 13]` + **Output:** `78` + +2. **Input:** `[1, 3, 5]` + **Output:** `0` + +3. **Input:** `[]` + **Output:** `0` + +4. **Input:** `null` + **Output:** `0` + +All test cases should pass successfully! + +### Conclusion + +In this exercise, we used **Java Streams** to filter and find the maximum even number from a list of integers. We made sure to handle cases where the input list could be `null`, empty, or contain only odd numbers. + +--- + +## Section 32: Java Coding Exercises - Set 10 + +## Solution Video For Coding Exercise - Enum Direction + +Welcome to another coding exercise solution! This time, we're working with **Enums** and implementing logic for **Direction** in Java. Let’s dive into the problem and break it down step-by-step. + +### Problem Overview + +In this task, you are given an enumeration called `Direction`, representing the four cardinal directions: +- **North** +- **South** +- **East** +- **West** + +The goal is to implement two methods: +1. **left()**: Returns the direction to the left of the current direction. +2. **right()**: Returns the direction to the right of the current direction. + +Enums are useful for representing a restricted set of values, such as directions, and they make it easier to work with constant values like these. + +### Example Behavior: +1. **Left of North** is **West**. +2. **Right of North** is **East**. +3. **Left of West** is **South**. +4. **Right of West** is **North**. + +### Approach + +We’ll implement the `left()` and `right()` methods for the `Direction` enum to correctly return the appropriate direction when turning left or right. + +### Enum Structure: +- **Enum Name:** `Direction` +- **Values:** `NORTH`, `SOUTH`, `EAST`, `WEST` +- **Methods:** + - `left()`: Returns the direction to the left. + - `right()`: Returns the direction to the right. + +### Key Concepts: +- **Enums:** Enums are great for representing a fixed set of constants, like cardinal directions. +- **Switch Statements:** We'll use switch statements to handle the different direction cases. +- **Circular Logic:** The direction sequence is circular, meaning that left of `NORTH` is `WEST`, and right of `WEST` is `NORTH`. + +### Enum Code Implementation: + +```java +public enum Direction { + NORTH("North"), + SOUTH("South"), + EAST("East"), + WEST("West"); + + private final String name; + + Direction(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + // Method to return the direction to the left + public Direction left() { + switch (this) { + case NORTH: + return WEST; + case WEST: + return SOUTH; + case SOUTH: + return EAST; + case EAST: + return NORTH; + default: + throw new IllegalArgumentException("Invalid Direction"); + } + } + + // Method to return the direction to the right + public Direction right() { + switch (this) { + case NORTH: + return EAST; + case EAST: + return SOUTH; + case SOUTH: + return WEST; + case WEST: + return NORTH; + default: + throw new IllegalArgumentException("Invalid Direction"); + } + } +} +``` + +### Breakdown of the Code: + +1. **Enum Values**: + We define four constants: `NORTH`, `SOUTH`, `EAST`, and `WEST`. Each has an associated `name` (for display purposes), which is passed via the constructor and stored in the `name` field. + +2. **left() Method**: + - This method determines which direction is to the left of the current direction. + - We use a `switch` statement to check the current direction and return the appropriate direction. + - For example, `left()` of `NORTH` is `WEST`, and `left()` of `WEST` is `SOUTH`. + +3. **right() Method**: + - This method determines which direction is to the right of the current direction. + - Similarly, we use a `switch` statement here. + - For example, `right()` of `NORTH` is `EAST`, and `right()` of `EAST` is `SOUTH`. + +4. **Error Handling**: + - We include a `default` case in both switch statements to throw an `IllegalArgumentException` in case an invalid direction is encountered (though this shouldn't happen with a fixed set of enum values). + +### Running the Tests + +Let's test the solution with a few examples: + +1. **Left of NORTH:** + - **Input:** `NORTH.left()` + - **Output:** `WEST` + +2. **Right of NORTH:** + - **Input:** `NORTH.right()` + - **Output:** `EAST` + +3. **Left of WEST:** + - **Input:** `WEST.left()` + - **Output:** `SOUTH` + +4. **Right of WEST:** + - **Input:** `WEST.right()` + - **Output:** `NORTH` + +All test cases should pass successfully! + +### Conclusion + +In this exercise, we implemented an **Enum** to represent cardinal directions and added methods to determine the direction to the left and right. This solution showcases the power of enums for representing fixed sets of constants and how we can implement custom logic in enum classes. + +--- + +## Solution Video For Coding Exercise - Enum Day Of The Week + +Welcome back to another solution video for a coding exercise! This time, we are working with **Enums** to handle the days of the week. Let's dive into how we can effectively implement methods in an Enum to solve this problem. + +### Problem Overview + +In this task, you are given an incomplete `DaysOfWeek` enum, representing all seven days of the week: +- **Monday** +- **Tuesday** +- **Wednesday** +- **Thursday** +- **Friday** +- **Saturday** +- **Sunday** + +The goal is to implement the following methods: + +1. **getName()**: Returns the name of the day. +2. **isWeekday()**: Returns true if the day is a weekday (Monday through Friday) and false otherwise. +3. **isHoliday()**: Returns true if the day is a holiday (Saturday and Sunday). + +### Example Behavior: +1. For **Tuesday**: + - `getName()` should return **"Tuesday"** + - `isWeekday()` should return **true** + - `isHoliday()` should return **false** + +2. For **Saturday**: + - `getName()` should return **"Saturday"** + - `isWeekday()` should return **false** + - `isHoliday()` should return **true** + +### Approach + +We'll implement these methods step-by-step using the enum structure, which allows us to represent a restricted set of constant values (the days of the week). Enums also allow us to associate custom behavior (methods) with each value. + +### Enum Code Implementation + +```java +public enum DaysOfWeek { + MONDAY("Monday"), + TUESDAY("Tuesday"), + WEDNESDAY("Wednesday"), + THURSDAY("Thursday"), + FRIDAY("Friday"), + SATURDAY("Saturday"), + SUNDAY("Sunday"); + + private final String name; + + // Constructor to initialize the day name + DaysOfWeek(String name) { + this.name = name; + } + + // Method to return the name of the day + public String getName() { + return this.name; + } + + // Method to check if the day is a weekday + public boolean isWeekday() { + return this != SATURDAY && this != SUNDAY; + } + + // Method to check if the day is a holiday + public boolean isHoliday() { + return !isWeekday(); + } +} +``` + +### Breakdown of the Code + +1. **Enum Values**: + We define all seven days of the week, each associated with a string name (e.g., `"Monday"`, `"Tuesday"`, etc.). + +2. **Constructor**: + The constructor takes the name of the day as an argument and assigns it to the `name` field. This allows each enum constant (day) to store its respective name. + +3. **getName() Method**: + - This method simply returns the `name` field, which holds the name of the day. + - For example, calling `TUESDAY.getName()` will return `"Tuesday"`. + +4. **isWeekday() Method**: + - This method checks if the current day is a weekday (Monday through Friday). + - If the day is not **Saturday** or **Sunday**, we return true (it's a weekday). Otherwise, we return false. + +5. **isHoliday() Method**: + - This method checks if the current day is a holiday. + - We simply return the opposite of `isWeekday()`. If it's not a weekday, then it's a holiday. + +### Alternative Approaches + +- **Using a `switch` statement**: + Instead of using conditional checks, we could use a switch statement for checking whether a day is a weekday or a holiday. For example: + + ```java + public boolean isWeekday() { + switch (this) { + case SATURDAY: + case SUNDAY: + return false; + default: + return true; + } + } + ``` + +- **Manual Conditions**: + Instead of checking for weekdays using a single condition (`this != SATURDAY && this != SUNDAY`), we could use multiple `if` statements or switch cases, but the current approach is cleaner and easier to maintain. + +### Running the Tests + +Let's test the solution with a few examples: + +1. **For Tuesday**: + - `getName()` returns **"Tuesday"** + - `isWeekday()` returns **true** + - `isHoliday()` returns **false** + +2. **For Saturday**: + - `getName()` returns **"Saturday"** + - `isWeekday()` returns **false** + - `isHoliday()` returns **true** + +All tests should pass successfully! + +### Conclusion + +In this exercise, we learned how to work with **Enums** in Java to represent a fixed set of values (days of the week) and associate custom methods to those values. By using Enums, we can create clean, organized code that handles specific scenarios with a predefined set of constants. + +--- + +> End of coding exercises! \ No newline at end of file diff --git a/java-new-features.md b/java-new-features.md new file mode 100644 index 00000000..0d5dce2a --- /dev/null +++ b/java-new-features.md @@ -0,0 +1,1907 @@ +# Section 34: Java New Features - Java 10 to Java 16 + +## Step 01 - Understanding Java Versions: A 10,000 Feet Overview + +Java has undergone numerous changes since its inception, with new releases now arriving every six months. + +In this step, we will cover the key Java versions, their release timelines, and the new approach to versioning that Oracle has adopted in recent years. + +This will provide a high-level understanding of Java’s evolution and the versioning system. + +### Early Java Versions + +The first version of Java was released as **JDK 1.0** in **January 1996**, marking the beginning of what would become one of the most widely used programming languages. + +Subsequent versions included JDK 2, 3, and 4. However, a major release came in **September 2004** with **J2SE 5.0**. + +### Key Milestones (1996 - 2004): + +- **JDK 1.0**: Released in January 1996. + +- **J2SE 5.0**: Released in September 2004. This marked the fifth release of Java in eight years. + +### Java SE 8 - A Landmark Release + +The most significant release, according to many, is **Java SE 8**, which was released in **March 2014**. This version brought **functional programming** to Java and introduced important features such as: + +- **Lambda Expressions** + +- **Streams API** + +- **Method References** + +These features made Java SE 8 a transformative release, enabling developers to write more expressive and functional-style code. + +Before Java SE 8, functional programming was not possible in Java. + +### Transition to Time-based Releases + +Starting with **Java SE 9** in **September 2017**, Oracle introduced a shift in the way new versions of Java were released. Between **2004** and **2017**, Java saw only four major releases, from **Java SE 5** to **Java SE 9**. However, this pace would soon change. + +From **Java SE 10** (released in **March 2018**), Oracle adopted a **time-based release versioning model**. + +This new approach ensures a **new release every six months**. Instead of waiting for specific features to be ready, each release includes whatever features are completed within the six-month timeframe. + +### Recent Java Versions (2018 - 2021) + +With this shift, Java has seen a dramatic increase in the number of releases. Some of the key releases are: + +- **Java SE 10**: Released in March 2018. + +- **Java SE 11**: Released in September 2018 (a **long-term support** or LTS release). + +- **Java SE 12**: Released in March 2019. + +- **Java SE 13**: Released in September 2019. + +- **Java SE 14**: Released in March 2020. + +- **Java SE 15**: Released in September 2020. + +- **Java SE 16**: Released in March 2021. + +In just three years (March 2018 to March 2021), there were six new Java releases. + +### Long-Term Support (LTS) Versions + +Oracle now offers **long-term support (LTS)** versions every three years. These LTS versions are recommended for use in production environments because they come with extended support and stability guarantees. + +- **Java SE 11** is the most recent LTS release. + +- The next LTS version will be **Java SE 17**. + +--- + +## Step 02 - Understanding Java New Features: An Overview + +Java has introduced numerous features across various versions, each bringing new capabilities that enhance the language. + +In this step, we'll review some of the most important features introduced in older and newer versions of Java, providing a broad overview of how the language has evolved. + +### Key Features from Earlier Releases + +### J2SE 5.0 (Released in 2004) + +**J2SE 5.0** is a significant release that introduced several important language features, including: + +- **Enhanced For Loop**: Simplifies iterating through collections. + +- **Generics**: Introduced type safety for collections and other types. + +- **Enums**: Added support for enumerated types. + +- **Autoboxing/Unboxing**: Automatic conversion between primitives and their corresponding wrapper classes. + +These features laid the foundation for modern Java programming. + +### Java SE 8 (Released in March 2014) + +**Java SE 8** is arguably the most important Java release to date because it introduced **functional programming** to the language, significantly changing how Java applications are written. Some key features include: + +- **Lambda Expressions**: Enable writing concise anonymous functions. + +- **Streams API**: Provide a powerful way to perform functional-style operations on collections of data. + +- **Method References**: Simplify the use of lambda expressions by referencing existing methods. + +- **Static Methods in Interfaces**: Allowed defining static methods within interfaces. + +Java SE 8 revolutionized the language by introducing these functional programming constructs, making code more concise, readable, and expressive. + +### Java SE 9 (Released in September 2017) + +**Java SE 9** introduced a significant architectural improvement to Java: + +- **Modularization**: The JDK was broken into smaller modules, allowing developers to create modularized applications. This improves both scalability and maintainability. + +We'll explore modularization in more depth in a later step. + +### Java SE 10 (Released in March 2018) + +**Java SE 10** brought the concept of **local variable type inference**: + +- **Local Variable Type Inference**: By using the `var` keyword, Java can infer the type of local variables. + +- This reduces the need for explicit type declarations, making code cleaner and less verbose, especially when dealing with complex types. + +### Java SE 14 (Released in March 2020) + +**Java SE 14** introduced **switch expressions**: + +- **Switch Expressions**: In addition to being used as a statement, switch can now be used as an expression, allowing you to return values from switch constructs directly. This results in cleaner and more functional code. + +We'll dive deeper into switch expressions in a later step. + +### Java SE 15 (Released in September 2020) + +**Java SE 15** introduced a new feature for working with multi-line strings: + +- **Text Blocks**: Allow you to write multi-line string literals in a more readable and maintainable way. + +- This is especially useful for strings that contain special characters, quotes, or span multiple lines. + +### Java SE 16 (Released in March 2021) + +**Java SE 16** introduced **record classes**, a new way to create data-carrying classes (also known as Java beans): + +- **Record Classes**: Provide a concise syntax for creating immutable data classes. With records, you no longer need to manually write getters, setters, constructors, `toString()`, `hashCode()`, and `equals()` methods. + +- Instead, you can define all of this with just a few lines of code. + +This greatly simplifies the creation of simple data-holding classes. + +### Performance Improvements Across Versions + +- Each new version of Java typically includes various performance improvements, especially in the area of **garbage collection**. + +- As programs create and discard objects, Java uses garbage collection algorithms to reclaim memory. + +- Across different Java versions, these algorithms have been continuously optimized for better performance and efficiency. + +--- + +## Step 03 - Getting Started with Java Modularization + +In this step, we will explore an important feature introduced in **Java 9**—**Java modularization**. + +Modularization brings several improvements, such as the ability to create modularized applications and the modularization of the JDK itself. + +This step will provide an overview of these concepts, focusing on how modularization can make Java programs more efficient, organized, and easier to manage. + +### Why Modularization? + +Before **Java 9**, the **JDK** came bundled in a large jar file known as **RT.jar** (Runtime Jar). + +Over time, as new features were added to Java, the size of RT.jar grew significantly, reaching over **60 MB** by Java 8. + +This jar contained all the classes and libraries needed for Java programs, regardless of whether an application needed them or not. + +- For example, if a program did not use any **SQL** features, it still had to carry around the **java.sql** library. + +- **Java 9** solved this issue by breaking the JDK into **modules**. + +### Modularizing the JDK + +In **Java 9**, the JDK was divided into multiple **modules**. + +A module is a self-contained unit of code that has a well-defined interface and clearly declared dependencies on other modules. + +This means that when building an application, you no longer need the entire JDK; you can choose only the modules your application needs. + +Let's explore this with an example. + +### Listing Available Modules + +To see the available modules in your current JDK version, use the following command: + +```bash +java --list-modules +``` + +This command lists all the modules in your JDK. For example, you will see: + +- **java.base**: The base module required for all Java programs. + +- **java.logging**: Contains logging functionality. + +- **java.sql**: Contains JDBC classes for database access. + +- **java.xml**: Provides XML processing functionality. + +You will also see **JDK-specific modules**, such as: + +- **jdk.compiler**: For compiling Java code. + +- **jdk.jshell**: For using the **JShell** tool. + +The JDK is now divided into these modules, allowing you to include only what is needed for your specific application, making it lighter and more efficient. + +### Modular Dependencies + +Modules often have dependencies on each other. For example: + +- **java.sql** depends on **java.base**. + +- **java.logging** might also depend on **java.base**. + +You can explore the dependencies of a module using this command: + +```bash +java -Djava.sql +``` + +This command will show that **java.sql** requires **java.base** as a dependency. + +### Exporting Packages + +Modules can specify which of their **packages** are available to other modules. + +For example, **java.sql** might export certain packages to make them accessible to other modules, but it can keep some internal packages hidden to improve encapsulation. + +In the next step, we will explore how to modularize a sample Java application, comparing the traditional approach with the new modular approach enabled by Java 9. + +--- + +## Step 04 - Java Modularization - 01 - Building Service and Consumer + +In this step, we will build a simple Java application without worrying about modularization or splitting it into different JAR files. + +Later, we will modularize it to demonstrate the benefits and differences modularization brings to the application. + +Our goal is to set up a basic sorting utility and a consumer to use it. + +### Step-by-Step Process + +### 1. Creating the Java Project + +1. **Create a New Java Project:** + + - Go to `File > New > Java Project`. + + - Name the project **modularization-1** and **combined** (everything combined in one place). + + - **Important:** Uncheck "Create module-info.java file" as we are not worrying about modularization yet. + + - Click **Finish**. + +### 2. Building the Sorting Utility + +Next, we will build a simple sorting utility that allows us to sort a list of names. + +2. **Create a New Class:** + + - Class Name: **MySortingUtil** + + - Package: `com.in28minutes.sorting.util` + + - The class will contain a method `sort()` that accepts a list of names and returns it sorted (for now, we return the list as-is). + + ```java + package com.in28minutes.sorting.util; + + import java.util.List; + + public class MySortingUtil { + public List sort(List names) { + // BubbleSort implementation goes here (for now, return names as-is) + BubbleSort bubbleSort = new BubbleSort(); + return bubbleSort.sort(names); + } + } + ``` + +3. **Create the BubbleSort Class:** + + - We will implement a simple **BubbleSort** class in a new package. + + ```java + package com.in28minutes.sorting.algorithm; + + import java.util.List; + + public class BubbleSort { + public List sort(List names) { + // Return names as-is for now + return names; + } + } + ``` + + - This class provides flexibility to switch to a different sorting algorithm later (e.g., QuickSort). + +### 3. Creating the Consumer + +Now, let's create a **consumer** class that will use the sorting utility. + +4. **Create a New Class:** + + - Class Name: **MySortingUtilConsumer** + + - Package: `com.in28minutes.consumer` + + - This class contains the `main()` method and uses the sorting utility to sort a list of names. + + ```java + package com.in28minutes.consumer; + + import com.in28minutes.sorting.util.MySortingUtil; + import java.util.List; + import java.util.logging.Logger; + + public class MySortingUtilConsumer { + private static final Logger logger = Logger.getLogger(MySortingUtilConsumer.class.getName()); + + public static void main(String[] args) { + MySortingUtil util = new MySortingUtil(); + List sorted = util.sort(List.of("Ranga", "Ravi", "Sathish", "Adam", "Eve")); + logger.info(sorted.toString()); + } + } + ``` + +### 4. Logging the Output + +- Instead of printing output using `System.out.println()`, we use **java.util.logging.Logger** to log the results of the sorted list. + +```java +private static final Logger logger = Logger.getLogger(MySortingUtilConsumer.class.getName()); +``` + +- The logger logs the sorted list: + +```java +logger.info(sorted.toString()); +``` + +### 5. Running the Application + +- **Run the Application**: + + - Right-click the project and select `Run As > Java Application`. + + - The console should display the following output (since we haven't implemented actual sorting yet, the list is returned as-is): + + ```java + Ranga, Ravi, Sathish, Adam, Eve + ``` + +In this step, we built the basic structure of the sorting utility and its consumer. + +The sorting utility uses a BubbleSort class, while the consumer sorts a list of names and logs the results. + +In the following steps, we will split this project into different JARs and explore the modularization process. + +--- + +## Step 05 - Java Modularization - 02 - Splitting Service and Consumer into JARs + +In this step, we continue setting up our problem in preparation for Java modularization. + +We'll demonstrate how to split a service and a consumer into separate JARs. + +The challenge here is that without proper modularization, consumers can bypass intended APIs and directly access underlying implementation classes (like sorting algorithms), which may not be desirable. We will explore how to address this problem. + +### Step-by-Step Process + +### 1. Scenario Setup + +Let’s assume we have two teams working on different parts of our project: + +- **Team 1:** Implements the sorting algorithms and utility (service). + +- **Team 2:** Implements the consumer that should use the sorting utility. + +However, if both the service and consumer exist in the same project, a consumer developer might bypass the sorting utility and directly use the sorting algorithm (e.g., `BubbleSort`). + +This is not the intended usage, as changes to the sorting utility might not propagate correctly. + +### 2. Demonstrating the Problem + +1. **Create a Direct Consumer:** + + - Copy the existing `MySortingUtilConsumer` class. + + - Create a new class called `DirectConsumer`, which uses the `BubbleSort` algorithm directly, bypassing the `MySortingUtil`. + + ```java + package com.in28minutes.consumer; + + import com.in28minutes.sorting.algorithm.BubbleSort; + import java.util.List; + import java.util.logging.Logger; + + public class DirectConsumer { + private static final Logger logger = Logger.getLogger(DirectConsumer.class.getName()); + + public static void main(String[] args) { + BubbleSort bubbleSort = new BubbleSort(); + List sorted = bubbleSort.sort(List.of("Ranga", "Ravi", "Sathish", "Adam", "Eve")); + logger.info(sorted.toString()); + } + } + ``` + + - **Problem:** The `DirectConsumer` class can access and use `BubbleSort` directly instead of using `MySortingUtil`. + + - If the sorting algorithm is updated in `MySortingUtil`, the `DirectConsumer` class will not benefit from the change. + +### Splitting into Separate JARs + +To address this issue, we will now split the project into two separate JARs: + +- **Service JAR:** Contains the sorting algorithms and utility. + +- **Consumer JAR:** Contains the consumers that use the service JAR. + +### 3. Creating the Service JAR Project + +1. **Create a New Java Project:** + + - Go to `File > New > Java Project`. + + - Name the project **modularization-2-service-jar**. + + - **Important:** Uncheck "Create module-info.java" as we are not yet implementing modularization. + + - Click **Finish**. + +2. **Move Sorting Classes to Service JAR:** + + - Move the `com.in28minutes.sorting.algorithm` and `com.in28minutes.sorting.util` packages to the **modularization-2-service-jar** project. + +### 4. Creating the Consumer JAR Project + +1. **Create a New Java Project:** + + - Go to `File > New > Java Project`. + + - Name the project **modularization-3-consumer-jar**. + + - Uncheck "Create module-info.java". + + - Click **Finish**. + +2. **Move Consumer Classes to Consumer JAR:** + + - Move the `com.in28minutes.consumer` package to the **modularization-3-consumer-jar** project. + +### 5. Configuring Dependencies Between JARs + +To allow the **consumer JAR** to access the classes in the **service JAR**, we need to add the service JAR to the classpath of the consumer JAR: + +1. **Add Service JAR to Consumer JAR's Classpath:** + + - Right-click the **modularization-3-consumer-jar** project and select **Properties**. + + - Go to **Java Build Path** > **Projects**. + + - Click **Add** and select **modularization-2-service-jar**. + + - Click **Apply and Close**. + + This will allow the consumer project to reference the sorting utility and algorithms from the service JAR. + +### 6. Running the Application + +Now that the projects are split into separate JARs, we can test them: + +1. **Run MySortingUtilConsumer:** + + - Right-click **MySortingUtilConsumer** and select `Run As > Java Application`. + + - You should see the following output in the console: + + ```java + [Ranga, Ravi, Sathish, Adam, Eve] + ``` + +2. **Run DirectConsumer:** + + - Similarly, right-click **DirectConsumer** and select `Run As > Java Application`. + + - You will see the same output, showing that the direct use of `BubbleSort` still works. + +In the next step, we will introduce modularization and see how it can help prevent the direct use of implementation classes like `BubbleSort`. + +--- + +## Step 06 - Java Modularization - 03 - Splitting Service and Consumer into Modules + +In this step, we take our service and consumer projects and split them into proper Java modules. + +We’ll explore the benefits modularization brings in terms of encapsulation and access control. + +Unlike the Classpath approach, Java modularization allows for fine-grained control over which parts of a module are exposed to other modules. + +### Step-by-Step Process + +### 1. Creating the Service Module + +1. **Create a New Java Project:** + + - Go to `File > New > Java Project`. + + - Name the project **modularization-4-service-module**. + + - Ensure **Create module-info.java** is checked. + + - Click **Finish**. + +2. **Define the Module Name:** + + - You will be prompted to name the module. Name it `com.in28minutes.service.provider`. + + - This creates a `module-info.java` file, which defines the module and its dependencies. + +3. **Understanding the module-info.java File:** + + - The `module-info.java` file defines the module's metadata, such as the module's name and the packages it exports to other modules. + +### 2. Creating the Consumer Module + +1. **Create Another New Java Project:** + + - Go to `File > New > Java Project`. + + - Name the project **modularization-5-consumer-module**. + + - Ensure **Create module-info.java** is checked. + + - Click **Finish**. + +2. **Define the Consumer Module Name:** + + - Name the module `com.in28minutes.consumer`. + + - This creates another `module-info.java` file for the consumer module. + +### 3. Moving Code to the Modules + +1. **Copy the Code for the Service:** + + - Copy the `com.in28minutes.sorting.algorithm` and `com.in28minutes.sorting.util` packages from the **modularization-2-service-jar** to **modularization-4-service-module**. + +2. **Copy the Code for the Consumer:** + + - Copy the `com.in28minutes.consumer` package from **modularization-3-consumer-jar** to **modularization-5-consumer-module**. + +### 4. Setting Up Dependencies Between Modules + +1. **Fix Compilation Errors:** + + - After copying the code, you'll notice compilation errors in the consumer module because it depends on the service module. + +2. **Declare the Service Module Dependency:** + + - In the consumer module’s `module-info.java` file, add the following line to specify the dependency: + + ```java + requires com.in28minutes.service.provider; + ``` + + - This tells the consumer module that it requires the service provider module to function. + +3. **Resolve the Module Dependency:** + + - Right-click on the **modularization-5-consumer-module** project and select **Properties**. + + - Go to **Java Build Path** > **Projects** > **Modulepath**. + + - Add **modularization-4-service-module** to the Modulepath. + + - Click **Apply and Close**. + + This resolves the compilation error in the consumer module as it now knows where to find the required service module. + +### 5. Handling External Dependencies (Logging) + +1. **Resolve Java Logging Dependency:** + + - The consumer module uses the `java.util.logging.Logger` class, which belongs to the `java.logging` module. + + - In the consumer module’s `module-info.java` file, add: + + ```java + requires java.logging; + ``` + +2. **Apply the Fix:** + + - This can be done manually, or you can use the Quick Fix feature in the IDE when it prompts you to add the required module. + +### 6. Controlling Access with Exports + +1. **Control Which Packages Are Exported:** + + - By default, the consumer module cannot access any classes from the service module unless they are explicitly exported. + + - In the **service module's** `module-info.java`, export only the `com.in28minutes.sorting.util` package: + + ```java + exports com.in28minutes.sorting.util; + ``` + +2. **Test the Changes:** + + - You will see that the `MySortingUtilConsumer` compiles and runs fine since it uses the exported `MySortingUtil` class. + + - However, `DirectConsumer` now fails to compile because it tries to access the `BubbleSort` class, which is in the `com.in28minutes.sorting.algorithm` package and is not exported. + +### 7. Additional Control Over Access + +1. **If You Want to Export More Packages:** + + - You can export the `com.in28minutes.sorting.algorithm` package as well by modifying the service module’s `module-info.java`: + + ```java + exports com.in28minutes.sorting.algorithm; + ``` + + - This will allow both the `MySortingUtilConsumer` and `DirectConsumer` to compile and run successfully. + +- Java modularization provides a much-needed level of encapsulation that is not available with the traditional Classpath approach. + +- By explicitly declaring which packages are exported, we can control what parts of a module are accessible to other modules. + +- This allows us to prevent unintended use of implementation classes (like `BubbleSort`) and ensure that consumers use the intended API (like `MySortingUtil`). + +In the next steps, we will explore more features of modularization and continue refining our understanding of how modules can enhance code organization and maintenance. + +--- + +## Step 07 - Java Modularization - 04 - A Quick Review + +In this step, let's quickly review some key concepts about Java modularization that we’ve covered so far. + +We'll revisit the module descriptor file (`module-info.java`), its components, and the benefits of modularization. + +### Key Concepts of Java Modularization + +### 1. **Module Descriptor (`module-info.java`)** + + - The `module-info.java` file defines metadata for the module. + + - It contains the essential declarations, such as: + + - **Requires**: Declares dependencies on other modules. + + - **Exports**: Specifies which packages are exposed to other modules. + +### 2. **Requires Statement** + + - The `requires` keyword specifies which modules your module depends on to work. + + - Example: + + ```java + requires java.logging; + requires com.in28minutes.service.provider; + ``` + + - In the **consumer module**, we specified that it requires `java.logging` (for logging purposes) and `com.in28minutes.service.provider` (for accessing the service module). + +### 3. **Transitive Requires** + + - You can use the `requires transitive` keyword to propagate module dependencies to consumers of your module. + + - Example: + + ```java + requires transitive java.logging; + ``` + + - If a module declares a transitive dependency, then any module that depends on this module will automatically have access to the transitive dependency (`java.logging` in this case). + +### 4. **Exports Statement** + + - The `exports` keyword is used to specify which packages can be accessed by other modules. + + - In the **service module**, we exported only the utility package: + + ```java + exports com.in28minutes.sorting.util; + ``` + + - This ensures that only the utility package can be accessed by other modules, while keeping other packages (like the algorithm package) hidden. + +### 5. **Opening Packages for Reflection** + + - Starting with Java 9, reflection access is controlled. + + - By default, reflection cannot access private types or members unless you explicitly allow it. + + - You can open specific packages to certain modules for reflection using the `opens` keyword: + + ```java + opens com.in28minutes.sorting.util to specific.module; + ``` + + - This restricts reflection only to the specified package and module. + +### Advantages of Java Modularization + +### 1. **Compile-Time Checks** + - Modularization provides **compile-time checks** for module dependencies. + + - If a required module is missing in the Modulepath, the compilation will fail, ensuring that all necessary modules are available. + +### 2. **Improved Encapsulation** + + - Modules allow for **better encapsulation** of code. + + - Unlike the Classpath approach, you can control which parts of your module are visible to other modules using `exports`. + + - Only classes and packages explicitly exported are accessible by other modules, helping maintain tighter control over your module’s internal structure. + +### 3. **Smaller Java Runtime** + + - With Java modularization, you can create a **smaller runtime** by choosing only the modules you need. + + - For example, if your program requires logging, you explicitly include `java.logging`. If not, it is excluded, leading to a more lightweight runtime. + +In this quick review, we looked at how the `module-info.java` file helps define dependencies and control access within modules. + +We also covered the benefits of modularization, such as compile-time checks, improved encapsulation, and the ability to create a smaller Java runtime. + +--- + +## Step 08 - Exploring New Java API - List, Set, and Map - copyOf Methods + +In this step, we will explore new methods introduced in Java 10 that allow us to create unmodifiable collections from existing ones. + +These methods—`copyOf`—are available in the `List`, `Set`, and `Map` interfaces. + +We'll see how these methods can help you create immutable collections easily, and when and why to use them. + +### Setting Up the Project + +1. **Create a New Java Project:** + + - Project Name: `JavaNewAPIFeatures` + + - Make sure to select the latest execution environment. + + - Uncheck the option to create `module-info.java`. + +2. **Create a New Class:** + + - Class Name: `CopyOfAPI` + + - Package: `com.in28minutes.api.a` + + - Add a `main` method to this class. + +### The `copyOf` Methods in Java 10+ + +### What is `copyOf`? + +The `copyOf` method is a utility added in Java 10 that allows you to create an **unmodifiable collection** from an existing collection. It's available for: + +- `List` + +- `Set` + +- `Map` + +**Key Features:** + +- The `copyOf` method creates an **unmodifiable** version of the collection passed to it. + +- The collection must not contain `null` values. + +- If the collection is already unmodifiable, `copyOf` will return the same collection, avoiding unnecessary copying. + +### Example - Creating Unmodifiable Collections + +### Using `List.copyOf` + +1. **Create a Modifiable List:** + + ```java + List names = new ArrayList<>(); + names.add("Ranga"); + names.add("Ravi"); + names.add("John"); + ``` + +2. **Pass List to a Method that Modifies It:** + + ```java + public static void doNotChangeNames(List names) { + names.add("Adam"); // Trying to modify the list + } + ``` + +3. **Without `copyOf` Method:** + + If we pass the list `names` directly, the method `doNotChangeNames` can modify it, which may not be desirable: + + ```java + doNotChangeNames(names); // This will modify the list + System.out.println(names); // Output: [Ranga, Ravi, John, Adam] + ``` + +4. **Using `List.copyOf` for Immutability:** + + To prevent changes to the list, we use `List.copyOf` to create an immutable copy: + + ```java + List copyOfNames = List.copyOf(names); + doNotChangeNames(copyOfNames); // This will throw an exception + ``` + + - Output: + + ``` + Exception in thread "main" java.lang.UnsupportedOperationException: Immutable collection + ``` + +### The `copyOf` Methods for `Set` and `Map` + +- **`Set.copyOf`** works the same way as `List.copyOf`, creating an unmodifiable `Set`. + +- **`Map.copyOf`** allows you to create an immutable `Map` from an existing one. + +### Benefits of `copyOf` + +1. **Immutability:** + - Ensures that no one can modify a collection after it is passed around, preserving data integrity. + +2. **Efficiency:** + - If the collection is already immutable, `copyOf` returns the same collection without creating a new copy. + +In this step, we explored the `copyOf` methods introduced in Java 10 for `List`, `Set`, and `Map`. + +These methods allow you to create immutable collections from modifiable ones, providing a simple way to enforce immutability in your code. + +This is especially useful when you want to protect collections from being modified after passing them to external methods. + +--- + +## Step 09 - Exploring New Java API - Files - `readString` and `writeString` Methods + +In this step, we'll explore two important file-handling methods introduced in **Java 11**: `Files.readString` and `Files.writeString`. + +These methods simplify the process of reading and writing string data to and from files. + +We'll go through examples of reading a file into a string, modifying its content, and writing the modified content back to a new file. + +### Setting Up the Project + +1. **Create a New Class:** + + - Class Name: `FileReadWriteRunner` + + - Package: `com.in28minutes.api.b` + + - Add a `main` method. + +2. **Create a Resource Folder and File:** + + - **Folder:** `resources` + + - **File:** `sample.txt` (with content: "sample line 2 line 3") + +### Using `Files.readString` to Read a File + +1. **Create a Path Object:** + + ```java + Path path = Paths.get("./resources/sample.txt"); + ``` + +2. **Use `Files.readString` to Read the File Content:** + + ```java + String fileContent = Files.readString(path); + ``` + +3. **Handle Exceptions:** + + Since file operations can throw an `IOException`, make sure to either catch the exception or add a `throws IOException` to your `main` method. + +4. **Print File Content:** + + ```java + System.out.println(fileContent); + ``` + +5. **Output:** + + ``` + sample + line two + line three + ``` + +### Modifying and Writing Content Using `Files.writeString` + +1. **Modify the Content:** + + Let's replace the word "line" with "lines": + + ```java + String newFileContent = fileContent.replace("line", "lines"); + ``` + +2. **Write the Modified Content to a New File:** + + ```java + Path newFilePath = Paths.get("./resources/sample-new.txt"); + Files.writeString(newFilePath, newFileContent); + ``` + +3. **Check the New File:** + + After running the program, a new file `sample-new.txt` should be created with the updated content: + + ``` + sample + lines two + lines three + ``` + +### Key Points about `readString` and `writeString` + +1. **`Files.readString`:** + + - Introduced in **Java 11**. + + - Allows reading the entire content of a file as a string. + + - Uses `UTF-8` encoding by default but can accept other encodings as an optional parameter. + +2. **`Files.writeString`:** + + - Also introduced in **Java 11**. + + - Makes writing a string to a file easy by specifying the target `Path` and the content string. + + - Can overwrite an existing file or create a new one if it doesn't exist. + +In this step, we explored two utility methods introduced in **JDK 11**: `Files.readString` and `Files.writeString`. + +These methods simplify file operations by allowing us to easily read from and write strings to files. + +They reduce boilerplate code and provide more straightforward handling of file I/O in Java. + +--- + +## Step 10 - Exploring New Java API - `Predicate.not` Method + +In this step, we will explore the `Predicate.not` method, introduced in **JDK 11**. + +This method allows you to easily negate a predicate, making your functional programming code more readable and concise. + +We will also compare this new method with the traditional approach of using the `negate` method. + +### Setting Up the Example + +1. **Create a New Class:** + + - Class Name: `PredicateNotRunner` + + - Package: `com.in28minutes.api.c` + + - Add a `main` method. + +2. **Create a List of Integers:** + + ```java + List numbers = List.of(3, 4, 7, 10, 88, 99); + ``` + +3. **Define a Predicate for Even Numbers:** + + ```java + Predicate evenNumberPredicate = number -> number % 2 == 0; + ``` + +4. **Filter Even Numbers Using the Predicate:** + + ```java + numbers.stream() + .filter(evenNumberPredicate) + .forEach(System.out::println); + ``` + + This will print the even numbers from the list. + +### Negating the Predicate + +1. **Using the `negate()` Method:** + + - To filter out the odd numbers, you can negate the predicate: + + ```java + numbers.stream() + .filter(evenNumberPredicate.negate()) + .forEach(System.out::println); + ``` + + - Output: + + ``` + 3 + 7 + 99 + ``` + +### Using `Predicate.not` Method + +1. **Define a Method Reference for Even Numbers:** + + ```java + public static boolean isEven(Integer number) { + return number % 2 == 0; + } + ``` + +2. **Filter Using a Method Reference:** + + ```java + numbers.stream() + .filter(PredicateNotRunner::isEven) + .forEach(System.out::println); + ``` + + This will print the even numbers: `4, 10, 88`. + +3. **Negating the Method Reference with `Predicate.not`:** + + - If you want to filter the odd numbers using a method reference, use the `Predicate.not` method: + + ```java + numbers.stream() + .filter(Predicate.not(PredicateNotRunner::isEven)) + .forEach(System.out::println); + ``` + + - Output: + + ``` + 3 + 7 + 99 + ``` + +### Key Points about `Predicate.not` + +1. **`Predicate.not`:** + + - Introduced in **Java 11**. + + - Simplifies the process of negating predicates, especially useful when working with method references. + + - More readable and concise compared to the traditional `negate()` method. + +2. **Usage with Method References:** + + - The `Predicate.not` method is particularly handy when you are using method references and need to negate the predicate. + +In this step, we explored the **`Predicate.not`** method introduced in **JDK 11**. + +This method helps negate predicates in a more readable way, especially when working with method references. + +It enhances the functional programming capabilities in Java by making it easier to work with conditions and filters. + +--- + +## Step 11 - Exploring New Java API - String Utility Methods + +In this step, we will explore several new **String API** methods introduced in recent versions of Java. + +These methods improve the way you handle strings and simplify common tasks such as checking for blank strings, trimming whitespace, splitting lines, transforming strings, and formatting them. + +We'll also take a look at the **helpful NullPointerException** messages introduced in JDK 14, which add more context to null pointer exceptions, making debugging easier. + +### 1. Checking for Blank Strings + +### **`isBlank()`** Method (Introduced in Java 11) + +- **Purpose**: Checks whether a string is blank (empty or contains only whitespace). + +```java +String str = " "; +System.out.println(str.isBlank()); // true +``` + +The `isBlank()` method will return `true` if the string is either empty or only contains white space characters. + +### 2. Trimming Strings + +### **`strip()`**, **`stripLeading()`**, and **`stripTrailing()`** Methods (Introduced in Java 11) + +- **Purpose**: Removes leading and/or trailing whitespaces. + +```java +String str = " left right "; +System.out.println(str.strip()); // "left right" +System.out.println(str.stripLeading()); // "left right " +System.out.println(str.stripTrailing()); // " left right" +``` + +- **`strip()`** removes leading and trailing whitespaces. + +- **`stripLeading()`** removes only leading whitespaces. + +- **`stripTrailing()`** removes only trailing whitespaces. + +### 3. Breaking String into Lines + +### **`lines()`** Method (Introduced in Java 11) + +- **Purpose**: Breaks a string into multiple lines (returns a `Stream`). + +```java +String multiLineString = "Line1\nLine2\nLine3"; +multiLineString.lines().forEach(System.out::println); +``` + +This will split the string by line terminators and print each line separately. + +### 4. String Transformation + +### **`transform()`** Method (Introduced in Java 12) + +- **Purpose**: Allows transforming a string by passing it to a function (lambda expression). + +```java +String str = "UPPERCASE"; +String result = str.transform(s -> s.substring(2)); +System.out.println(result); // "PERCASE" +``` + +The `transform()` method allows you to apply any function to the string, enabling flexible string manipulations. + +### 5. Formatting Strings + +### **`formatted()`** Method (Introduced in Java 13) + +- **Purpose**: Formats a string using placeholders, similar to `String.format()`. + +```java +String formattedStr = "My name is %s and I am %d years old.".formatted("Ranga", 25); +System.out.println(formattedStr); + +// Output: "My name is Ranga and I am 25 years old." +``` + +The `formatted()` method is an alternative to `String.format()` and simplifies formatting. + +### 6. Helpful NullPointerException Messages + +### **Enhanced NullPointerException** (Introduced in Java 14) + +- **Purpose**: Provides more context in NullPointerException messages, making it easier to debug. + +```java +String str = null; +str.isBlank(); // This will throw a NullPointerException with detailed message +``` + +- **Error Message Example**: + + ``` + Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.isBlank()" because "str" is null + ``` + +With Java 14+, this enhanced message will specify **what exactly** is null, providing more detailed context. + +These methods simplify common string manipulation tasks, making your code more concise and readable. + +We also saw how debugging has been made easier with enhanced null pointer exception messages. + +--- + +## Step 12 - Exploring Java New Features - Local Variable Type Inference + +In this step, we will explore an important feature introduced in **Java 10**, called **local variable type inference**. + +This feature allows the **Java compiler to infer the type of local variables**, reducing the need to explicitly declare types, especially when dealing with complex type declarations. + +We'll see how this feature simplifies variable declaration while maintaining type safety. The **`var`** keyword plays a key role in this feature. + +### 1. What is Local Variable Type Inference? + +Local variable type inference allows the compiler to infer the type of a local variable based on the initializer (the expression on the right-hand side of the assignment). + +For example: + +```java +// Without type inference: +List names = List.of("John", "Adam"); + +// With type inference (using var): +var names = List.of("John", "Adam"); +``` + +Here, **`var`** tells the compiler to infer the type from the assigned value (`List`). This reduces boilerplate code and can be especially useful when dealing with complex types. + +### 2. Example of Type Inference + +Let's take a more complex example of nested lists: + +```java +// List of List of Strings without type inference: +List> namesList = List.of(names1, names2); + +// With type inference: +var namesList = List.of(names1, names2); +``` + +Even though the type (`List>`) is complex, **`var`** allows the compiler to infer the correct type, making the code cleaner and easier to read. + +### 3. Type Safety with `var` + +Even though you use **`var`**, type safety is not compromised. The compiler still checks the types at **compile time**. + +For example: + +```java +var names = List.of("John", "Adam"); + +// You can still perform valid operations on the list: +names.stream().forEach(System.out::println); + +// If you attempt an invalid operation, you'll get a compile-time error: +names.streamOne(); // Error: streamOne() is not a valid method for List +``` + +The type is inferred based on the right-hand side, and any invalid operations will result in a compile-time error, ensuring type safety. + +### 4. Using `var` in Loops + +You can also use **`var`** in loops, simplifying variable declaration within loop constructs. + +### Example: + +```java +// Standard for-loop +for (var i = 0; i < 10; i++) { + System.out.println(i); +} + +// Enhanced for-loop with type inference: +for (var name : names) { + System.out.println(name); +} +``` + +In both examples, **`var`** allows the compiler to infer the type of the loop variables. + +### 5. Restrictions on `var` + +#### 1. **Cannot be assigned `null`**: + +You cannot assign `null` to a variable declared with **`var`**, because the compiler cannot infer the type from `null`. + +```java +var str = null; // Compile-time error: Cannot infer type for variable initialized to null +``` + +#### 2. **Not a keyword**: + +**`var`** is not a keyword in Java, which means you can still use **`var`** as an identifier for variable or method names (although this is discouraged). + +```java +var var = "This is valid, but not recommended."; +System.out.println(var); +``` + +### 6. Use `var` Wisely + +While **`var`** can simplify code, using it inappropriately can make code harder to understand. + +For example, if variable names are not descriptive enough, it becomes unclear what the inferred type is. + +#### Bad Example: + +```java +var x = List.of("John", "Adam"); // Not clear what `x` is +``` + +#### Good Example: + +```java +var namesList = List.of("John", "Adam"); // Clearer and descriptive variable name +``` + +### 7. Improving Readability with `var` + +Type inference is particularly helpful in improving readability in situations where you have **chained method calls** or **complex expressions**. + +#### Example: + +```java +var filteredNames = List.of("Ranga", "Ravi", "Adam") + .stream() + .filter(name -> name.length() < 5) + .collect(Collectors.toList()); + +filteredNames.forEach(System.out::println); +``` + +In this example, **`var`** improves readability by letting the developer focus on the logic rather than the exact type of the variable. + +### 8. `var` in Final Variables + +You can also declare **final** variables using **`var`**, but by default, **`var`** variables are **not final**. To make a **`var`** variable immutable, you need to explicitly declare it as **final**. + +```java +final var immutableNames = List.of("John", "Adam"); +``` + +In this step, we explored the **local variable type inference** feature introduced in Java 10, which allows the use of the **`var`** keyword for variable declarations. + +--- + +## Step 13 - Exploring Java New Features - Switch Expression + +In this step, we explore **Switch Expressions**, a feature introduced in **JDK 14**. + +While Java has long supported the traditional **Switch Statement**, the **Switch Expression** offers a more concise and flexible syntax that enhances readability and eliminates common issues such as fall-through behavior. + +**Switch Expression** was initially released as a preview feature in **JDK 12** and **JDK 13**, and it was finalized as a standard feature in **JDK 14**. + +### 1. Traditional Switch Statement + +Let's first revisit a traditional **Switch Statement**, where we map an integer (0-6) to the corresponding day of the week. + +#### Example: + +```java +public static String findDayOfWeek(int day) { + String dayOfWeek = ""; + + switch (day) { + case 0: + dayOfWeek = "Sunday"; + break; + case 1: + dayOfWeek = "Monday"; + break; + case 2: + dayOfWeek = "Tuesday"; + break; + case 3: + dayOfWeek = "Wednesday"; + break; + case 4: + dayOfWeek = "Thursday"; + break; + case 5: + dayOfWeek = "Friday"; + break; + case 6: + dayOfWeek = "Saturday"; + break; + default: + throw new IllegalArgumentException("Invalid day: " + day); + } + + return dayOfWeek; +} +``` + +### Key Observations: + +- **Break statements** are necessary to prevent **fall-through** behavior. + +- The code involves a lot of boilerplate with repetitive assignments. + +- If we forget a break, it can lead to subtle bugs where one case flows into another. + +### 2. Simplifying with Switch Expressions + +With **Switch Expressions**, we can eliminate these issues and write cleaner, more concise code. + +#### Example: + +```java +public static String findDayOfWeekWithSwitchExpression(int day) { + return switch (day) { + case 0 -> "Sunday"; + case 1 -> "Monday"; + case 2 -> "Tuesday"; + case 3 -> "Wednesday"; + case 4 -> "Thursday"; + case 5 -> "Friday"; + case 6 -> "Saturday"; + default -> throw new IllegalArgumentException("Invalid day: " + day); + }; +} +``` + +### Key Benefits: + +- **No break statements**: Each case returns a value using the `->` (lambda-style) syntax. + +- **No fall-through**: Each case is evaluated independently. + +- The **Switch Expression** is concise and avoids unnecessary local variables. + +- **Returns a value** directly, making the switch itself an expression, not just a statement. + +### 3. Handling Complex Logic with Switch Expressions + +Sometimes, the logic inside a case might be more complex, involving multiple statements. In this case, we can use **braces** to group the logic and return the final value using the **`yield`** keyword. + +### Example: + +```java +public static String findDayWithComplexLogic(int day) { + return switch (day) { + case 0 -> { + System.out.println("Executing complex logic for Sunday"); + yield "Sunday"; + } + case 1 -> "Monday"; + case 2 -> "Tuesday"; + default -> throw new IllegalArgumentException("Invalid day: " + day); + }; +} +``` + +### Key Features: + +- When using **braces** to handle complex logic, use **`yield`** to return the value. + +- No need for a **semicolon** after the switch expression in cases where braces are used. + +### 4. No Fall-Through in Switch Expressions + +One of the critical advantages of **Switch Expressions** is that **fall-through behavior is completely eliminated**. Each case is **mutually exclusive**, and there is no need for **break** statements. + +In the example below, there is no risk that evaluating one case will inadvertently flow into another: + +```java +return switch (day) { + case 0 -> "Sunday"; // Directly returns "Sunday" + case 1 -> "Monday"; // Directly returns "Monday" + // No risk of fall-through +}; +``` + +- This makes the code more predictable and prevents common errors associated with forgetting to include `break` statements. + +Switch Expressions provide a **simplified**, **concise**, and **safe** way to work with conditional logic in Java. + +By eliminating fall-through behavior and allowing **return values** directly from the switch, it makes code more readable and less error-prone. + +In this step, we explored how to transform traditional switch statements into switch expressions and looked at how **`yield`** can be used for more complex logic within switch cases. + +--- + +## Step 14 - Exploring Java New Features - Text Blocks + +In this step, we explore **Text Blocks**, a feature introduced in **JDK 15**. Text blocks provide a simpler way to work with multi-line strings in Java, improving readability and maintainability. + +Before text blocks, creating complex multi-line strings often involved using escape sequences, making the code harder to read and maintain. Text blocks simplify this by allowing multi-line strings to be written more naturally. + +Text blocks were introduced as a **preview feature** in **JDK 13** and **JDK 14**, and were made a standard feature in **JDK 15**. + +### 1. The Problem with Traditional String Handling + +When working with traditional string literals, especially multi-line strings or strings with special characters, the code can become cluttered with escape sequences (`\n`, `\"`, etc.). + +#### Example (Without Text Blocks): + +```java +System.out.println("\"First Line\"\nSecond Line\nThird Line"); +``` + +This approach is hard to read, as it uses escape sequences for quotes and newlines. + +### 2. Introduction to Text Blocks + +**Text Blocks** simplify working with multi-line strings. They allow you to define a string using three double quotes (`"""`), making it easier to write and read large blocks of text, such as JSON, HTML, or SQL. + +#### Example (With Text Blocks): + +```java +System.out.println(""" + "name": "John", + age: 30, + city: "New York""" + ); +``` + +#### Key Benefits: + +- No need for escape sequences for quotes. + +- Multi-line strings are easier to read and maintain. + +- Leading and trailing spaces are automatically handled. + +### 3. Creating Text Blocks + +Let's create a text block to see how it works in practice. + +```java +String textBlock = """ + Line 1 + Line 2 + Line 3 + """; +``` + +#### Key Points: + +- Text blocks start and end with three double quotes (`"""`). + +- The content inside the block is treated as-is, including newlines. + +- You can use `System.out.print` to print the content of the text block: + +```java +System.out.print(textBlock); +``` + +This will output: + +```java +Line 1 +Line 2 +Line 3 +``` + +### Removing Trailing Newlines: + +If you don’t want a newline at the end, place the closing quotes (`"""`) immediately after the last line: + +```java +String textBlock = """ + Line 1 + Line 2 + Line 3"""; +``` + +This removes the extra newline at the end. + +### 4. Handling Indentation + +Text blocks automatically handle indentation. The first non-whitespace character on each line is treated as the left margin, and any whitespace to the left of this margin is ignored for all lines. + +For example: + +```java +String indentedBlock = """ + Line 1 + Line 2 + Line 3 + """; +``` + +Even though each line is indented, the printed output will not contain this indentation. + +### Custom Line Indentation: + +If you want specific lines to be indented, simply add spaces or tabs to those lines: + +```java +String indentedBlock = """ + Line 1 + Line 2 (indented) + Line 3 + """; +``` + +Output: + +```java +Line 1 + Line 2 (indented) +Line 3 +``` + +### 5. Double Quotes Inside Text Blocks + +Text blocks also allow you to use double quotes without escaping them. For example: + +```java +String quoteExample = """ + He said, "Hello!" + """; +``` + +There is no need to escape the quotes. + +### 6. Text Blocks and String Operations + +You can use text blocks wherever you would use normal strings. This includes performing operations such as string formatting. + +### Example (Using `formatted` method): + +```java +String template = """ + Name: %s + Age: %d + """; +String formatted = template.formatted("John", 25); +System.out.print(formatted); +``` + +This will output: + +```java +Name: John +Age: 25 +``` + +#### Example (Combining with String Methods): + +You can also chain other string methods, such as `replace` or `toUpperCase`: + +```java +String block = """ + Hello, World! + """.toUpperCase(); +``` + +### 7. Restrictions and Best Practices + +- **Line Break Requirement**: After the opening three quotes (`"""`), there must be a line break. You cannot define a text block all on one line. + + **Invalid Example**: + ```java + String invalid = """Hello"""; + ``` + + **Valid Example**: + ```java + String valid = """ + Hello + """; + ``` + +- **Automatic Alignment**: If there is consistent leading whitespace in all lines, it is automatically removed. + +- **Trailing Whitespace**: Any trailing whitespace is also stripped. If you want to preserve trailing whitespace, it must be explicitly added. + +#### Best Practice: + +```java +String block = """ + Line 1 + Line 2 + Line 3 + """; +``` + +This formatting makes it clear that the string is a multi-line block. + +### 8. Text Blocks for Templates + +Text blocks can be particularly useful for creating templates such as HTML or SQL queries. + +### Example (HTML Template): + +```java +String htmlTemplate = """ + + + %s + + +

%s

+ + + """.formatted("My Page", "Welcome to My Page!"); +``` + +This makes it easy to create dynamic content by formatting the template with actual values. + +In this step, we explored how to create and work with text blocks, including handling formatting, indentation, and embedding values using `formatted`. + +--- + +## Step 15 - Exploring Java New Features - Records + +In this step, we explore **records**, a feature introduced in **JDK 14** as a preview and made a standard feature in **JDK 16**. + +Records are a special kind of Java class that eliminate the need for boilerplate code. They automatically generate: + +- **Constructors** + +- **Public accessor methods** (getters) + +- **equals()** + +- **hashCode()** + +- **toString()** + +Records are primarily used for classes that are simple data carriers, also known as **data transfer objects (DTOs)** or **POJOs**. + +### 1. Traditional Java Class: The Problem + +In traditional Java programming, creating a simple class with member variables often requires a lot of repetitive code. For example, a typical `Employee` class might look like this: + +```java +public class Employee { + private String name; + private String email; + private String phoneNumber; + + public Employee(String name, String email, String phoneNumber) { + this.name = name; + this.email = email; + this.phoneNumber = phoneNumber; + } + + public String getName() { return name; } + public String getEmail() { return email; } + public String getPhoneNumber() { return phoneNumber; } + + @Override + public String toString() { + return "Employee{name='" + name + "', email='" + email + "', phoneNumber='" + phoneNumber + "'}"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Employee)) return false; + Employee employee = (Employee) o; + return name.equals(employee.name) && + email.equals(employee.email) && + phoneNumber.equals(employee.phoneNumber); + } + + @Override + public int hashCode() { + return Objects.hash(name, email, phoneNumber); + } +} +``` + +This class defines fields, constructors, getters, `toString()`, `equals()`, and `hashCode()` methods. For each new class, we repeat this boilerplate code. + +### 2. Introducing Records + +**Records** eliminate this boilerplate by automatically generating constructors, getters, `toString()`, `equals()`, and `hashCode()`. + +#### Example: + +```java +public record Person(String name, String email, String phoneNumber) { } +``` + +This single line of code defines a class that: + +- Has three fields: `name`, `email`, and `phoneNumber` + +- Automatically provides: + + - A constructor + + - Getters (`name()`, `email()`, and `phoneNumber()`) + + - `toString()`, `equals()`, and `hashCode()` + +#### Creating a Record Instance: + +```java +Person person = new Person("Ranga", "ranga@in28minutes.com", "1234567890"); +System.out.println(person); +``` + +The output: +``` +Person[name=Ranga, email=ranga@in28minutes.com, phoneNumber=1234567890] +``` + +### 3. Accessor Methods + +Records automatically generate **public accessor methods** for each field. These methods are named after the field. + +#### Example: + +```java +System.out.println(person.name()); // Prints: Ranga +System.out.println(person.email()); // Prints: ranga@in28minutes.com +System.out.println(person.phoneNumber()); // Prints: 1234567890 +``` + +### 4. Equality and Hashcode + +Records automatically implement `equals()` and `hashCode()` based on all their fields. Two records are considered equal if all their fields are equal. + +### Example: + +```java +Person person1 = new Person("Ranga", "ranga@in28minutes.com", "1234567890"); +Person person2 = new Person("Ranga", "ranga@in28minutes.com", "1234567890"); + +System.out.println(person1.equals(person2)); // Prints: true +``` + +### 5. Custom Constructors and Validations + +You can also define custom constructors and validations inside records. + +#### Example (Custom Constructor with Validation): + +```java +public record Person(String name, String email, String phoneNumber) { + public Person { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("Name cannot be null or empty"); + } + } +} +``` + +Here, the constructor checks that the `name` is not null or empty. If the validation fails, an `IllegalArgumentException` is thrown. + +### Compact Constructors: +Java also allows **compact constructors** for records, where you don’t need to explicitly assign fields to `this`: + +```java +public record Person(String name, String email, String phoneNumber) { + public Person { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("Name cannot be null or empty"); + } + } +} +``` + +This compact constructor automatically assigns `name`, `email`, and `phoneNumber` without requiring explicit assignments like `this.name = name`. + +### 6. Restrictions in Records + +While records simplify a lot of work, they come with certain restrictions: + +- **No additional instance variables**: You cannot add additional fields other than the ones defined in the record header. + +- **No mutable fields**: Fields in records are final, which means records are immutable by default. + +- **Custom methods**: You can add additional methods, but you cannot add mutable fields or instance initializers. + +#### Allowed Example: + +```java +public record Person(String name, String email, String phoneNumber) { + public String uppercaseName() { + return name.toUpperCase(); + } +} +``` + +#### Not Allowed Example: + +```java +public record Person(String name, String email, String phoneNumber) { + private int age; // Not allowed +} +``` + +### 7. Static Fields and Methods in Records + +You **can** add static fields and methods to records. + +### Example: +```java +public record Person(String name, String email, String phoneNumber) { + public static String species = "Homo sapiens"; + + public static String getSpecies() { + return species; + } +} +``` + +### 8. Benefits of Records + +- **Less boilerplate**: Records automatically generate much of the repetitive code, making the class definition cleaner and easier to read. + +- **Immutable by default**: Records are inherently immutable, making them safe for concurrent programming. + +- **Well-defined equality**: The `equals()` and `hashCode()` methods are based on the fields, which makes comparisons straightforward. + +In this step, we explored **records**, a feature introduced in **JDK 16** that simplifies class creation by eliminating boilerplate code for constructors, getters, `toString()`, `equals()`, and `hashCode()`. + +--- diff --git a/java-tips.md b/java-tips.md new file mode 100644 index 00000000..93f4bdc7 --- /dev/null +++ b/java-tips.md @@ -0,0 +1,2025 @@ +# Section 31: Java Tips + +## Java Tip 01 - Imports and Static Imports + +In this tip, we revisited the concept of **imports** and explored the use of **static imports** in Java. + +We discussed how to import classes and packages, when imports happen automatically, and how to make your code cleaner and more concise using static imports. + +### 1. Default Imports in Java + +Some packages in Java are **imported by default**, meaning you do not need to manually import them. + +One such package is `java.lang`, which contains essential classes like `String`, `System`, and `Math`. + +#### Example: + +```java +String str = "Hello, World!"; +// No need to import java.lang.String; it's automatically available. +``` + +#### Key Point: + +- **`java.lang`** is imported automatically by the Java compiler. + +- No need to explicitly import classes from `java.lang`, such as `String` or `System`. + +### 2. Regular Imports + +For classes not part of `java.lang`, you need to explicitly **import** them. + +This ensures that your program has access to specific classes from other packages, such as `java.util`, `java.io`, etc. + +#### Example: + +```java +import java.math.BigDecimal; + +BigDecimal value = new BigDecimal("123.45"); +``` + +#### Best Practice: + +- **Avoid wildcard imports** (e.g., `import java.util.*`). Instead, import specific classes to improve readability and avoid unnecessary imports. + + ```java + import java.util.List; // Good + import java.util.*; // Not recommended + ``` + +### 3. Static Imports + +**Static imports** allow you to import static members (methods or variables) from a class, so you can access them directly without needing to reference the class name each time. + +### 3.1 Static Import of Variables + +A common use case is with `System.out`. Normally, you would write `System.out.println()`, but with static imports, you can simplify this to `out.println()`. + +#### Example: + +```java +import static java.lang.System.out; + +public class StaticImportExample { + public static void main(String[] args) { + out.println("Static Imports are useful!"); + } +} +``` + +### 3.2 Static Import of Methods + +You can also statically import methods, such as `Collections.sort()`, so you don’t need to reference the class name repeatedly. + +#### Example: + +```java +import static java.util.Collections.sort; +import java.util.ArrayList; +import java.util.List; + +public class StaticImportExample { + public static void main(String[] args) { + List numbers = new ArrayList<>(); + numbers.add(3); + numbers.add(1); + numbers.add(2); + + sort(numbers); // No need to write Collections.sort(numbers) + System.out.println(numbers); + } +} +``` + +#### When to Use Static Imports: + +- Use **static imports** when you are frequently calling static methods or accessing static variables in a class. + +- Avoid overusing static imports as they can reduce code clarity by hiding the class origin of methods and variables. + +--- + +## Java Tip 02 - Blocks + +In this tip, we explore **blocks** in Java, which are a fundamental part of controlling flow in programs. Blocks are used in structures like **if statements**, **loops**, and methods. + +In this lesson, we dive deeper into blocks, best practices for using them, and some tips on how variables behave within blocks. + +### What are Blocks? + +A **block** in Java is a section of code enclosed within curly braces `{}`. Blocks define a **scope** where variables and logic can be declared and executed. + +### Types of Blocks: + +- **Method Block**: Encloses the body of a method. + +- **Code Block**: A generic block of code enclosed by curly braces, which can be used anywhere. + +- **If Block / Loop Block**: A block used to define the statements executed within an `if`, `for`, `while`, or other conditional structures. + +### Example of Blocks + +### 1. **If Block** + +In conditional statements like `if`, a block is used to group the statements that will be executed if the condition is true. + +```java +if (3 > 2) { + System.out.println("3 > 2"); // This is an if block +} +``` + +### 2. **Else Block** + +An `else` block can be added after an `if` block to handle the false condition. + +```java +if (3 > 5) { + System.out.println("This won't be printed."); +} else { + System.out.println("This is printed because 3 is not greater than 5."); +} +``` + +### 3. **Best Practice for Blocks** + +It is considered **bad practice** to omit curly braces when defining blocks, even if the block contains only one statement. Not using braces can lead to errors or misunderstandings, especially when adding more code later. + +#### Example of Bad Practice: + +```java +if (3 > 2) + System.out.println("3 > 2"); + System.out.println("This is always printed, not part of the if block!"); // Misleading +``` + +#### Good Practice: + +```java +if (3 > 2) { + System.out.println("3 > 2"); + System.out.println("This is part of the if block."); +} +``` + +### Standalone Blocks + +Blocks do not always need to be associated with a control structure like `if` or `for`. You can create **standalone blocks** to limit the scope of variables, for example. + +```java +{ + int i = 10; + System.out.println("Value inside block: " + i); +} +// Outside the block, variable 'i' is not accessible +System.out.println(i); // This would cause a compilation error +``` + +#### Key Point: + +- Variables declared inside a block are **local** to that block and cannot be accessed outside of it. + +### Variable Scope in Blocks + +A variable declared inside a block is **limited to that block's scope**. Once you exit the block, the variable is no longer accessible. + +```java +{ + int x = 5; + System.out.println("x inside block: " + x); +} +// x is not accessible here +System.out.println(x); // Compilation error: x cannot be resolved to a variable +``` + +Always use curly braces `{}` to define blocks, even when writing simple one-line conditional statements, as it helps avoid mistakes and makes the code more maintainable. + +Understanding blocks and their scope is essential for writing clear and bug-free code. + +--- + +## Java Tip 03 - `equals()` Method + +In this tip, we explore the **`equals()` method** in Java, which is used to compare objects for equality. By default, the `equals()` method only checks if two objects refer to the same memory location (i.e., they are the same object). + +However, we can override this behavior to provide a more meaningful comparison, such as comparing object values (like IDs). In this tip, we will see how to override `equals()` in a custom class. + +### Default Behavior of `equals()` Method + +The default implementation of `equals()` is provided by the **`Object` class** in Java. It compares whether two references point to the **same object in memory**. + +#### Example: + +```java +Client c1 = new Client(1); +Client c2 = new Client(1); + +System.out.println(c1.equals(c2)); // Output: false +``` + +- Even though `c1` and `c2` have the same `id` (1), the default `equals()` method returns **false** because `c1` and `c2` refer to different objects in memory. + +- If you compare `c1.equals(c1)`, it would return **true** because both references point to the same object. + +#### Key Point: + +- The default `equals()` method compares **object references**, not object content. + +### Overriding `equals()` Method + +To compare the **content** of objects (such as comparing two `Client` objects based on their `id`), we need to **override** the `equals()` method. + +#### Example Class `Client`: + +```java +class Client { + private int id; + + public Client(int id) { + this.id = id; + } + + @Override + public boolean equals(Object that) { + if (this == that) return true; // If both references point to the same object + if (that == null) return false; // If the other object is null, return false + if (getClass() != that.getClass()) return false; // Ensure both objects are of the same class + + Client otherClient = (Client) that; // Cast the Object to Client + return this.id == otherClient.id; // Compare based on id + } +} +``` + +#### Explanation: + +- **`this == that`**: If both references point to the same object, return `true`. + +- **`that == null`**: If the other object is `null`, return `false`. + +- **`getClass() != that.getClass()`**: If the objects are of different classes, return `false`. + +- **Cast `Object` to `Client`**: Cast the object to the `Client` type for comparison. + +- **Compare `id` values**: If the `id` values of both `Client` objects are the same, return `true`. + +#### Example of Using Overridden `equals()`: + +```java +Client c1 = new Client(1); +Client c2 = new Client(1); + +System.out.println(c1.equals(c2)); // Output: true +``` + +- Now, `c1.equals(c2)` returns **true** because both `Client` objects have the same `id`. + +### Why Do We Also Generate `hashCode()`? + +- Whenever you override the `equals()` method, it is recommended to also override the **`hashCode()`** method. The `hashCode()` method ensures that objects that are considered equal (according to `equals()`) return the same hash code. + +- The **`hashCode()`** method plays an important role when objects are used in **hash-based collections** like `HashMap`, `HashSet`, etc. We will discuss the `hashCode()` method in detail in the next tip. + +By overriding `equals()`, you can provide more meaningful comparisons between objects, such as checking if two `Client` objects with the same `id` are considered equal. + +--- + +## Java Tip 04 - `hashCode()` Method + +In this tip, we explore the **`hashCode()` method** in Java and its importance, particularly when working with **hash-based collections** such as `HashMap` and `HashSet`. + +We also explain why `hashCode()` is usually implemented alongside the `equals()` method and the essential properties that a good `hashCode()` function must follow. + +### Why is `hashCode()` Important? + +The **`hashCode()` method** is crucial for the efficiency of **hash-based collections** such as `HashMap`, `HashSet`, and `Hashtable`. + +These collections use **buckets** to store objects, and an object's **hash code** determines which bucket it will be placed in. + +### How HashMap Works: + +1. A **hash function** (which uses the object's `hashCode()`) computes an integer value that helps decide the bucket where the object should be placed. + +2. The **goal** of a good `hashCode()` implementation is to **distribute objects evenly** across all buckets to avoid collisions and ensure efficient lookups. + +#### Example of `hashCode()` and `HashMap`: + +```java +Map clientMap = new HashMap<>(); +Client c1 = new Client(1); +Client c2 = new Client(1); + +clientMap.put(c1, "Client 1"); +clientMap.put(c2, "Client 2"); + +// If equals and hashCode are properly implemented, c1 and c2 will be treated as equal +System.out.println(clientMap.size()); // Output: 1 (if equals and hashCode are correctly implemented) +``` + +- In the example above, **c1** and **c2** have the same `id`. If `equals()` and `hashCode()` are correctly implemented, both objects should hash to the same bucket and be considered **equal**, so the map size remains 1. + +### Properties of a Good `hashCode()` Implementation + +To ensure correctness and efficiency in hash-based collections, the **`hashCode()` method** must follow these two key properties: + +### 1. **Consistent with `equals()`** + +- If two objects are **equal** according to the `equals()` method, then their **`hashCode()` values must also be equal**. + +### 2. **Stable `hashCode()` Value** + +- The **hash code** of an object should remain **consistent** as long as the object's state (used in `equals()`) does not change. + +- The **`hashCode()` value** should not change over time unless a field used in `equals()` is modified. + +#### Example of a `hashCode()` Implementation: + +```java +class Client { + private int id; + + public Client(int id) { + this.id = id; + } + + @Override + public boolean equals(Object that) { + if (this == that) return true; + if (that == null || getClass() != that.getClass()) return false; + Client client = (Client) that; + return id == client.id; + } + + @Override + public int hashCode() { + return Integer.hashCode(id); // hash code based on the 'id' + } +} +``` + +#### Key Points: + +- **`equals()` and `hashCode()` must work together**: If two objects are equal, they **must** have the same hash code. + +- A poor `hashCode()` implementation can lead to inefficient data storage and lookups in hash-based collections (e.g., all objects ending up in the same bucket). + +### Why `hashCode()` and `equals()` are Implemented Together + +In Java, **`hashCode()` and `equals()`** are often implemented together because they serve complementary roles in ensuring the correct behavior of collections like `HashMap` and `HashSet`. + +- **`equals()`**: Defines object equality based on content (e.g., `id`). + +- **`hashCode()`**: Determines the bucket where an object should be stored in hash-based collections. + +Java tools like Eclipse offer a combined option to generate both **`hashCode()` and `equals()`** at the same time to ensure consistency and correctness. + +--- + +## Java Tip 05 - Class Access Modifiers: `public` and `default` + +In this tip, we explore **class-level access modifiers** in Java. Access modifiers help control the visibility of classes, methods, and variables, promoting **encapsulation**. + +The primary focus here is on two access modifiers: **`public`** and **`default`** (also known as package-private), and their impact on class accessibility across different packages. + +### Access Modifiers Overview + +Java provides four access modifiers: + +- **`public`**: Accessible from anywhere. + +- **`protected`**: Limited to subclasses and the package (not applicable to classes). + +- **`default`** (no modifier): Accessible only within the same package. + +- **`private`**: Restricted to the enclosing class (not applicable to classes). + +In this tip, we focus on **class-level modifiers** and discuss the use of **`public`** and **`default`**. + +### 1. `public` Access Modifier + +When a class is marked as **`public`**, it is **accessible from anywhere**—including different packages. This is the most permissive access level. + +#### Example: + +```java +// In package1 +package com.in28minutes.tips.access.package1; + +public class ClassAccessModifiers { + // Class content here +} +``` + +#### Usage in Another Package: + +```java +// In package2 +package com.in28minutes.tips.access.package2; + +import com.in28minutes.tips.access.package1.ClassAccessModifiers; + +public class ClassAccessModifiersRunnerInOtherPackage { + public static void main(String[] args) { + ClassAccessModifiers c = new ClassAccessModifiers(); // Accessible since it is public + } +} +``` + +#### Key Point: + +- A **`public` class** can be accessed from **any package**. It allows other packages to create instances of this class or call its methods. + +### 2. `default` (Package-Private) Access Modifier + +When no access modifier is specified, the class is said to have **`default` access**, meaning it is only accessible **within the same package**. + +This is also known as **package-private** visibility. + +#### Example: + +```java +// In package1 +package com.in28minutes.tips.access.package1; + +class ClassAccessModifiers { + // No public modifier, so this class has default (package-private) access +} +``` + +#### Trying to Use `default` Class in Another Package: + +```java +// In package2 +package com.in28minutes.tips.access.package2; + +import com.in28minutes.tips.access.package1.ClassAccessModifiers; // Compilation Error + +public class ClassAccessModifiersRunnerInOtherPackage { + public static void main(String[] args) { + ClassAccessModifiers c = new ClassAccessModifiers(); // Not accessible outside package1 + } +} +``` + +#### Key Point: + +- A **`default` class** (without an access modifier) is **only accessible within the same package**. It **cannot** be accessed from outside the package. + +### Important Rules for Class-Level Access Modifiers + +1. **`public` and `default`** are the only access modifiers allowed on a class. + +2. **`protected`** and **`private`** cannot be applied to top-level classes. These modifiers are used for methods, fields, and inner classes but not for classes themselves. + +#### Example of Invalid Modifiers for Classes: + +```java +protected class MyClass { // Compilation Error: Cannot use protected with classes + // Class content here +} + +private class MyClass { // Compilation Error: Cannot use private with classes + // Class content here +} +``` + +Additionally, we learned that **`protected`** and **`private`** cannot be applied to top-level classes. + +The choice of access modifier depends on how much visibility you want to grant to other parts of your code. Encapsulation is a key principle, and selecting the right modifier helps control access to classes effectively. + +--- + +## Java Tip 06 - Method Access Modifiers: `public`, `protected`, `private`, and `default` + +In this tip, we explore **method-level access modifiers** in Java. Access modifiers control the visibility of methods within classes, packages, and subclasses, helping to enforce encapsulation. + +Java provides four main access modifiers for methods: **`public`**, **`protected`**, **`private`**, and **`default`** (package-private). We will discuss how these modifiers affect method accessibility from the **same class**, **same package**, **subclasses**, and **different packages**. + +### Overview of Method Access Modifiers + +### 1. **`public`** + +- A **`public` method** is accessible **everywhere**—within the same class, package, different packages, and even subclasses. + +### 2. **`protected`** + +- A **`protected` method** is accessible within the **same package** and **subclasses** (even if they are in different packages). + +### 3. **`private`** + +- A **`private` method** is accessible **only within the class** where it is defined. It cannot be accessed from outside the class, even by subclasses. + +### 4. **`default`** (package-private) + +- When no modifier is specified, a method has **`default`** (also called package-private) access. Such methods are accessible only within the **same package**. + +### Example: Method Access Modifiers + +We create a class `ExampleClass` with methods of different access modifiers: + +```java +package com.in28minutes.tips.access.package1; + +public class ExampleClass { + public void publicMethod() { + System.out.println("Public method"); + } + + protected void protectedMethod() { + System.out.println("Protected method"); + } + + void defaultMethod() { + System.out.println("Default method"); + } + + private void privateMethod() { + System.out.println("Private method"); + } +} +``` + +### 1. Access within the **same class** + +All methods—**public**, **protected**, **default**, and **private**—can be accessed within the same class. + +```java +public class ExampleClass { + public static void main(String[] args) { + ExampleClass example = new ExampleClass(); + example.publicMethod(); // Accessible + example.protectedMethod(); // Accessible + example.defaultMethod(); // Accessible + example.privateMethod(); // Accessible + } +} +``` + +### 2. Access within the **same package** + +In a different class within the same package, you can access **public**, **protected**, and **default** methods. However, **private** methods are not accessible. + +```java +package com.in28minutes.tips.access.package1; + +public class MethodAccessRunner { + public static void main(String[] args) { + ExampleClass example = new ExampleClass(); + example.publicMethod(); // Accessible + example.protectedMethod(); // Accessible + example.defaultMethod(); // Accessible + example.privateMethod(); // Not Accessible - Compilation Error + } +} +``` + +### 3. Access from a **different package** + +When accessing methods from a different package, only **public** methods are accessible unless the class is extended (for `protected` methods). + +```java +package com.in28minutes.tips.access.package2; + +import com.in28minutes.tips.access.package1.ExampleClass; + +public class MethodAccessRunnerInDifferentPackage { + public static void main(String[] args) { + ExampleClass example = new ExampleClass(); + example.publicMethod(); // Accessible + example.protectedMethod(); // Not Accessible - Compilation Error + example.defaultMethod(); // Not Accessible - Compilation Error + example.privateMethod(); // Not Accessible - Compilation Error + } +} +``` + +### 4. Access in a **subclass in a different package** + +In a subclass from a different package, only **public** and **protected** methods are accessible. + +```java +package com.in28minutes.tips.access.package2; + +import com.in28minutes.tips.access.package1.ExampleClass; + +public class SubClass extends ExampleClass { + public void testMethods() { + publicMethod(); // Accessible + protectedMethod(); // Accessible + defaultMethod(); // Not Accessible - Compilation Error + privateMethod(); // Not Accessible - Compilation Error + } +} +``` + +### Summary of Access Levels for Methods + +| Modifier | Same Class | Same Package | Subclass (Same Package) | Subclass (Different Package) | Different Package | +|-----------|------------|--------------|-------------------------|------------------------------|-------------------| +| `public` | Yes | Yes | Yes | Yes | Yes | +| `protected`| Yes | Yes | Yes | Yes | No | +| `default` | Yes | Yes | Yes | No | No | +| `private` | Yes | No | No | No | No | + +--- + +### Best Practices + +1. **Use `public`** when you want your method to be accessible from anywhere. +2. **Use `protected`** for methods that should only be accessible within the same package or subclasses. +3. **Use `private`** for methods that should only be accessible within the same class. +4. **Avoid `default`** unless package-level access is explicitly required. + +### Important Note: +- **Variables** follow the same access rules as methods, but it’s generally best practice to keep variables `private` and provide controlled access through methods. + +Choosing the right access modifier is crucial for **encapsulation** and helps maintain clear and organized code. Be mindful of how you expose methods in your classes and use the appropriate modifier to control access. + +--- + +# Java Tip 07 - Final Classes and Final Methods + +In this tip, we explore the **`final` non-access modifier** in Java. The `final` keyword can be applied to both **classes** and **methods**. + +When used, it prevents classes from being extended and methods from being overridden. In this tip, we will cover the purpose of `final` on both classes and methods, its impact on inheritance, and when you might want to use it. + +### 1. Final Classes + +A **`final class`** cannot be extended or subclassed. Once a class is marked as `final`, no other class can inherit from it. This is useful when you want to prevent modification or extension of the behavior of the class. + +#### Syntax: + +```java +final class FinalClass { + // Class content here +} +``` + +#### Example: + +```java +final class FinalClass { + // Some code here +} + +class SomeClass extends FinalClass { // Compilation error: Cannot subclass a final class + // This class will cause a compilation error +} +``` + +### Why Use Final Classes? + +Java provides several **final classes** to prevent modification and ensure that certain classes behave predictably. For example: +- **`String`** and **wrapper classes** like `Integer`, `Long`, etc., are marked as `final`. This ensures that no one can modify or extend these classes to alter their behavior, which is important for maintaining the integrity of core Java features like hashing and memory management. + +#### Example: String Class + +```java +// String is final, meaning it cannot be extended +final class String { + // Class content here +} +``` + +#### Key Point: +- A **final class** is used when you want to prevent extension and modification of a class's behavior. +- Examples include core Java classes like `String`, `Integer`, `Long`, etc. + +### 2. Final Methods + +A **`final method`** cannot be overridden by subclasses. If you want to prevent a method from being overridden in any subclass, you can declare it as `final`. + +### Syntax: + +```java +class SomeClass { + public final void doSomething() { + // Method content here + } +} +``` + +#### Example: + +```java +class SomeClass { + public final void doSomething() { + System.out.println("This method is final."); + } +} + +class ExtendingClass extends SomeClass { + @Override + public void doSomething() { // Compilation error: Cannot override a final method + // This will cause a compilation error + } +} +``` + +### Why Use Final Methods? + +You might use `final` on a method when you want to **prevent subclasses from changing the implementation** of that method. This ensures that the method behaves consistently across all subclasses and prevents any potential errors that might occur due to overriding. + +#### Example: Enforcing a Method's Logic + +Consider a scenario where you have a template method that defines a specific sequence of actions, and you don't want subclasses to modify that sequence: + +```java +class Recipe { + public final void execute() { + getReady(); + doTheDish(); + cleanup(); + } + + void getReady() { /* Subclass can implement */ } + void doTheDish() { /* Subclass can implement */ } + void cleanup() { /* Subclass can implement */ } +} +``` + +In this example, the `execute()` method is **final** because you don't want subclasses to change the order of the steps in the recipe, while allowing subclasses to define how each step is implemented. + +Use the `final` keyword when you want to **protect the integrity** of a class or method by preventing inheritance or modification. This is especially important in cases where modifying behavior could lead to errors or inconsistencies in the system. + +--- + +## Java Tip 08 - Final Variables and Final Arguments + +In this tip, we explore the concept of **`final` variables** and **`final` arguments** in Java. + +The `final` keyword can be applied to variables and method arguments to ensure that their values can only be assigned once, making them **immutable**. This practice promotes better coding standards and helps in writing more predictable and maintainable code. + +### 1. Final Variables + +A **`final` variable** is a variable that can only be assigned a value **once**. Once a value has been assigned, it cannot be changed throughout the program. This makes the variable **immutable** after its initial assignment. + +#### Syntax: + +```java +final int i = 5; +``` + +#### Example: + +```java +public class FinalVariablesExample { + public static void main(String[] args) { + final int i = 5; // i is assigned the value 5 + i = 7; // Compilation Error: Cannot assign a value to final variable i + } +} +``` + +- **Without `final`**: A regular variable's value can be changed multiple times. + +- **With `final`**: The variable's value can only be assigned once. Any attempt to change it results in a **compilation error**. + +#### Key Point: + +- A `final` variable **must** be initialized either at the time of declaration or later in the constructor, but it can only be assigned **once**. + +### 2. Final Arguments + +A **`final` argument** is a method parameter that cannot be modified inside the method body. Once a method is called, the argument’s value is set and cannot be changed. + +#### Syntax: + +```java +public void doSomething(final int arg) { + // arg is a final argument and cannot be modified +} +``` + +#### Example: + +```java +public class FinalArgumentsExample { + public void doSomething(final int arg) { + arg = 10; // Compilation Error: Cannot assign a value to final parameter arg + } +} +``` + +- **Without `final`**: You can modify the argument inside the method body, although this is generally not considered a good practice. + +- **With `final`**: The argument becomes **immutable** and cannot be reassigned a new value within the method. + +#### Key Point: +- Making method arguments `final` ensures that they **remain unchanged** throughout the method, making the method more predictable and easier to understand. + +### When to Use `final`? + +The **`final` modifier** is typically recommended for both **variables** and **method arguments** to promote **immutability**. Immutable variables make code easier to understand and maintain because their values remain consistent once assigned. + +### Advantages of Using `final`: + +- **Immutability**: Once a value is assigned, it cannot change, leading to more predictable behavior. + +- **Code Readability**: By marking variables and arguments as `final`, it becomes clear to others that these values should not and cannot be changed. + +- **Coding Standards**: Many coding standards recommend using `final` wherever possible. Some organizations may flag variables that are not marked as `final` as coding violations. + +### Best Practice: +- While it may not be practical to make every variable `final`, you should strive to make **most variables and arguments final** when their values do not need to change. This results in cleaner and more maintainable code. + +--- + +## Java Tip 09 - Why Do We Need Static Variables? + +In this tip, we explore the concept of **static variables** in Java. Static variables, unlike instance variables, are shared across all instances of a class. + +This makes them useful when you need a common value or state that is shared across all objects of a class. We will look at a practical example to understand the need for static variables. + +### What Are Static Variables? + +A **static variable** belongs to the **class** rather than to individual instances (objects) of the class. This means that **only one copy** of the static variable is shared among all instances of that class. In contrast, instance variables are unique to each object. + +#### Syntax: + +```java +class ClassName { + static int staticVariable; +} +``` + +#### Example: Player Class with Static Variable + +Consider the following example where we track the number of `Player` instances created: + +```java +class Player { + private String name; + private static int count = 0; // Static variable shared across all instances + + public Player(String name) { + this.name = name; + count++; // Increment count every time a Player object is created + } + + public static int getCount() { + return count; + } +} +``` + +#### Example Usage: + +```java +public class StaticModifierRunner { + public static void main(String[] args) { + Player player1 = new Player("Ronaldo"); + Player player2 = new Player("Federer"); + + System.out.println(Player.getCount()); // Output: 2 + } +} +``` + +#### Key Points: + +- **`count` is a static variable**: It is shared among all instances of the `Player` class. + +- Each time a new `Player` is created, the `count` variable is incremented. + +- The **`getCount()`** method is also static, meaning it can be accessed using the class name (`Player.getCount()`), without needing to instantiate an object. + +### Why Do We Need Static Variables? + +Static variables are useful when you need **shared data** or a **common state** across all instances of a class. In the example above, the `count` variable tracks how many players have been created across all instances of the `Player` class. + +#### Without Static Variable: + +```java +class Player { + private String name; + private int count = 0; // Instance variable + + public Player(String name) { + this.name = name; + count++; + } + + public int getCount() { + return count; + } +} +``` + +In this case, each `Player` object has its own `count` variable, and the value of `count` will be reset for every instance. This means: + +- `player1.getCount()` will return `1`. + +- `player2.getCount()` will also return `1` (not the desired behavior). + +#### With Static Variable: + +By making the `count` variable **static**, the value is shared across all `Player` objects. This allows us to track the total number of `Player` objects created. + +### Key Characteristics of Static Variables + +1. **Shared Across Instances**: + - A static variable is shared across all instances of a class. + - All objects of the class refer to the same static variable. + +2. **Memory Management**: + - A static variable is stored in a common memory location that is created when the class is loaded. + - Static variables are initialized only once, at the start of the program's execution, and persist throughout the program. + +3. **Accessed via Class Name**: + - Static variables can be accessed using the class name (e.g., `ClassName.staticVariable`), making it clear that they are shared among all instances. + +### When to Use Static Variables + +Use static variables when: +- You need to maintain **shared state** or data across all instances of a class. +- The value should remain consistent across all objects (e.g., a counter tracking how many instances of a class have been created). + +In this tip, we learned about the importance of **static variables** and how they differ from instance variables. Static variables are useful when you need a **single shared instance** of a variable across all objects of a class, such as tracking the total number of objects created. + +--- + +## Java Tip 09 - Why Do We Need Static Methods? + +In this tip, we explore the concept of **static methods** in Java. Static methods belong to the **class** rather than any specific instance of the class, which allows them to be called without creating an object. + +Static methods are commonly used when a method performs an operation that is **not dependent on instance-specific data** but rather on class-level or static data. + +We will explore why static methods are useful, especially when working with static variables. + +### Why Do We Need Static Methods? + +#### Context: +In the previous tip, we discussed **static variables**, which are shared across all instances of a class. When a method only operates on static variables, it is logical to make that method **static**. Static methods are useful because: + +- They can be accessed **without needing an instance** of the class. + +- They operate on **class-level data** rather than instance-level data. + +#### Example: Player Class with Static Method + +Consider the following example where we track the number of `Player` instances created. We make the `getCount()` method static because it operates on the static `count` variable, which is shared across all `Player` objects. + +```java +class Player { + private String name; + private static int count = 0; // Shared between all instances + + public Player(String name) { + this.name = name; + count++; // Increment the shared count when a new player is created + } + + // Static method to access the static count variable + public static int getCount() { + return count; + } +} +``` + +#### Example Usage: + +```java +public class StaticModifierRunner { + public static void main(String[] args) { + Player player1 = new Player("Ronaldo"); + Player player2 = new Player("Federer"); + + // Calling static method using the class name + System.out.println(Player.getCount()); // Output: 2 + } +} +``` + +### Why Use Static Methods? + +- **Shared Access**: Since `count` is shared among all instances of the `Player` class, the method that accesses it, `getCount()`, should also be shared. This is achieved by making the method static. + +- **Class-Level Operations**: Static methods allow you to perform operations related to the **class** itself rather than individual objects. In this case, `Player.getCount()` is a class-level operation. + +### Static Methods vs Instance Methods + +- **Static Methods**: + - Can be called using the **class name** (e.g., `Player.getCount()`). + - Do not depend on any instance-specific data. + - Operate on **static data** (e.g., static variables). + +- **Instance Methods**: + - Must be called using an **instance of the class** (e.g., `player1.getName()`). + - Can access both **instance-specific** and **static data**. + +#### Example: + +```java +Player player1 = new Player("Ronaldo"); + +// Calling instance method +player1.getName(); // Instance method, needs an object + +// Calling static method +Player.getCount(); // Static method, can be called with class name +``` + +Even though it's possible to call a static method using an instance (e.g., `player1.getCount()`), it's **not recommended**. The preferred approach is to call static methods using the **class name**, making it clear that the method belongs to the class, not the instance. + +### Key Characteristics of Static Methods + +1. **Belong to the Class**: + - Static methods are associated with the **class itself** rather than any instance. + - They can be called using the **class name** (e.g., `Player.getCount()`). + +2. **Access Only Static Data**: + - Static methods can only operate on **static variables** or other static methods. + - They **cannot** access instance variables or instance methods directly. + +3. **Common Use Cases**: + - Utility functions like `Math.max()`, `Collections.sort()`, and factory methods such as `List.of()` and `Map.of()`. + - Operations that do not depend on instance-specific data. + +In this tip, we learned about the importance of **static methods** and why they are useful when dealing with **class-level data** such as static variables. + +Static methods can be called without creating an instance of the class, making them perfect for operations that do not depend on instance-specific data. + +--- + +## Java Tip 10 - Static Methods Cannot Use Instance Methods or Variables + +In this tip, we explore an important rule about **static methods** in Java: **static methods cannot access instance methods or variables**. This rule stems from the fact that static methods belong to the **class itself**, not to any particular object instance. + +On the other hand, instance methods and variables belong to individual objects. In this tip, we will break down why this limitation exists and how it impacts the way you write static methods. + +### Static Methods vs Instance Methods + +- **Static Methods**: + - Belong to the **class** itself and can be called without creating an object. + - Can only access **static variables** and other **static methods**. + +- **Instance Methods**: + - Belong to a specific **instance** of a class and can access both **instance variables** (specific to an object) and **static variables** (shared across all objects). + +#### Example: Player Class with Static and Instance Methods + +Let's continue using the `Player` class from the previous examples, but this time, we'll focus on how static methods and instance methods interact with variables and methods. + +```java +class Player { + private String name; // Instance variable + private static int count = 0; // Static variable + + public Player(String name) { + this.name = name; + count++; // Increment shared count for every new Player object + } + + // Static method that returns the total count of players + public static int getCount() { + return count; + } + + // Instance method that returns the name of the player + public String getName() { + return name; + } +} +``` + +### Static Methods Cannot Access Instance Variables or Methods + +A **static method** operates at the class level and does not have access to object-specific data, such as **instance variables** or **instance methods**. This is because static methods do not require an instance of the class to be called. + +#### Example of What You **Cannot** Do: + +```java +public static void getPlayerInfo() { + System.out.println(name); // Compilation error: Cannot make a static reference to a non-static field 'name' +} +``` + +- **Why does this fail?** + - The variable `name` is an **instance variable**, meaning it belongs to a specific object of the `Player` class. + - The static method `getPlayerInfo()` belongs to the class itself, and there is no specific object instance to provide the `name` value for. + +#### What You **Can** Do: + +Static methods can only access **static variables** or call other **static methods**. + +```java +public static void printPlayerCount() { + System.out.println(getCount()); // Allowed: static method accessing static method +} +``` + +#### Instance Methods Can Access Both Static and Instance Data + +In contrast, **instance methods** can access both instance variables and static variables. Since instance methods are called on an object, they can access object-specific data as well as class-level data. + +```java +public void printDetails() { + System.out.println("Player: " + getName()); // Allowed: instance method accessing instance variable + System.out.println("Total Players: " + getCount()); // Allowed: instance method accessing static method +} +``` + +### Key Rules for Static Methods + +1. **Static methods can only access static variables**: + - Static variables belong to the class and are shared across all instances, so static methods can access them directly. + - Example: + ```java + public static int getCount() { + return count; // Allowed: accessing static variable + } + ``` + +2. **Static methods can only call static methods**: + - Since static methods do not have an associated instance, they cannot call instance methods. + - Example: + ```java + public static void showCount() { + getCount(); // Allowed: static method accessing another static method + } + ``` + +3. **Instance methods can access both static and instance data**: + - Instance methods are tied to a specific object, so they can access both instance variables (specific to that object) and static variables (shared by all objects). + - Example: + ```java + public void printNameAndCount() { + System.out.println("Name: " + name); // Accessing instance variable + System.out.println("Count: " + getCount()); // Accessing static variable + } + ``` + +### Why This Limitation Exists + +The main reason for this limitation is that **static methods** are not tied to any particular object. They are called on the class itself, and since there is no specific object associated with a static method, there is no instance data (such as instance variables or instance methods) available for the static method to access. + +On the other hand, **instance methods** are always tied to an object, so they have access to both the object-specific data (instance variables) and class-level data (static variables). + +--- + +## Java Tip 11 - `public static final` - Constants + +In this tip, we explore the **`public static final`** combination in Java, which is used to define **constants**. Constants are values that do not change throughout the execution of a program. + +Java makes extensive use of constants in its core classes, and understanding how and why to use them helps in writing more readable and maintainable code. + +We will also discuss the importance of using **`public static final`** for clarity and reusability in programs. + +### What is `public static final`? + +The `public static final` combination has three components: +- **`public`**: The constant can be accessed from anywhere. +- **`static`**: The constant belongs to the class itself and not to any specific instance. This means there is only one copy of the constant shared among all instances of the class. +- **`final`**: The value cannot be changed once initialized. The constant is immutable. + +#### Syntax: + +```java +public static final CONSTANT_NAME = ; +``` + +#### Example: + +```java +public class ConstantsExample { + public static final int SECONDS_IN_MINUTE = 60; + public static final int MINUTES_IN_HOUR = 60; + public static final int HOURS_IN_DAY = 24; + + public static final int SECONDS_IN_DAY = SECONDS_IN_MINUTE * MINUTES_IN_HOUR * HOURS_IN_DAY; +} +``` + +### Why Use `public static final`? + +1. **Clarity and Readability**: + - Using constants makes the code **self-explanatory**. Rather than hardcoding values, constants give meaningful names to values, making the code easier to understand. + - Example: + ```java + int secondsInDay = 60 * 60 * 24; // Hard to understand what these numbers represent + ``` + vs + ```java + int secondsInDay = SECONDS_IN_MINUTE * MINUTES_IN_HOUR * HOURS_IN_DAY; // Clear and understandable + ``` + +2. **Reusability**: + - Once a constant is declared as `public static final`, it can be accessed from anywhere in the program. + - Example: + ```java + System.out.println(ConstantsExample.SECONDS_IN_DAY); // Accessing the constant from another class + ``` + +3. **Immutability**: + - Since the value is marked as `final`, it cannot be changed after it is initialized. This ensures **consistency** throughout the application. + +### Example: Using Constants + +Let’s consider a real-world example where we calculate the number of seconds in a day. + +#### Without Constants: + +```java +public class TimeCalculator { + public static void main(String[] args) { + int secondsInDay = 60 * 60 * 24; // Hardcoded values + System.out.println("Seconds in a day: " + secondsInDay); + } +} +``` + +This works, but it's not immediately clear what the numbers represent. Now, let's rewrite it using `public static final` constants. + +#### With `public static final` Constants: + +```java +public class ConstantsExample { + public static final int SECONDS_IN_MINUTE = 60; + public static final int MINUTES_IN_HOUR = 60; + public static final int HOURS_IN_DAY = 24; + + public static final int SECONDS_IN_DAY = SECONDS_IN_MINUTE * MINUTES_IN_HOUR * HOURS_IN_DAY; +} + +public class TimeCalculator { + public static void main(String[] args) { + System.out.println("Seconds in a day: " + ConstantsExample.SECONDS_IN_DAY); // Using constants + } +} +``` + +By using constants, the code becomes more **understandable** and **maintainable**. + +### Real-World Use of `public static final` in Java + +Java makes extensive use of `public static final` for constants in core libraries. For example: + +1. **`Integer.MIN_VALUE` and `Integer.MAX_VALUE`**: + - In the `Integer` class, constants like `MIN_VALUE` and `MAX_VALUE` represent the minimum and maximum values an `int` can hold. + - Example: + ```java + System.out.println("Min value of int: " + Integer.MIN_VALUE); + System.out.println("Max value of int: " + Integer.MAX_VALUE); + ``` + +2. **Other APIs Using `public static final`**: + - Many classes in the Java API, such as `Collections`, `Arrays`, and `Math`, define constants using `public static final` to make their values accessible globally without allowing modification. + +### Benefits of Using Constants + +- **Prevents Magic Numbers**: + - Magic numbers are hardcoded numbers that appear in code without context. Using constants replaces these magic numbers with meaningful names. + - Example: + ```java + public static final int DAYS_IN_WEEK = 7; + ``` + +- **Easier Maintenance**: + - If you need to update the value of a constant (e.g., a configuration setting), you only need to change it in one place, and the change will propagate across the entire codebase. + +- **Improved Code Understanding**: + - Constants make the intent of the code clearer to others who read it, reducing the learning curve and improving maintainability. + +In this tip, we explored the use of **`public static final`** to define constants. Using constants helps make your code more readable, maintainable, and error-free. + +They provide a clear way to define values that should remain unchanged throughout the program. Java heavily uses constants in its core libraries, and you should also make use of this pattern when writing your programs. + +--- + +## Java Tip 12 - Nested Classes: Inner Class vs Static Nested Class + +In this tip, we explore **Nested Classes** in Java, focusing on the differences between **Inner Classes** and **Static Nested Classes**. + +Nested classes are defined within another class, and depending on whether they are static or not, they behave differently. Understanding when and how to use these different types of nested classes helps in writing more modular and organized code. + +### What Are Nested Classes? + +A **Nested Class** is any class that is defined inside another class. There are two types of nested classes in Java: +1. **Inner Class**: A non-static nested class. +2. **Static Nested Class**: A nested class marked with the `static` keyword. + +#### Example: + +```java +public class OuterClass { + class InnerClass { + // Inner class (non-static nested class) + } + + static class StaticNestedClass { + // Static nested class + } +} +``` + +### Inner Class vs Static Nested Class + +### 1. Inner Class (Non-Static Nested Class) + +An **Inner Class** is a class that is nested within another class and **cannot exist independently** of the enclosing class. It requires an instance of the outer class to be created. + +#### Key Characteristics: +- An instance of an Inner Class can only be created if an instance of the **enclosing (outer) class** exists. +- An Inner Class **can access** the instance variables and methods of the enclosing class. + +#### Example of Inner Class: + +```java +public class OuterClass { + private int outerValue = 10; + + class InnerClass { + public void display() { + System.out.println("Outer class value: " + outerValue); // Access outer class's instance variable + } + } +} +``` + +To create an instance of `InnerClass`, you must first create an instance of `OuterClass`: + +```java +OuterClass outer = new OuterClass(); +OuterClass.InnerClass inner = outer.new InnerClass(); +inner.display(); // Output: Outer class value: 10 +``` + +### 2. Static Nested Class + +A **Static Nested Class** is a nested class marked with the `static` keyword. Unlike inner classes, a static nested class **can exist independently** of an instance of the outer class. It behaves more like a top-level class but is still logically grouped with its enclosing class. + +#### Key Characteristics: +- A Static Nested Class **can be instantiated without creating an instance** of the enclosing class. +- It **cannot access** the instance variables or instance methods of the enclosing class directly. + +#### Example of Static Nested Class: + +```java +public class OuterClass { + private int outerValue = 10; + + static class StaticNestedClass { + public void display() { + // System.out.println(outerValue); // Error: Cannot access non-static outer class members + System.out.println("Static nested class."); + } + } +} +``` + +To create an instance of `StaticNestedClass`, you don't need an instance of `OuterClass`: + +```java +OuterClass.StaticNestedClass staticNested = new OuterClass.StaticNestedClass(); +staticNested.display(); // Output: Static nested class. +``` + +### Differences Between Inner Class and Static Nested Class + +| Feature | Inner Class | Static Nested Class | +|---------------------------------|--------------------------------------------|--------------------------------------------| +| **Keyword** | No `static` keyword | Declared with `static` keyword | +| **Requires Outer Class Instance** | Yes | No | +| **Access to Outer Class Members** | Can access all instance variables and methods of the outer class | Cannot access instance variables or methods of the outer class | +| **Instantiation** | Requires an instance of the outer class | Can be instantiated independently of the outer class | +| **Use Case** | When you need a tight coupling between the inner class and the outer class | When the nested class is more loosely related to the outer class and does not depend on instance data | + +### Code Example: Inner Class vs Static Nested Class + +```java +public class NestedClassRunner { + private int outerValue = 42; + + // Inner Class (Non-Static Nested Class) + class InnerClass { + public void display() { + System.out.println("Inner class can access outerValue: " + outerValue); // Access instance variable + } + } + + // Static Nested Class + static class StaticNestedClass { + public void display() { + // Cannot access outerValue directly + System.out.println("Static nested class."); + } + } + + public static void main(String[] args) { + // Creating an instance of Inner Class + NestedClassRunner outer = new NestedClassRunner(); + NestedClassRunner.InnerClass inner = outer.new InnerClass(); + inner.display(); // Output: Inner class can access outerValue: 42 + + // Creating an instance of Static Nested Class + NestedClassRunner.StaticNestedClass staticNested = new NestedClassRunner.StaticNestedClass(); + staticNested.display(); // Output: Static nested class. + } +} +``` + +--- + +## Java Tip 13 - Anonymous Classes + +In this tip, we explore the concept of **Anonymous Classes** in Java. An anonymous class is a **class without a name** and is typically used when you need to override a method or implement an interface on the spot, without creating a separate named class. + +Anonymous classes are useful when the implementation is only required for a short scope and won't be reused elsewhere. + +### What Is an Anonymous Class? + +An **anonymous class** in Java is a type of **inner class** that is created **without a class name**. It is used to instantiate classes or interfaces inline, often to provide custom implementations for methods without the need for a full class declaration. + +### Syntax: + +```java +new () { + // Method implementations +}; +``` + +Anonymous classes are often used when: +- You need to provide a quick implementation of an interface or class. +- The implementation is short and specific to a particular use case. +- You do not plan to reuse the implementation elsewhere in the code. + +### Example: Sorting a List with an Anonymous Comparator + +Let's consider sorting a list of strings by their length. Normally, you would use a `Comparator` to define the custom sorting logic. + +#### Regular Comparator Implementation: + +```java +import java.util.*; + +public class LengthComparator implements Comparator { + @Override + public int compare(String str1, String str2) { + return Integer.compare(str1.length(), str2.length()); + } +} +``` + +To use this `LengthComparator`: + +```java +List animals = new ArrayList<>(List.of("Ant", "Cat", "Ball", "Elephant")); +Collections.sort(animals, new LengthComparator()); +System.out.println(animals); // Output: [Ant, Cat, Ball, Elephant] +``` + +### Using an Anonymous Class: + +Instead of creating a separate `LengthComparator` class, you can implement the `Comparator` interface directly using an **anonymous class**. + +```java +List animals = new ArrayList<>(List.of("Ant", "Cat", "Ball", "Elephant")); + +Collections.sort(animals, new Comparator() { + @Override + public int compare(String str1, String str2) { + return Integer.compare(str1.length(), str2.length()); + } +}); + +System.out.println(animals); // Output: [Ant, Cat, Ball, Elephant] +``` + +In this example: +- We use the `new Comparator() { ... }` syntax to create an anonymous class that implements the `Comparator` interface. +- There is no need to define a separate named class (`LengthComparator`), and the comparator is defined and used in the same place. + +### Why Use Anonymous Classes? + +1. **Convenience**: You can provide an implementation directly at the point where it's needed, without cluttering your code with unnecessary class declarations. +2. **Encapsulation**: If the implementation is only required for a specific use case and won't be reused, it can be kept hidden within the scope where it's relevant. +3. **Reduce Boilerplate**: It simplifies the code when a full class declaration is not required. + +However, use anonymous classes sparingly, as they can make your code harder to maintain and understand if overused or applied inappropriately. + +### Key Points About Anonymous Classes + +1. **No Name**: An anonymous class does not have a class name. The instance of the class is created immediately after the class definition. + +2. **Implements an Interface or Extends a Class**: An anonymous class must either implement an interface or extend a class. + +3. **One-Time Use**: Anonymous classes are typically used for one-time use cases where you don't need to reuse the implementation elsewhere. + +4. **Access to Variables**: Anonymous classes can access local variables of the enclosing method, but only if the variables are declared `final` or effectively final. + +#### Example: + +```java +int base = 5; + +Collections.sort(animals, new Comparator() { + @Override + public int compare(String str1, String str2) { + // Anonymous class can access local variable 'base' + return Integer.compare(str1.length() + base, str2.length() + base); + } +}); +``` + +In this case, the anonymous class can access the `base` variable because it is effectively final. + +### Use Cases of Anonymous Classes + +1. **Event Listeners**: Often used in UI programming (e.g., handling button clicks). + +2. **Comparators**: As shown in the example, anonymous classes are frequently used when you need to implement custom sorting logic. + +3. **Runnable Implementations**: For providing quick implementations of the `Runnable` interface when starting threads. + +#### Example: Runnable with Anonymous Class + +```java +new Thread(new Runnable() { + @Override + public void run() { + System.out.println("Thread is running"); + } +}).start(); +``` + +In this case, we use an anonymous class to provide a `Runnable` implementation directly. + +### Anonymous Classes vs Lambda Expressions + +Anonymous classes and **lambda expressions** both allow for concise implementations of interfaces with a single method (functional interfaces). + +However, lambda expressions are more concise and are preferred in most cases where functional programming is supported. + +#### Example: Lambda vs Anonymous Class for Comparator + +#### Anonymous Class: +```java +Collections.sort(animals, new Comparator() { + @Override + public int compare(String str1, String str2) { + return Integer.compare(str1.length(), str2.length()); + } +}); +``` + +#### Lambda Expression: +```java +Collections.sort(animals, (str1, str2) -> Integer.compare(str1.length(), str2.length())); +``` + +The lambda expression is more concise and achieves the same result. + +--- + +## Java Tip 14 - Why Enum and Enum Basics: `ordinal` and `values` + +In this tip, we explore **Enums** in Java, short for **Enumerations**. Enums are a special type of class that represent a fixed set of constants. + +They are useful when you need to define a variable that can only take one out of a small set of possible values, such as days of the week, seasons, or directions. + +This tip covers: +- What an enum is. +- How to define and use enums. +- Utility methods like `ordinal()` and `values()`. + +### Why Use Enums? + +Enums help restrict variables to predefined constants. For example, if you are representing the seasons of the year, you can use `String` to represent them, but it would not prevent someone from assigning invalid values like `"Garbage"`. + +Using enums enforces the valid set of values, ensuring that only allowed values can be used. + +#### Example with String (Problematic): + +```java +String season = "Summer"; // This is fine. +season = "Garbage"; // This is not valid, but there is no restriction. +``` + +#### Example with Enum (Correct Approach): + +```java +enum Season { + WINTER, SPRING, SUMMER, FALL; +} + +// Now, season can only have one of the valid values defined in the enum. +Season season = Season.WINTER; +``` + +### Defining and Using Enums + +Enums in Java are defined similarly to a class but use the `enum` keyword. Inside the enum, you list the allowed values (known as constants). + +#### Defining an Enum: + +```java +public enum Season { + WINTER, SPRING, SUMMER, FALL; +} +``` + +#### Using Enums: + +```java +Season currentSeason = Season.SUMMER; +System.out.println(currentSeason); // Output: SUMMER +``` + +By using enums, you restrict the variable to only accept predefined values (`WINTER`, `SPRING`, `SUMMER`, and `FALL`). + +### Utility Methods for Enums + +Java enums come with built-in utility methods that make them easier to work with. + +### 1. `valueOf(String name)` + +The `valueOf` method returns the enum constant of the specified string name, but it must exactly match the name of one of the constants in the enum (case-sensitive). + +#### Example: + +```java +Season season1 = Season.valueOf("WINTER"); +System.out.println(season1); // Output: WINTER +``` + +If you pass an invalid string or incorrect case (e.g., `"winter"`), it will throw an exception: +```java +// Throws java.lang.IllegalArgumentException +Season season2 = Season.valueOf("winter"); // Case-sensitive! +``` + +### 2. `ordinal()` + +The `ordinal` method returns the **position** of the enum constant in the enum declaration, starting from `0`. + +#### Example: + +```java +System.out.println(Season.WINTER.ordinal()); // Output: 0 +System.out.println(Season.SPRING.ordinal()); // Output: 1 +``` + +#### Important Note: +Avoid using `ordinal()` to store enum values in a database because if the order of enum constants changes in the future, it will break the integrity of your data. Always store enums by name rather than ordinal. + +### 3. `values()` + +The `values` method returns an array of all the constants in the enum, which allows you to iterate over the enum constants. + +#### Example: + +```java +Season[] allSeasons = Season.values(); +System.out.println(Arrays.toString(allSeasons)); +// Output: [WINTER, SPRING, SUMMER, FALL] +``` + +This method is useful for looping over all possible values of the enum. + +### Example: Using Enum with Methods + +Let's put everything together in an example: + +```java +import java.util.Arrays; + +public class EnumRunner { + public enum Season { + WINTER, SPRING, SUMMER, FALL; + } + + public static void main(String[] args) { + // Assigning an enum constant + Season currentSeason = Season.SUMMER; + System.out.println("Current season: " + currentSeason); + + // Using valueOf to convert a string to an enum constant + Season season1 = Season.valueOf("WINTER"); + System.out.println("Season from valueOf: " + season1); + + // Using ordinal to get the position of enum constants + System.out.println("WINTER ordinal: " + Season.WINTER.ordinal()); + System.out.println("SPRING ordinal: " + Season.SPRING.ordinal()); + + // Using values() to list all enum constants + Season[] allSeasons = Season.values(); + System.out.println("All seasons: " + Arrays.toString(allSeasons)); + } +} +``` + +#### Output: + +```java +Current season: SUMMER +Season from valueOf: WINTER +WINTER ordinal: 0 +SPRING ordinal: 1 +All seasons: [WINTER, SPRING, SUMMER, FALL] +``` + +### Key Points to Remember + +1. **Enums provide a way to restrict variables** to predefined constants, improving code safety and readability. + +2. **Enums can be used like classes**: they can have fields, methods, and constructors, though we only covered the basics here. + +3. **`ordinal()`**: Returns the position of the enum constant in its declaration (starting from 0). + +4. **`values()`**: Returns all constants in the enum as an array. + +5. **`valueOf(String name)`**: Converts a string into the corresponding enum constant, but the string must exactly match the constant's name (case-sensitive). + +Enums are a powerful tool in Java that allow you to represent a fixed set of constants in a type-safe manner. + +They help make your code more robust and easier to maintain by limiting the possible values a variable can take. + +In this tip, we discussed the basics of enums, focusing on utility methods like `ordinal()` and `values()`. In the next tip, we'll dive deeper into enums and explore how you can assign custom values to them. + +--- + +## Java Tip 15 - Enum: Constructor, Variables, and Methods + +In this tip, we will dive deeper into **Enums** in Java and explore how they can have **constructors**, **variables**, and **methods**. We will also look at how to assign custom values to enum constants, which can be useful for storing them in a database. + +This helps to overcome the limitation of using `ordinal()` for database storage, as the ordinal can change if the order of enum constants is modified. + +### Why Avoid `ordinal()` for Storing Enums in Databases? + +As discussed earlier, using `ordinal()` for storing enums in a database is risky because `ordinal()` depends on the position of the enum constant in the declaration. If the order of the enum constants changes, the ordinal values will also change, causing inconsistency in the stored data. + +The solution is to assign **custom values** to enum constants and use these values for database storage. + +### Enum Constructor, Variables, and Methods + +Enums in Java can have: +- **Instance variables** to hold data specific to each enum constant. +- **Constructors** to initialize these instance variables. +- **Methods** to access or manipulate the values. + +#### Defining Enums with Custom Values + +To assign custom values to enum constants, we need to define a constructor in the enum and pass the value to it. + +#### Example: + +```java +public enum Season { + WINTER(1), SPRING(4), SUMMER(2), FALL(3); + + // Enum instance variable + private int value; + + // Private constructor + private Season(int value) { + this.value = value; + } + + // Getter for the value + public int getValue() { + return value; + } +} +``` + +#### Key Points: +1. **Enum Constructor**: The constructor is private because enum constants are predefined, and no external class should instantiate enum objects. +2. **Instance Variable**: Each enum constant holds a specific value (e.g., `WINTER(1)` assigns the value `1` to `WINTER`). +3. **Getter Method**: A public getter method `getValue()` is provided to retrieve the assigned value. + +### Accessing Enum Values + +Once the enum constants have been defined with custom values, you can access these values using the getter method. + +#### Example: + +```java +public class EnumRunner { + public static void main(String[] args) { + // Accessing enum values and custom assigned values + Season season = Season.SPRING; + System.out.println("Season: " + season); + System.out.println("Value of " + season + ": " + season.getValue()); + + // Printing all enum values and their custom values + for (Season s : Season.values()) { + System.out.println(s + " has value: " + s.getValue()); + } + } +} +``` + +#### Output: + +``` +Season: SPRING +Value of SPRING: 4 +WINTER has value: 1 +SPRING has value: 4 +SUMMER has value: 2 +FALL has value: 3 +``` + +### Changing the Position of Enum Constants + +If you change the order of the enum constants, the `ordinal()` will change, but the custom values assigned will remain the same. + +#### Example: Changing the Position of Constants + +```java +public enum Season { + WINTER(1), SUMMER(2), FALL(3), SPRING(4); // SPRING is now last +} +``` + +Even though the ordinal of `SPRING` will now be `3`, its value will still be `4`: + +```java +System.out.println(Season.SPRING.ordinal()); // Output: 3 +System.out.println(Season.SPRING.getValue()); // Output: 4 +``` + +This ensures that custom values remain consistent, even when the enum constants' positions change. + +### Enum Methods + +Enums can also have methods just like regular classes. In our example, we used a **getter method** `getValue()` to return the custom value of the enum constant. This allows us to expose values without exposing the internal logic or data structure of the enum. + +#### Example: Custom Methods in Enums + +```java +public enum Season { + WINTER(1), SPRING(4), SUMMER(2), FALL(3); + + private int value; + + private Season(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + // Custom method to check if the season is warm + public boolean isWarm() { + return this == SUMMER || this == SPRING; + } +} +``` + +Now you can call the custom method on the enum constants: + +```java +System.out.println(Season.SUMMER.isWarm()); // Output: true +System.out.println(Season.WINTER.isWarm()); // Output: false +``` + +Enums in Java are much more than just a list of constants. They can have variables, constructors, and methods, allowing them to model more complex behaviors and data. + +By assigning custom values to enums and using methods to access them, you can make your code more robust and adaptable, especially when working with databases. + +--- + +## Java Tip 16 - A Quick Look at Built-in Enums: `Month` and `DayOfWeek` + +In the previous tips, we discussed the basics of **Enums** and how to create and use them. Enums are often used when you need a variable to have only a predefined set of values. + +In this tip, we will explore some of the **built-in enums** in Java, specifically focusing on `DayOfWeek` and `Month`, which are part of the `java.time` package introduced in Java 8. + +### Moving Enums to Their Own Class Files + +Enums can be defined as their own independent class files. This allows them to be organized like other Java classes. + +#### Example: + +```java +public enum Season { + WINTER, SPRING, SUMMER, FALL; +} +``` + +Instead of defining this enum inside another class, it can be placed in its own `.java` file as a public enum, allowing other classes to access it more easily. + +### Built-in Enums in Java: `DayOfWeek` and `Month` + +Java provides several built-in enums as part of its API. Two of the most commonly used enums are: + +### 1. `DayOfWeek` (java.time.DayOfWeek) + +The `DayOfWeek` enum represents the days of the week, starting from Monday and going up to Sunday. This enum is part of the `java.time` package, which provides comprehensive support for date and time in Java. + +#### Example: + +```java +import java.time.DayOfWeek; + +public class EnumRunner { + public static void main(String[] args) { + DayOfWeek today = DayOfWeek.MONDAY; + System.out.println("Today is: " + today); + + // Looping through all days of the week + for (DayOfWeek day : DayOfWeek.values()) { + System.out.println("Day: " + day + " Ordinal: " + day.ordinal()); + } + } +} +``` + +#### Output: + +```java +Today is: MONDAY +Day: MONDAY Ordinal: 0 +Day: TUESDAY Ordinal: 1 +Day: WEDNESDAY Ordinal: 2 +Day: THURSDAY Ordinal: 3 +Day: FRIDAY Ordinal: 4 +Day: SATURDAY Ordinal: 5 +Day: SUNDAY Ordinal: 6 +``` + +### 2. `Month` (java.time.Month) + +The `Month` enum represents the twelve months of the year, starting from January (`1`) to December (`12`). Like `DayOfWeek`, `Month` is part of the `java.time` package. + +#### Example: + +```java +import java.time.Month; + +public class EnumRunner { + public static void main(String[] args) { + Month currentMonth = Month.JANUARY; + System.out.println("Current month is: " + currentMonth); + + // Looping through all months of the year + for (Month month : Month.values()) { + System.out.println("Month: " + month + " Ordinal: " + month.ordinal()); + } + + // Getting a Month by its number (1 for January, 12 for December) + Month monthByNumber = Month.of(3); + System.out.println("Month for number 3: " + monthByNumber); + } +} +``` + +#### Output: + +``` +Current month is: JANUARY +Month: JANUARY Ordinal: 0 +Month: FEBRUARY Ordinal: 1 +Month: MARCH Ordinal: 2 +Month: APRIL Ordinal: 3 +Month: MAY Ordinal: 4 +Month: JUNE Ordinal: 5 +Month: JULY Ordinal: 6 +Month: AUGUST Ordinal: 7 +Month: SEPTEMBER Ordinal: 8 +Month: OCTOBER Ordinal: 9 +Month: NOVEMBER Ordinal: 10 +Month: DECEMBER Ordinal: 11 +Month for number 3: MARCH +``` + +#### Key Methods of `Month` Enum: + +- `Month.of(int monthNumber)`: Returns the `Month` corresponding to the number passed (e.g., `Month.of(3)` returns `MARCH`). +- `Month.values()`: Returns all the `Month` values in an array. + +### Primitive Obsession and Why You Should Use Enums + +Many developers often default to using primitive types like `String` or `int` to represent specific values, such as days of the week or months. This is known as **primitive obsession**, and it can lead to errors and poor code readability. + +For example, storing the day of the week as a `String` or `int` can easily result in invalid values being assigned. + +#### Example of Primitive Obsession: + +```java +String day = "Monday"; // Correct +String day = "Funday"; // Invalid, but no compile-time check +``` + +Using enums helps prevent this issue by providing a fixed set of values that can be assigned, ensuring type safety and reducing the possibility of errors. + +#### Example with Enum (Correct Approach): + +```java +DayOfWeek day = DayOfWeek.MONDAY; // Correct +// DayOfWeek day = "Funday"; // Invalid, compile-time error +``` + +Enums also improve the readability of your code by making it clear what kind of values are expected, and they are much easier to maintain and extend. + +In this tip, we explored some of the **built-in enums** in Java, specifically focusing on `DayOfWeek` and `Month`. + +These enums are part of the `java.time` package and are used to represent days of the week and months of the year, respectively. + +When you're working with values that have a predefined set of constants, such as days, months, or directions, consider using enums to make your code cleaner, more maintainable, and less error-prone. + +--- \ No newline at end of file diff --git a/missing-info.md b/missing-info.md index ac9f8e63..d9ecffc7 100644 --- a/missing-info.md +++ b/missing-info.md @@ -194,7 +194,144 @@ Multiplication Table for 4: ### Step 06 - Introduction to Java Method Arguments - Puzzles and Tips -> **Note**: Step-6 is not present in GitHub repo. +#### Overview + +In this step, we will learn about **method arguments** in Java. This includes understanding the difference between **parameters** and **arguments**, as well as some common mistakes that beginners often make when working with methods. + +Methods are essential in Java programming because they allow us to reuse blocks of code by passing values to them. + +Let's explore a few puzzles that will help solidify your understanding of how method arguments work. + +### Puzzle 1: What Happens When No Argument is Passed? + +Imagine we have a method called `sayHelloWorld` that expects an integer as a parameter. What happens if we don’t pass any argument to the method? + +**Scenario**: + +```java +sayHelloWorld(); // No argument passed +``` + +**Result**: + +``` +Error: actual and formal argument lists differ in length +``` + +**Explanation**: + +- This error occurs because the method definition requires **one argument**. + +- If we call the method without any arguments (i.e., an empty pair of parentheses `()`), the program throws an error. + +- The error message says that the **actual** number of arguments (0) is different from the **expected** number of arguments (1). + +To fix this error, we need to pass exactly one argument that matches the type expected by the method. + +### Puzzle 2: Passing a String Instead of an Integer + +What if we try to pass a **string** to the `sayHelloWorld` method that expects an integer? Will that work? + +**Scenario**: + +```java +sayHelloWorld("Hello"); // Passing a string +``` + +**Result**: + +``` +Error: incompatible types +``` + +**Explanation**: + +- The method expects an **integer** (like `4` or `10`), but we are trying to pass a **string** (like `"Hello"`). + +- In Java, you cannot pass a value of the wrong type to a method. In this case, the types don't match—an `int` was expected, but a `String` was provided. + +- This causes the error. + +To fix it, we need to pass a number that is compatible with the method’s parameter type (i.e., an integer). + +### Puzzle 3: Passing a Decimal (Double) Instead of an Integer + +What happens if we pass a **decimal number** (also known as a double) instead of an integer? + +**Scenario**: + +```java +sayHelloWorld(4.5); // Passing a double +``` + +**Result**: + +``` +Error: incompatible types +``` + +**Explanation**: + +- Even though `4.5` is a number, it's a **double** (a number with a decimal), not an **integer** (whole number). + +- Since the method is designed to accept an integer, passing a double will result in an error. + +- Java is strict about matching the types exactly. + +To fix this, we need to pass a whole number (e.g., `4`) that matches the `int` type expected by the method. + +### Key Tip: Understanding Parameters vs. Arguments + +#### What is a Parameter? + +A **parameter** is the name of the variable that appears in the method’s definition. It's like a placeholder. When defining a method, we use parameters to tell the method what kind of data it will accept. + +**Example**: + +```java +public void sayHelloWorld(int noOfTimes) { + // noOfTimes is the parameter +} +``` + +In this example, `noOfTimes` is the parameter that holds the value passed to the method. + +#### What is an Argument? + +An **argument** is the actual value that we pass to the method when we call it. The argument is what fills in the placeholder defined by the parameter. + +When you pass a value to the method, that value becomes the argument. + +**Example**: + +```java +sayHelloWorld(4); // 4 is the argument +``` + +In this example, `4` is the argument that we pass to the method. + +The method takes the argument and uses it in place of the parameter `noOfTimes`. + +#### Example Code: + +```java +public void sayHelloWorld(int noOfTimes) { + for (int i = 0; i < noOfTimes; i++) { + System.out.println("Hello World"); + } +} + +// Method call +sayHelloWorld(4); // Passing 4 as the argument +``` + +**Explanation**: + +- In the method definition: `int noOfTimes` is the **parameter**. + +- When we call the method with `sayHelloWorld(4);`, the value `4` is the **argument**. + +In this case, `noOfTimes` takes on the value of the argument (`4`), so the method prints "Hello World" four times. --- @@ -1334,278 +1471,3470 @@ Tax Amount: $15000.0 ### Step 02 - Java For Loop - Exercises Overview and First Exercise Prime Numbers -> **Note**: Step-2 is not present in GitHub repo. +#### Overview -### Step 03 - Java For Loop - Exercise - Sum Upto N Numbers and Sum of Divisors +In this step, we are going to explore several exercises that use **for loops** in Java. -> **Note**: Step-3 is not present in GitHub repo. +We will work with a custom class called `MyNumber` to perform tasks such as checking if a number is **prime**, finding the **sum of numbers up to N**, calculating the **sum of divisors**, and printing a **number triangle**. -### Step 04 - Java For Loop - Exercise - Print a Number Triangle +### Exercises Overview -> **Note**: Step-4 is not present in GitHub repo. +Here are the main exercises we will be solving: -### Step 05 - While Loop in Java - An Introduction +1. **Prime Number Check**: Write a method to check whether a number is a prime number. -> **Note**: Step-5 is not present in GitHub repo. +2. **Sum Up to N**: Write a method to find the sum of all numbers from 1 up to N. -### Step 06 - While Loop - Exercises - Cubes and Squares upto limit +3. **Sum of Divisors**: Write a method to calculate the sum of divisors of a number, excluding 1 and the number itself. -> **Note**: Step-6 is not present in GitHub repo. +4. **Print a Number Triangle**: Print a right-angled triangle with numbers based on the given input. -### Step 07 - Do While Loop in Java - An Introduction +### Exercise 1: Checking if a Number is Prime -> **Note**: Step-7 is not present in GitHub repo. +A **prime number** is a number greater than 1 that is only divisible by 1 and itself. For example: -### Step 08 - Do While Loop in Java - An Example - Cube while user enters positive numbers +- **5** is a prime number because it is only divisible by 1 and 5. -> **Note**: Step-8 is not present in GitHub repo. +- **6** is not prime because it is divisible by 1, 2, 3, and 6. -### Step 09 - Introduction to Break and Continue +#### Solution: -> **Note**: Step-9 is not present in GitHub repo. +We will create a class called `MyNumber`, and inside this class, we will define a method `isPrime()` to determine if a given number is prime. Let's break down the steps: -### Step 10 - Selecting Loop in Java - For vs While vs Do While +1. **Class Creation**: -> **Note**: Step-10 is not present in GitHub repo. + - First, we create a new class called `MyNumber`. ---- + - We define a constructor that accepts a number, and this number is stored as an instance variable. -### Additional Coding Exercises: +2. **Method Creation**: -> **Note**: Exercises are based on the Step 1 as other Steps are not present in Github repo for Loops. + - We create a method `isPrime()` that returns a boolean value (`true` if the number is prime, `false` if it is not). -> EXERCISES TO BE ADDED IN NEXT PULL REQUEST - Last Updated - 12th Oct 2024 (03:12 AM) + - The method will check if the number is divisible by any number between 2 and the number minus 1. ---- + - If the number is divisible by any of these numbers, it is not prime. -## Section 16: Reference Types in Java Programming +#### Code: -### Step 14 - Java Reference Types - Conclusion +```java +// Class definition +public class MyNumber { + private int number; -> **Note**: Step-14 is not present in GitHub repo. + // Constructor to initialize the number + public MyNumber(int number) { + this.number = number; + } ---- + // Method to check if the number is prime + public boolean isPrime() { + // Guard condition for numbers less than 2 (which are not prime) + if (number < 2) { + return false; + } -## Section 18: Arrays and ArrayLists in Java Programming + // Loop to check divisibility from 2 to number-1 + for (int i = 2; i < number; i++) { + if (number % i == 0) { + return false; // If divisible, it is not prime + } + } -### Step 01 - Understanding the need and Basics about an Array + return true; // If no divisors, it's prime + } +} +``` -You can use an index to find the specific element from the array. It is done by using the indexing operator, '[]'. +**Explanation**: -The expression marks[0] maps to the first array element stored at index 0 of the array marks. +- **Constructor**: Initializes the number passed as input. -```java -jshell> marks[0] -$20 ==> 75 +- `isPrime()` method: -jshell> marks[1] -$21 ==> 60 +- First, it checks for numbers less than 2, which are not prime. -jshell> marks[2] -$22 ==> 56 -``` +- Then, it checks divisibility using a for loop from 2 to the number minus 1. If the number is divisible by any value, it returns false (not prime). ---- +- Otherwise, it returns true (prime). -### Step 16 - Introduction to Array and ArrayList - Conclusion +**Guard Condition**: + +A Guard Condition is used to handle special cases at the beginning of the method. In this case: -> **Note**: Step-16 is not present in GitHub repo. +Numbers less than 2 (negative numbers, 0, 1) are not prime, so we return false for them right away. --- -## Section 20: Java - Oriented Programming Again +### Step 03 - Java For Loop - Exercise - Sum Upto N Numbers and Sum of Divisors -### Step 20 - Java Interface Flyable and Abstract Class Animal - An Exercise +#### Overview -> Not found in Github repo. +In this lesson, we will continue working with the `MyNumber` class and implement two new methods: ---- +1. `sumUptoN()`: This method will calculate the sum of all numbers from 1 to N. -### Step 21 - Polymorphism - An introduction +2. `sumOfDivisors()`: This method will calculate the sum of divisors of a given number, excluding 1 and the number itself. -> Not found in Github repo. +Both methods will use the **for loop** to iterate through numbers and perform the required calculations. ---- +### Exercise 1: Sum Up to N -## Section 25: Introduction to Functional Programming in Java +#### Problem Description: -### Step 12 - Optional class in Java - An Introduction +Given a number `N`, the task is to calculate the sum of all integers from `1` to `N`. For example: +- If `N = 6`, the sum would be `1 + 2 + 3 + 4 + 5 + 6 = 21`. -In an earlier section, we wrote and ran the following code: +### Solution Approach: -```java - jshell> List.of(23, 12, 34, 53).stream().max((n1, n2) -> Integer.compare(n1, n2)); - Optional[53] - jshell> -``` +To calculate the sum, we need to iterate through all numbers from 1 to `N` and keep adding them together. -In order to get the result in a form you would appreciate, we modified this code to look like: +### Code: ```java -jshell> List.of(23, 12, 34, 53).stream().max((n1, n2) -> Integer.compare(n1, n2)).get(); -53 -jshell> -``` - -`max()` is a stream operation, that needs to consume a stream. It is possible that the input stream is empty. In that case, the maximum value would be null. It is undesirable in FP to encounter an exception during a stream operation. +public class MyNumber { + private int number; -It is extremely inelegant if we are asked to handle an exception in an FP code pipeline. + // Constructor to initialize the number + public MyNumber(int number) { + this.number = number; + } ---- + // Method to calculate sum up to N + public int sumUptoN() { + int sum = 0; // Initialize sum to 0 -## Section 27: Introduction to Threads And Concurrency in Java + // Loop from 1 to the number + for (int i = 1; i <= number; i++) { + sum = sum + i; // Add the current value of i to sum + } -### Step 08 - Need for Controlling the Execution of Threads + return sum; // Return the final sum + } +} +``` -Drawbacks of earlier approaches +**Explanation**: -We saw few of the methods for synchronization in the Thread class +- **Looping through 1 to N**: We start from 1 and go up to number (N). On each iteration, we add the current value (i) to sum. -- `start()` -- `join()` -- `sleep()` -- `wait()` +- **Sum variable**: This variable is initialized to 0 and will store the running total. As we loop through the numbers, we keep adding to sum. -#### Above approaches have a few drawbacks: -No Fine-Grained Control: Suppose, for instance , we want Task3 to run after any one of Task1 or Task2 is done. +#### Here’s how to use the sumUptoN() method in the main program: -#### How do we do it? +```java +public class MyNumberRunner { + public static void main(String[] args) { + MyNumber number = new MyNumber(6); // Creating an instance with the number 6 + int sum = number.sumUptoN(); // Calculating sum up to 6 + System.out.println("Sum up to N: " + sum); // Output: 21 + } +} +``` -- **Difficult to maintain**: Imagine managing 5-10 threads with code written in earlier examples. It would become very difficult to maintain. +#### Output: -- **NO Sub-Task Return Mechanism**: With the Thread class or the Runnable interface, there is no way to get the result from a sub-task. +```java +Sum up to N: 21 +``` ---- +- For N = 6, the loop goes through 1, 2, 3, 4, 5, 6 and keeps adding these numbers to sum. -### Step 14 - Threads and MultiThreading - Conclusion +- At the end of the loop, the total sum is 21. -> **Note**: Step-14 is not present in GitHub repo. +### Exercise 2: Sum of Divisors ---- +Given a number N, the task is to calculate the sum of all divisors of N, excluding 1 and the number itself. For example: -## Section 28: Introduction to Exception Handling in Java +If N = 6, its divisors are 1, 2, 3, 6. Excluding 1 and 6, the sum of divisors is 2 + 3 = 5. -### Step 01 - Introduction to Exception Handling - Your Thought Process during Exceptions +If N = 9, its divisors are 1, 3, 9. Excluding 1 and 9, the sum of divisors is 3. -#### Snippet-1 : Exception Condition +#### Solution Approach: -ExceptionHandlingRunner.java +To calculate the sum of divisors, we need to: -```java +- Loop through all numbers from 2 to N-1. - package com.in28minutes.exceptionhandling; - - public class ExceptionHandlingRunner { - public static void main(String[] args) { - callMethod(); - System.out.println("callMethod Done"); - } +- Check if each number divides N without a remainder. - static void callMethod() { - String str = null; - int len = str.length(); - System.out.println("String Length Done"); - } - } -``` +- If it does, add it to the sum. -#### Console Output +#### Code: ```java -java.lang.NullPointerException - -Exception in thread "main" java.lang.NullPointerException +public class MyNumber { + private int number; -at com.in28minutes.exceptionhandling.ExceptionHandlingRunner.callMethod (ExceptionHandlingRunner.java:8) + // Constructor to initialize the number + public MyNumber(int number) { + this.number = number; + } -at com.in28minutes.exceptionhandling.ExceptionHandlingRunner.main (ExceptionHandlingRunner.java:4) -``` + // Method to calculate sum of divisors + public int sumOfDivisors() { + int sum = 0; // Initialize sum to 0 + // Loop from 2 to number - 1 + for (int i = 2; i < number; i++) { + if (number % i == 0) { // Check if i is a divisor of number + sum = sum + i; // Add i to sum if it's a divisor + } + } -#### Snippet-01 Explained + return sum; // Return the final sum + } +} +``` -A java.lang.NullPointerException is thrown by the Java run-time when we called length() on the null reference. +**Explanation**: -If an exception is not handled in the entire call chain, including main, the exception is thrown out and the program terminates. +- Looping through 2 to N-1: We check every number between 2 and number - 1 to see if it's a divisor of number. -System.out.println() statements after the exception are never executed. +- Checking divisibility: We use the modulus operator % to check if the remainder is zero. If number % i == 0, then i is a divisor. -The runtime prints the call stack trace onto the console. +- Sum of divisors: We only add i to the sum if it's a divisor. -For instance, consider this simple class Test: +#### Here’s how to use the sumOfDivisors() method in the main program: ```java - public class Test { - public static void main(String[] args) { - callOne(); - } +public class MyNumberRunner { + public static void main(String[] args) { + MyNumber number = new MyNumber(6); // Creating an instance with the number 6 + int sum = number.sumOfDivisors(); // Calculating sum of divisors for 6 + System.out.println("Sum of divisors: " + sum); // Output: 5 - public static void callOne() { - callTwo(); - } + number = new MyNumber(9); // Creating an instance with the number 9 + sum = number.sumOfDivisors(); // Calculating sum of divisors for 9 + System.out.println("Sum of divisors: " + sum); // Output: 3 + } +} +``` - public static void callTwo() { - callThree(); - } +#### Output: - public static void callThree() { - String name; - System.out.println("This name is %d characters long", name.length()); - } - } +```java +Sum of divisors: 5 +Sum of divisors: 3 ``` -However, the code name.length() used in callThree() caused a NullPointerException to be thrown. +- For N = 6, the divisors are 1, 2, 3, 6. Excluding 1 and 6, the remaining divisors are 2 and 3. Their sum is 5. -However, this is not handled, and the console coughs up the following display: +- For N = 9, the divisors are 1, 3, 9. Excluding 1 and 9, the only remaining divisor is 3. So, the sum is 3. -```java -Exception in thread "main" java.lang.NullPointerException +--- -at Test.callThree(Test.java:13) +### Step 04 - Java For Loop - Exercise - Print a Number Triangle -at Test.callTwo(Test.java:9) +#### Overview -at Test.callOne(Test.java:6) +In this exercise, we will focus on printing a **number triangle** using **nested loops** in Java. -at Test.main(Test.java:3) -``` +The goal is to print a triangle pattern where each row contains increasing numbers up to the input value. -This is nothing but a call trace of the stack, frozen in time. +This exercise demonstrates how to use a **for loop** inside another **for loop** (loop within a loop) to achieve this triangular pattern. ---- +#### Problem Description: -### Step 14 - Exception Handling - Conclusion with Best Practices +Given an input `N`, we need to print a **number triangle** where: -> **Note**: Step-14 is not present in GitHub repo. +- The first row contains the number `1`. ---- +- The second row contains the numbers `1 2`. -## Section 29: Files and Directories in Java +- The third row contains `1 2 3`, and so on, until the last row contains numbers from `1` to `N`. -### Step 05 - Files - Conclusion +#### Solution Approach: -> Not found in Github repo. +To print this triangle, we will use **two for loops**: ---- +1. The outer loop controls the rows (i.e., how many lines we print). -## Section 30: More Concurrency with Concurrent Collections and Atomic Operations +2. The inner loop prints the numbers in each row, from 1 up to the current row number. -### Step 09 - Conclusion +### Code: + +```java +public class MyNumber { + private int number; -> **Note**: Step-9 is not present in GitHub repo. + // Constructor to initialize the number + public MyNumber(int number) { + this.number = number; + } + + // Method to print a number triangle + public void printANumberTriangle() { + // Outer loop to control the number of rows + for (int i = 1; i <= number; i++) { + // Inner loop to print numbers for each row + for (int j = 1; j <= i; j++) { + System.out.print(j + " "); // Print number with a space + } + System.out.println(); // Print a new line after each row + } + } +} +``` + +**Explanation**: + +- Outer loop (i loop): This loop runs from 1 to number (i.e., the total number of rows). It controls the number of rows to be printed. + +- Inner loop (j loop): For each row i, this loop runs from 1 to i. It prints numbers from 1 up to the current value of i. + +- `System.out.print()`: This is used to print numbers on the same line with a space. + +- `System.out.println()`: This adds a new line after each row, so that the next set of numbers starts on the next line. + +#### Here’s how to use the `printANumberTriangle()` method in the main program: + +```java +public class MyNumberRunner { + public static void main(String[] args) { + MyNumber number = new MyNumber(5); // Create an instance with the number 5 + number.printANumberTriangle(); // Print the number triangle + } +} +``` + +**Output**: + +```java +1 +1 2 +1 2 3 +1 2 3 4 +1 2 3 4 5 +``` + +- For N = 5, the outer loop runs 5 times, once for each row. +For each iteration of the outer loop, the inner loop prints numbers from 1 up to the current row number (i). + +- After printing each row, `System.out.println()` is used to move to the next line. + +--- + +### Step 05 - While Loop in Java - An Introduction + +#### Overview + +In this lesson, we will explore the **while loop** in Java, a type of loop that executes a block of code repeatedly as long as a specified condition is true. + +We will cover the syntax of the while loop, compare it to the **if statement**, and highlight some common mistakes like infinite loops. + +By the end, you'll understand how the while loop works and its differences from other loops like the for loop. + +### What is a While Loop? + +- The **while loop** is a control flow statement that allows you to repeat a block of code as long as the condition is true. + +- It is similar to the `if` statement in its syntax, but unlike `if`, which executes the block only once, the while loop will execute the block repeatedly until the condition becomes false. + +### Syntax of the While Loop: + +```java +while (condition) { + // Code to be executed while the condition is true +} +``` + +- The condition is evaluated before each iteration of the loop. + +- If the condition is true, the block of code inside the loop is executed. + +- If the condition is false, the loop stops. + +**Problem**: + +We want to print the numbers from 0 to 4 using a while loop. + +#### Code: + +```java +public class WhileLoopExample { + public static void main(String[] args) { + int i = 0; // Initialize i + + // While loop: repeat as long as i is less than 5 + while (i < 5) { + System.out.println(i); // Print the current value of i + i++; // Increment i after each loop iteration + } + } +} +``` + +**Explanation**: + +- The variable i is initialized to 0. + +- The condition (i < 5) is checked before each iteration. As long as i is less than 5, the loop will continue. + +- Inside the loop, System.out.println(i) prints the current value of i. + +- After each iteration, i is incremented by 1 using i++. + +- The loop will stop once i reaches 5. + +**Output**: + +```java +0 +1 +2 +3 +4 +``` + +### Key Difference Between if and while + +The syntax of the while loop looks similar to an if statement, but the key difference is that: + +An if statement runs the code only once if the condition is true. + +A while loop runs the code multiple times as long as the condition remains true. + +**Example comparison**: + +```java +int i = 0; + +// If statement +if (i < 5) { + System.out.println("i is less than 5"); // Runs only once if condition is true +} + +// While loop +while (i < 5) { + System.out.println(i); // Runs multiple times while i is less than 5 + i++; // Increment i +} +``` + +### Common Mistakes - What is an Infinite Loop? + +- An infinite loop occurs when the condition in a while loop never becomes false. + +- This can happen if we forget to modify the condition within the loop. For example, if we forget to increment the value of i, the loop will continue forever because i will never reach the limit that makes the condition false. + +#### Example of an Infinite Loop: + +```java +int i = 0; + +// Infinite loop: i is never incremented, so the condition is always true +while (i < 5) { + System.out.println(i); + // i++ is missing, so i never changes +} +``` + +- In this case, the loop will print 0 infinitely because the condition i < 5 is always true, and i never gets incremented. + +- To stop the loop, we would need to add i++ inside the loop to ensure that i eventually reaches 5 and the condition becomes false. + +### Problem: + +What happens if the initial value of i is set to a value greater than or equal to the loop condition? + +#### Code: + +```java +int i = 6; // Initialize i to 6 + +while (i < 5) { + System.out.println(i); + i++; // This will not be executed +} +``` + +**Explanation**: + +- Here, the initial value of i is 6, and the condition is (i < 5). + +- Since the condition is false at the start, the loop will not run at all. + +- No output will be produced. + +**Output**: + +```java +(nothing is printed) +``` + +#### Example: Starting with a Negative Value + +### Problem: + +If we start with a negative value for i, how does the while loop behave? + +#### Code: + +```java +int i = -2; + +while (i < 5) { + System.out.println(i); + i++; // Increment i +} +``` + +**Explanation**: + +- The variable i starts at -2. + +- The condition (i < 5) is true initially, so the loop begins and continues until i reaches 5. + +- During each iteration, the current value of i is printed, and then i is incremented. + +**Output**: + +```java +-2 +-1 +0 +1 +2 +3 +4 +``` + +Make sure to increment the value of i (or modify the condition in some way) inside the loop to prevent infinite loops. + +--- + +### Step 06 - While Loop - Exercises - Cubes and Squares upto limit + +#### Overview + +In this lesson, we will explore two exercises using the **while loop**: + +1. Printing the **squares** of numbers up to a specified limit. + +2. Printing the **cubes** of numbers up to a specified limit. + +We will use the **while loop** in scenarios where we don't know in advance how many iterations we need. The loop will continue running until the square or cube of the number exceeds the limit. + +### Problem 1: Print Squares Up to a Limit + +#### Problem Description: + +We want to print the squares of numbers starting from 1, but only as long as the square is less than the given **limit**. + +For example: + +- If the limit is `30`, the output should be: `1, 4, 9, 16, 25` (since 36 exceeds the limit). + +#### Solution Approach: + +We will use a **while loop** to iterate through the numbers, calculate their squares, and print the square only if it is less than the limit. + +#### Code: + +```java +public class WhileNumberPlayer { + private int limit; + + // Constructor to initialize the limit + public WhileNumberPlayer(int limit) { + this.limit = limit; + } + + // Method to print squares up to the limit + public void printSquaresUptoLimit() { + int i = 1; // Initialize i to 1 + + // While loop: Repeat as long as i * i is less than the limit + while (i * i < limit) { + System.out.print(i * i + " "); // Print the square of i + i++; // Increment i after each iteration + } + System.out.println(); // Move to the next line after printing all squares + } +} +``` + +**Explanation**: + +- **Constructor**: The limit is passed when creating an instance of WhileNumberPlayer. + +- `printSquaresUptoLimit()` method: +We initialize i to 1 and start a while loop that continues as long as i * i (the square of i) is less than the limit. + +- Inside the loop, we print the square of i and increment i by 1. + +- The loop stops when the square of i exceeds the limit. + +```java +public class WhileNumberPlayerRunner { + public static void main(String[] args) { + WhileNumberPlayer player = new WhileNumberPlayer(30); // Limit is 30 + player.printSquaresUptoLimit(); // Output squares up to 30 + } +} +``` + +**Output**: + +```java +1 4 9 16 25 +``` + +### Problem 2: Print Cubes Up to a Limit + +#### Problem Description: + +We want to print the cubes of numbers starting from 1, but only as long as the cube is less than the given limit. For example: + +If the limit is 90, the output should be: 1, 8, 27, 64 (since 125 exceeds the limit). + +#### Solution Approach: + +We will use a similar approach as the squares exercise, but this time, we will calculate the cubes of the numbers and stop when the cube exceeds the limit. + +#### Code: + +```java +public class WhileNumberPlayer { + private int limit; + + // Constructor to initialize the limit + public WhileNumberPlayer(int limit) { + this.limit = limit; + } + + // Method to print cubes up to the limit + public void printCubesUptoLimit() { + int i = 1; // Initialize i to 1 + + // While loop: Repeat as long as i * i * i is less than the limit + while (i * i * i < limit) { + System.out.print(i * i * i + " "); // Print the cube of i + i++; // Increment i after each iteration + } + System.out.println(); // Move to the next line after printing all cubes + } +} +``` + +**Explanation**: + +- `printCubesUptoLimit()` method: +We initialize i to 1 and start a while loop that continues as long as i * i * i (the cube of i) is less than the limit. + +- Inside the loop, we print the cube of i and increment i by 1. + +- The loop stops when the cube of i exceeds the limit. + +```java +public class WhileNumberPlayerRunner { + public static void main(String[] args) { + WhileNumberPlayer player = new WhileNumberPlayer(90); // Limit is 90 + player.printCubesUptoLimit(); // Output cubes up to 90 + } +} +``` + +#### Output: + +```java +1 8 27 64 +``` + +--- + +### Step 07 - Do While Loop in Java - An Introduction + +In this lecture, we will explore the **do-while loop** in Java. + +In the previous lesson, we discussed the **while loop**, which executes as long as a condition is true. + +Now, we will learn about the do-while loop, its syntax, and when to use it. + +### Syntax of a Do-While Loop + +The syntax of a do-while loop is very similar to the while loop. However, the key difference is the placement of the condition check. + +In a **do-while loop**, the condition is checked at the end of the loop rather than at the beginning. + +#### Example: + +```java +int i = 1; // Initialize i with value 1 +do { + System.out.println(i); // Print the value of i + i++; // Increment i by 1 +} while (i < 5); // Condition check after the loop body +``` + +- In this example, the loop will print numbers from **1** to **4**. When `i` becomes **5**, the condition `(i < 5)` will fail, and the loop will stop. + +#### Output: + +```java +1 +2 +3 +4 +``` + +### Difference Between `while` and `do-while` Loops + +- In a **while loop**, the condition is checked **before** the execution of the loop body. + +- In a **do-while loop**, the condition is checked **after** the execution of the loop body, which guarantees that the code inside the loop is executed **at least once**, even if the condition is false. + +#### Example with a While Loop: + +```java +int i = 10; +while (i < 5) { + System.out.println(i); // This code will never execute + i++; +} +``` + +- In this case, since the initial value of `i` is **10** (which is greater than 5), the condition `(i < 5)` is false from the start, so the loop body is **never executed**. + +#### Output: + +``` +(no output) +``` + +#### Example with a Do-While Loop: + +```java +int i = 10; +do { + System.out.println(i); // This code will execute once + i++; +} while (i < 5); +``` + +- In this case, even though `i = 10` (which is greater than 5), the **do-while loop** will still execute **once** because the condition is checked **after** the loop body. + +#### Output: + +``` +10 +``` + +### When to Use a Do-While Loop + +You should use a **do-while loop** in situations where you want the code inside the loop to be executed at least once, regardless of whether the condition is true or not. + +For all other cases, where you only want to execute the loop based on the condition, a **while loop** is recommended. + +--- + +### Step 08 - Do While Loop in Java - An Example - Cube while user enters positive numbers + +In this lecture, we will implement an example using the **do-while loop** to repeatedly ask the user for a number, compute its cube, and stop when the user enters a negative number. + +### Problem Statement + +We want to design a program that performs the following steps: + +1. Ask the user to enter a number. + +2. Print the cube of the number. + +3. Repeat steps 1 and 2 until the user enters a negative number. + +4. When a negative number is entered, print a farewell message and exit the loop. + +#### Example Interaction: + +```java +Enter a number: 5 +Cube is 125 +Enter a number: 3 +Cube is 27 +Enter a number: -1 +Thank you! Have Fun! +``` + +### Solution Implementation + +The solution is implemented using a **do-while loop** to ensure that the program asks for a number at least once, even if the user enters a negative number at the beginning. + +#### Code: + +```java +import java.util.Scanner; + +public class DoWhileRepeatedQuestionRunner { + public static void main(String[] args) { + // Create a scanner object to read input + Scanner scanner = new Scanner(System.in); + + // Variable to store the number entered by the user + int number = 0; + + // Do-while loop to repeatedly ask for a number and print its cube + do { + System.out.print("Enter a number: "); // Prompt the user for input + number = scanner.nextInt(); // Read the number + + if (number >= 0) { + // Print the cube of the number if it's non-negative + System.out.println("Cube is " + (number * number * number)); + } + } while (number >= 0); // Continue the loop as long as the number is non-negative + + // Print a farewell message when the loop ends + System.out.println("Thank you! Have Fun!"); + } +} +``` + +### Explanation: + +1. **Scanner Class**: We use the `Scanner` class to read input from the user. + + - `Scanner scanner = new Scanner(System.in);` + + - This creates a scanner object that reads input from the console. + +2. **Loop Logic**: + + - The program starts by asking the user to enter a number using `System.out.print("Enter a number: ")`. + + - The entered number is then stored in the `number` variable using `number = scanner.nextInt();`. + + - If the number is non-negative, the cube of the number is calculated and printed using `System.out.println("Cube is " + (number * number * number));`. + + - The **do-while loop** ensures that the prompt and cube calculation occur at least once, even if the user enters a negative number immediately. + +3. **Loop Termination**: + + - The loop continues until the user enters a negative number, at which point the loop ends, and the program prints the message `"Thank you! Have Fun!"`. + +#### Output Example + +#### Scenario 1 - User Enters Positive Numbers: + +```java +Enter a number: 12 +Cube is 1728 +Enter a number: 6 +Cube is 216 +Enter a number: 2 +Cube is 8 +Enter a number: -1 +Thank you! Have Fun! +``` + +#### Scenario 2 - User Enters Zero: + +```java +Enter a number: 0 +Cube is 0 +Enter a number: -1 +Thank you! Have Fun! +``` + +### Key Points + +- The **do-while loop** is used because we need to ensure that the prompt for input is displayed at least once. + +- We use the `Scanner` class to handle user input from the console. + +- The loop continues as long as the user enters a non-negative number. Once a negative number is entered, the program terminates with a farewell message. + +--- + +### Step 09 - Introduction to Break and Continue + +In this lecture, we are introduced to two important statements used in loops: **`break`** and **`continue`**. + +These statements allow you to control the flow of loops in a precise manner, either by breaking out of the loop entirely or skipping certain iterations. + +### The `break` Statement + +The **`break`** statement is used to exit a loop prematurely. When a `break` statement is encountered, the loop stops executing, and the control is transferred to the statement following the loop. + +### Example 1 - Using `break` in a `for` Loop + +```java +for (int i = 1; i <= 10; i++) { + if (i == 5) break; + System.out.print(i + " "); // Print numbers in a single line with space +} +``` + +#### Output: + +```java +1 2 3 4 +``` + +- In this example, the loop starts printing numbers from **1**. + +- When `i` becomes **5**, the condition `if (i == 5)` is met, and the `break` statement is executed. + +- The loop exits, and the numbers **5** to **10** are not printed. + +### The `continue` Statement + +The **`continue`** statement skips the rest of the current loop iteration and moves to the next iteration. + +Unlike `break`, it doesn't exit the loop but skips the code that comes after it for the current iteration. + +### Example 2 - Using `continue` in a `for` Loop + +```java +for (int i = 1; i <= 10; i++) { + if (i % 2 == 0) continue; + System.out.print(i + " "); +} +``` + +#### Output: + +```java +1 3 5 7 9 +``` + +- In this example, the loop prints only odd numbers. + +- The condition `if (i % 2 == 0)` checks if `i` is even. If the condition is true, the `continue` statement is executed, and the current iteration is skipped. + +- As a result, even numbers **2, 4, 6, 8, 10** are skipped, and only the odd numbers are printed. + +### Differences Between `break` and `continue` + +- **`break`**: When a `break` is executed, it **completely exits** the loop, and the control is passed to the next statement outside the loop. + +- **`continue`**: When a `continue` is executed, it **skips the rest of the current iteration** and moves on to the next iteration of the loop. + +### Exercise - Printing Even Numbers + +Let's create a program to print only the even numbers from 1 to 10 using the `continue` statement. + +### Example 3 - Printing Even Numbers with `continue` + +```java +for (int i = 1; i <= 10; i++) { + if (i % 2 != 0) continue; // Skip odd numbers + System.out.print(i + " "); +} +``` + +#### Output: + +```java +2 4 6 8 10 +``` + +- The condition `if (i % 2 != 0)` checks if `i` is odd. If it is, the `continue` statement is executed, skipping the odd numbers. + +- Only the even numbers **2, 4, 6, 8, 10** are printed. + +While **`break`** and **`continue`** can be useful, they can also make loops harder to understand. + +It is generally a good idea to minimize their use in loops unless absolutely necessary, as they can introduce complexity in program flow. + +--- + +### Step 10 - Selecting Loop in Java - For vs While vs Do While + +In this lecture, we review how to select the right loop to use in Java. We have learned about three types of loops: **For**, **While**, and **Do While**. + +The decision of which loop to use depends on the situation and the problem being solved. + +This lecture covers how to choose between these loops based on specific conditions. + +### Key Considerations for Selecting a Loop + +### 1. Do You Know How Many Times the Loop Will Run? + +- If you know the exact number of times the loop should execute, such as `i` times or `n/2` times, the **For loop** is the best choice. + + **Example**: + + ```java + for (int i = 0; i < 5; i++) { + System.out.println(i); + } + ``` + +- In many situations, you may **not** know how many times the loop will run. For example, if you're processing user input until a specific condition is met (e.g., user enters a negative number), you should use a **While** or **Do While** loop. + +### 2. Should the Code in the Loop Be Executed at Least Once? + +- If you need to ensure that the code in the loop executes **at least once**, regardless of whether the condition is true initially, you should use a **Do While** loop. + + **Example**: + + ```java + int number; + do { + System.out.println("Enter a number:"); + number = scanner.nextInt(); + } while (number >= 0); + ``` + +- If the condition should be checked before the loop executes, you should use a **While loop**. + + **Example**: + + ```java + int number = 1; + while (number >= 0) { + System.out.println("Enter a number:"); + number = scanner.nextInt(); + } + ``` + +### Example Scenario: Menu-Driven Program + +Consider a scenario where we have a menu that allows the user to enter two numbers and perform operations like addition, subtraction, multiplication, etc. + +In the previous section, the program exited after one operation. + +However, if we want to keep showing the menu until the user selects an "Exit" option, which loop should we use? + +#### **Choosing the Right Loop**: + +1. **Do we know how many times the operations will be executed at the start?** + - **No**. The number of operations is unknown, so the **For loop** is excluded. + +2. **Should the code in the loop be executed at least once?** + - **Yes**. We want the user to see the menu at least once. Therefore, the best choice is the **Do While loop**. + +### Example Code for Menu Loop: + +```java +int choice; +do { + System.out.println("Menu:"); + System.out.println("1. Add"); + System.out.println("2. Subtract"); + System.out.println("3. Multiply"); + System.out.println("4. Divide"); + System.out.println("5. Exit"); + System.out.print("Enter your choice: "); + choice = scanner.nextInt(); + + // Perform operations based on the user's choice + switch (choice) { + case 1: + // Add numbers + break; + case 2: + // Subtract numbers + break; + case 3: + // Multiply numbers + break; + case 4: + // Divide numbers + break; + case 5: + System.out.println("Exiting the program."); + break; + default: + System.out.println("Invalid choice, please try again."); + } +} while (choice != 5); +``` + +- In this scenario, we use a **Do While** loop to ensure that the menu is displayed at least once, and the loop continues to execute until the user chooses to exit (i.e., selects option **5**). + +--- + +### Additional Coding Exercises: + +### Exercise 1: Calculating the Sum of Even Numbers +**Objective:** Write a Java program that uses a `for` loop to calculate the sum of all even numbers from 1 to a given number `n`. + +**Task:** +1. Create a class called `SumOfEvenNumbers`. + +2. Implement a method `calculateEvenSum(int n)` that: + - Takes an integer `n` as input. + - Iterates through all numbers from 1 to `n` using a `for` loop. + - Checks if each number is even (`number % 2 == 0`). + - If the number is even, add it to the `sum` variable. + +3. Print the total sum after the loop completes. + +**Code:** + +```java +public class SumOfEvenNumbers { + public void calculateEvenSum(int n) { + int sum = 0; + for (int i = 1; i <= n; i++) { + if (i % 2 == 0) { + sum += i; + } + } + System.out.println("The sum of even numbers from 1 to " + n + " is: " + sum); + } +} + +public class SumOfEvenNumbersRunner { + public static void main(String[] args) { + SumOfEvenNumbers calculator = new SumOfEvenNumbers(); + calculator.calculateEvenSum(10); // Test with n = 10 + } +} +``` + +**Output:** + +```java +The sum of even numbers from 1 to 10 is: 30 +``` + +**Explanation:** +- The program calculates the sum of even numbers from 1 to 10. It checks if each number is even using `i % 2 == 0` and adds it to the sum. + +- By the end of the loop, the sum of even numbers (2, 4, 6, 8, 10) is `30`. + +### Exercise 2: Displaying Multiplication Table +**Objective:** Write a Java program that displays the multiplication table of a number using a `while` loop. + +**Task:** +1. Create a class called `MultiplicationTable`. + +2. Implement a method `printTable(int number)` that: + - Takes an integer `number` as input. + - Uses a `while` loop to print the multiplication table for the given number from `1` to `10`. + +3. Ensure that each line displays the result of multiplying the input number by values from 1 to 10. + +**Code:** + +```java +public class MultiplicationTable { + public void printTable(int number) { + int i = 1; + while (i <= 10) { + System.out.println(number + " x " + i + " = " + (number * i)); + i++; + } + } +} + +public class MultiplicationTableRunner { + public static void main(String[] args) { + MultiplicationTable table = new MultiplicationTable(); + table.printTable(5); // Test with number = 5 + } +} +``` + +**Output:** + +```java +5 x 1 = 5 +5 x 2 = 10 +5 x 3 = 15 +5 x 4 = 20 +5 x 5 = 25 +5 x 6 = 30 +5 x 7 = 35 +5 x 8 = 40 +5 x 9 = 45 +5 x 10 = 50 +``` + +**Explanation:** +- The program uses a `while` loop to print the multiplication table for the number `5`. It starts with `i = 1` and continues until `i` reaches `10`. + +- It prints each line in the format `"number x i = result"`, incrementing `i` in each iteration. + +--- + +## Section 16: Reference Types in Java Programming + +### Step 14 - Java Reference Types - Conclusion + +In this section, we explored the concept of **reference types** in Java and how they differ from **primitive types**. + +This was an in-depth look at reference variables, memory storage, initialization, and how assignment and equality work with them. + +We also discussed built-in reference types in Java, focusing specifically on the **String class**, its alternatives, and **wrapper classes**. + +### 1. Difference Between Reference and Primitive Types + +- **Primitive Types**: Simple data types such as `int`, `char`, `boolean`, etc. + +- **Reference Types**: Objects that refer to memory addresses where the data is stored, such as instances of classes (e.g., `String`, `Array`). + +### 2. Built-in Reference Types in Java + +#### a. The **String Class** + +- **String** is a commonly used reference type in Java. We examined how strings are stored in memory and the way they behave in terms of assignment and equality. + +#### b. **StringBuilder** and **StringBuffer** + +- These two classes provide alternatives to `String` when mutable strings are needed. We discussed: + + - **StringBuilder**: Faster but not thread-safe. + + - **StringBuffer**: Thread-safe but slower due to synchronization. + +### 3. Wrapper Classes + +Java has **eight wrapper classes**, each corresponding to one of the eight primitive types: + +- **Byte**, **Short**, **Integer**, **Long** +- **Float**, **Double** +- **Character** +- **Boolean** + +#### Why Wrapper Classes? +- Wrapper classes allow primitives to be used in contexts that require objects, such as collections (`ArrayList`, `HashMap`). +- They provide utility methods, like converting between strings and numbers. + +### 4. Date and Time API: `LocalDate`, `LocalDateTime`, and `LocalTime` +- Java’s new date and time API provides methods to manipulate date and time easily. + +#### Example Methods: + +- **LocalDate**: Retrieve and manipulate dates. + + ```java + LocalDate today = LocalDate.now(); + LocalDate futureDate = today.plusDays(10); + ``` + +- **LocalDateTime**: Combine date and time. + + ```java + LocalDateTime dateTime = LocalDateTime.now(); + ``` + +- **LocalTime**: Manipulate only the time part of the date. + + ```java + LocalTime time = LocalTime.now(); + ``` + +#### Common Methods: +- **Leap year check**: `isLeapYear()` +- **Length of month/year**: `lengthOfMonth()`, `lengthOfYear()` +- **Add/Subtract time**: `plusDays()`, `minusMonths()` + +### Importance of Exploring APIs + +This section also highlighted the importance of **exploring built-in APIs** in Java. + +Although it may seem tedious at times, understanding what is available allows you to effectively use Java's powerful libraries. + +Knowing which methods exist in APIs like `String`, `Wrapper Classes`, and `LocalDate` helps in building efficient programs. + +### Additional Coding Exercises: + +### Exercise 1: Wrapper Class Conversion + +**Objective:** Understand and demonstrate the use of Java wrapper classes by converting primitive types to their corresponding wrapper classes and performing operations on them. + +**Instructions:** + +1. **Declare Primitive Variables:** Start by declaring three primitive variables: an `int`, a `double`, and a `boolean`. + +2. **Convert to Wrapper Classes:** Use the appropriate wrapper classes (`Integer`, `Double`, and `Boolean`) to convert these primitive variables. +3. **Print Wrapper Values:** Print the values of the wrapper objects to see how they represent the primitive values. +4. **Convert Back to Primitive Types:** Demonstrate the conversion back to primitive types using the methods `intValue()`, `doubleValue()`, and `booleanValue()`. +5. **Print Results:** Finally, print the results after converting back to the primitive types. + +**Code:** + +```java +public class WrapperClassExample { + public static void main(String[] args) { + // Step 1: Declare primitive variables + int primitiveInt = 25; // Integer primitive + double primitiveDouble = 10.5; // Double primitive + boolean primitiveBoolean = true; // Boolean primitive + + // Step 2: Convert to wrapper classes + Integer wrapperInt = Integer.valueOf(primitiveInt); // Wrapper for Integer + Double wrapperDouble = Double.valueOf(primitiveDouble); // Wrapper for Double + Boolean wrapperBoolean = Boolean.valueOf(primitiveBoolean); // Wrapper for Boolean + + // Step 3: Print wrapper values + System.out.println("Primitive int value: " + primitiveInt); // Output: 25 + System.out.println("Wrapper Integer value: " + wrapperInt); // Output: 25 + System.out.println("Converted back to primitive: " + wrapperInt.intValue()); // Output: 25 + + System.out.println("Primitive double value: " + primitiveDouble); // Output: 10.5 + System.out.println("Wrapper Double value: " + wrapperDouble); // Output: 10.5 + System.out.println("Converted back to primitive: " + wrapperDouble.doubleValue()); // Output: 10.5 + + System.out.println("Primitive boolean value: " + primitiveBoolean); // Output: true + System.out.println("Wrapper Boolean value: " + wrapperBoolean); // Output: true + System.out.println("Converted back to primitive: " + wrapperBoolean.booleanValue()); // Output: true + } +} +``` + +**Sample Output:** + +```java +Primitive int value: 25 +Wrapper Integer value: 25 +Converted back to primitive: 25 + +Primitive double value: 10.5 +Wrapper Double value: 10.5 +Converted back to primitive: 10.5 + +Primitive boolean value: true +Wrapper Boolean value: true +Converted back to primitive: true +``` + +**Explanation:** + +- **Primitive Types:** Java has primitive types such as `int`, `double`, and `boolean`. These types store simple values. + +- **Wrapper Classes:** Each primitive type has a corresponding wrapper class (e.g., `Integer` for `int`, `Double` for `double`, and `Boolean` for `boolean`). These classes allow us to treat primitive types as objects. +- **Conversion:** We can convert a primitive type to its corresponding wrapper class using the `valueOf()` method. Similarly, we can convert a wrapper class back to a primitive type using methods like `intValue()`, `doubleValue()`, and `booleanValue()`. + +### Exercise 2: Date Manipulation + +**Objective:** Use the Java Date API to manipulate dates, check for leap years, and understand how to work with date objects. + +**Instructions:** + +1. **Get the Current Date:** Use `LocalDate.now()` to retrieve the current date. + +2. **Print the Current Date:** Output the current date to the console. +3. **Add Days to the Current Date:** Use the `plusDays()` method to add 30 days to the current date and print the new date. +4. **Check for Leap Year:** Use the `isLeapYear()` method to determine if the current year is a leap year and print the result. +5. **Get Length of the Current Month:** Use the `lengthOfMonth()` method to find the number of days in the current month and print this value. + +**Code:** + +```java +import java.time.LocalDate; + +public class DateManipulationExample { + public static void main(String[] args) { + // Step 1: Get the current date + LocalDate currentDate = LocalDate.now(); + System.out.println("Current Date: " + currentDate); // Output: e.g., 2023-10-17 + + // Step 2: Add 30 days + LocalDate newDate = currentDate.plusDays(30); + System.out.println("Date after adding 30 days: " + newDate); // Output: e.g., 2023-11-16 + + // Step 3: Check if the current year is a leap year + boolean isLeapYear = currentDate.isLeapYear(); + System.out.println("Is this year a leap year? " + isLeapYear); // Output: true or false + + // Step 4: Get the length of the current month + int lengthOfMonth = currentDate.lengthOfMonth(); + System.out.println("Length of the current month: " + lengthOfMonth); // Output: 31 (for October) + } +} +``` + +**Sample Output:** + +```java +Current Date: 2023-10-17 +Date after adding 30 days: 2023-11-16 +Is this year a leap year? false +Length of the current month: 31 +``` + +**Explanation:** + +- **LocalDate Class:** The `LocalDate` class represents a date without time-zone information. It is part of the `java.time` package introduced in Java 8. + +- **Current Date:** We retrieve the current date using `LocalDate.now()`, which provides an easy way to get today's date. +- **Date Manipulation:** The `plusDays()` method allows us to add a specified number of days to a date. +- **Leap Year Check:** The `isLeapYear()` method helps determine if the current year has 366 days instead of the usual 365. +- **Length of Month:** The `lengthOfMonth()` method returns the number of days in the month of the date, which is useful for calendar calculations. + +--- + +## Section 18: Arrays and ArrayLists in Java Programming + +### Step 01 - Understanding the need and Basics about an Array + +You can use an index to find the specific element from the array. It is done by using the indexing operator, '[]'. + +The expression marks[0] maps to the first array element stored at index 0 of the array marks. + +```java +jshell> marks[0] +$20 ==> 75 + +jshell> marks[1] +$21 ==> 60 + +jshell> marks[2] +$22 ==> 56 +``` + +--- + +### Step 16 - Introduction to Array and ArrayList - Conclusion + +In this section, we were introduced to the concepts of **Arrays** and **ArrayLists** in Java. + +These data structures allow us to store and manipulate collections of data efficiently. + +We learned why arrays are necessary for handling data of the same type and the limitations that led us to explore **ArrayLists** as a more flexible alternative. + +### 1. **Arrays**: The Basics + +- Arrays allow you to store **multiple elements** of the same type in a single variable. + +- We explored several operations that can be performed using arrays, such as: + - Storing and accessing a collection of values (e.g., marks). + + - **Sum**, **maximum**, **minimum**, and **average** of marks. + +### 2. Limitations of Arrays + +- **Fixed Size**: Once an array is created, its size cannot be changed. + +- **Adding and Removing Elements**: Inserting or removing elements in arrays can be cumbersome and inefficient because arrays have a fixed size. + +### 3. **ArrayList**: A More Flexible Alternative +- Unlike arrays, **ArrayLists** are dynamic and can grow or shrink in size as needed. + +- We introduced basic operations such as adding and removing elements using ArrayLists. + +### 4. ArrayList and the Java Collections Framework + +- ArrayList is part of the **Java Collections Framework**. + +- While this section introduced the basic usage of ArrayLists, more advanced concepts related to collections will be discussed in a future section. + +### Additional Coding Exercises: + +### **Exercise 1: Array Operations** + +**Objective:** Understand and demonstrate basic operations with Java arrays, including creation, initialization, and simple calculations. + +**Instructions:** + +1. Create an array of integers to store daily temperatures for a week. + +2. Initialize the array with sample temperature values. +3. Calculate and print the average temperature for the week. +4. Find and print the highest and lowest temperatures. +5. Print all the temperatures stored in the array. + +**Code:** + +```java +public class WeeklyTemperatureArray { + public static void main(String[] args) { + // Step 1: Create an array for daily temperatures + int[] temperatures = new int[7]; + + // Step 2: Initialize the array with sample values + temperatures[0] = 28; // Monday + temperatures[1] = 30; // Tuesday + temperatures[2] = 27; // Wednesday + temperatures[3] = 29; // Thursday + temperatures[4] = 31; // Friday + temperatures[5] = 32; // Saturday + temperatures[6] = 30; // Sunday + + // Step 3: Calculate average temperature + int sum = 0; + for (int temp : temperatures) { + sum += temp; + } + double average = (double) sum / temperatures.length; + + // Step 4: Find highest and lowest temperatures + int highest = temperatures[0]; + int lowest = temperatures[0]; + for (int i = 1; i < temperatures.length; i++) { + if (temperatures[i] > highest) { + highest = temperatures[i]; + } + if (temperatures[i] < lowest) { + lowest = temperatures[i]; + } + } + + // Step 5: Print results + System.out.println("Daily Temperatures:"); + for (int i = 0; i < temperatures.length; i++) { + System.out.println("Day " + (i + 1) + ": " + temperatures[i] + "°C"); + } + System.out.println("Average Temperature: " + average + "°C"); + System.out.println("Highest Temperature: " + highest + "°C"); + System.out.println("Lowest Temperature: " + lowest + "°C"); + } +} +``` + +**Output:** + +```java +Daily Temperatures: +Day 1: 28°C +Day 2: 30°C +Day 3: 27°C +Day 4: 29°C +Day 5: 31°C +Day 6: 32°C +Day 7: 30°C +Average Temperature: 29.571428571428573°C +Highest Temperature: 32°C +Lowest Temperature: 27°C +``` + +**Explanation:** + +- We create an array of integers to store temperatures for each day of the week. + +- We use array indexing to initialize and access elements. +- We use a for-each loop to calculate the sum of temperatures. +- We use a traditional for loop to find the highest and lowest temperatures. +- The length of the array is used to calculate the average and iterate through all elements. + +### **Exercise 2: ArrayList Operations** + +**Objective:** Understand and demonstrate basic operations with Java ArrayList, including adding elements, removing elements, and iterating through the list. + +**Instructions:** + +1. Create an ArrayList to store a list of fruits. + +2. Add several fruit names to the list. +3. Print the initial list of fruits. +4. Remove a fruit from the list. +5. Add a new fruit to the list. +6. Check if a specific fruit is in the list. +7. Print the final list of fruits and the total number of fruits. + +**Code:** + +```java +import java.util.ArrayList; + +public class FruitListArrayList { + public static void main(String[] args) { + // Step 1: Create an ArrayList for fruits + ArrayList fruits = new ArrayList<>(); + + // Step 2: Add fruits to the list + fruits.add("Apple"); + fruits.add("Banana"); + fruits.add("Orange"); + fruits.add("Mango"); + + // Step 3: Print initial list + System.out.println("Initial fruit list:"); + printFruits(fruits); + + // Step 4: Remove a fruit + fruits.remove("Banana"); + System.out.println("\nAfter removing Banana:"); + printFruits(fruits); + + // Step 5: Add a new fruit + fruits.add("Grapes"); + System.out.println("\nAfter adding Grapes:"); + printFruits(fruits); + + // Step 6: Check if a fruit is in the list + String fruitToCheck = "Mango"; + if (fruits.contains(fruitToCheck)) { + System.out.println("\n" + fruitToCheck + " is in the list."); + } else { + System.out.println("\n" + fruitToCheck + " is not in the list."); + } + + // Step 7: Print final list and count + System.out.println("\nFinal fruit list:"); + printFruits(fruits); + System.out.println("Total number of fruits: " + fruits.size()); + } + + // Helper method to print fruits + private static void printFruits(ArrayList fruits) { + for (String fruit : fruits) { + System.out.println("- " + fruit); + } + } +} +``` + +**Output:** + +```java +Initial fruit list: +- Apple +- Banana +- Orange +- Mango + +After removing Banana: +- Apple +- Orange +- Mango + +After adding Grapes: +- Apple +- Orange +- Mango +- Grapes + +Mango is in the list. + +Final fruit list: +- Apple +- Orange +- Mango +- Grapes +Total number of fruits: 4 +``` + +**Explanation:** + +- We use ArrayList to create a dynamic list of fruits. + +- The `add()` method is used to add elements to the ArrayList. +- The `remove()` method is used to remove an element from the ArrayList. +- The `contains()` method checks if an element is present in the ArrayList. +- The `size()` method returns the number of elements in the ArrayList. +- We use a for-each loop to iterate through the ArrayList and print its contents. + +--- + +## Section 20: Java - Oriented Programming Again + +### Step 20 - Java Interface Flyable and Abstract Class Animal - An Exercise + +In this exercise, we will practice implementing both an **interface** and an **abstract class** in Java. + +We will focus on how interfaces represent common actions across different objects and how abstract classes provide a base for shared functionality. + +### Exercise 1: Interface `Flyable` + +We want to create an interface called **Flyable**, which represents the action of flying. This interface will be implemented by two classes: **Bird** and **Aeroplane**, which have different methods of flying. + +### Steps: + +1. Create the interface `Flyable` with a method `void fly()`. + +2. Implement the interface in two classes: + + - **Bird**: The `fly()` method should print `"with wings"`. + + - **Aeroplane**: The `fly()` method should print `"with fuel"`. + +3. In the `FlyableRunner` class, create an array of `Flyable` objects (`new Bird()` and `new Aeroplane()`). + +4. Loop through the array and call the `fly()` method for each object. + +#### Code: + +```java +// Flyable Interface +interface Flyable { + void fly(); +} + +// Bird class implementing Flyable +class Bird implements Flyable { + @Override + public void fly() { + System.out.println("with wings"); + } +} + +// Aeroplane class implementing Flyable +class Aeroplane implements Flyable { + @Override + public void fly() { + System.out.println("with fuel"); + } +} + +// Runner class to test the interface +public class FlyableRunner { + public static void main(String[] args) { + // Creating an array of Flyable objects + Flyable[] flyingObjects = { new Bird(), new Aeroplane() }; + + // Looping through the array and invoking fly() on each object + for (Flyable object : flyingObjects) { + object.fly(); + } + } +} +``` + +#### Output: + +```java +with wings +with fuel +``` + +#### Explanation: + +- The interface **Flyable** declares a common method `fly()`. + +- The classes **Bird** and **Aeroplane** implement the `fly()` method with their respective flying mechanisms. + +- In the `FlyableRunner`, we loop through the array of `Flyable` objects and invoke the `fly()` method on both `Bird` and `Aeroplane`. + +### Exercise 2: Abstract Class `Animal` + +We want to create an abstract class called **Animal**, which has an abstract method `void bark()`. + +Two concrete classes, **Dog** and **Cat**, will extend this abstract class and provide their own implementations of the `bark()` method. + +### Steps: + +1. Create an abstract class `Animal` with an abstract method `void bark()`. + +2. Implement two classes: + + - **Dog**: The `bark()` method should print `"Bow Bow"`. + + - **Cat**: The `bark()` method should print `"Meow Meow"`. + +3. In the `AnimalRunner` class, create an array of `Animal` objects (`new Dog()` and `new Cat()`). + +4. Loop through the array and call the `bark()` method for each object. + +#### Code: + +```java +// Abstract class Animal +abstract class Animal { + abstract void bark(); +} + +// Dog class extending Animal +class Dog extends Animal { + @Override + public void bark() { + System.out.println("Bow Bow"); + } +} + +// Cat class extending Animal +class Cat extends Animal { + @Override + public void bark() { + System.out.println("Meow Meow"); + } +} + +// Runner class to test the abstract class +public class AnimalRunner { + public static void main(String[] args) { + // Creating an array of Animal objects + Animal[] animals = { new Dog(), new Cat() }; + + // Looping through the array and invoking bark() on each object + for (Animal animal : animals) { + animal.bark(); + } + } +} +``` + +#### Output: + +```java +Bow Bow +Meow Meow +``` + +#### Explanation: + +- The abstract class **Animal** defines the abstract method `bark()`. + +- The **Dog** and **Cat** classes implement the `bark()` method with their own sounds. + +- In the `AnimalRunner`, we loop through the array of `Animal` objects and invoke the `bark()` method on both `Dog` and `Cat`. + +--- + +### Step 21 - Polymorphism - An introduction + +In this lecture, we explore an important concept in object-oriented programming: **Polymorphism**. + +Polymorphism allows objects of different types to be treated as instances of the same class or interface, enabling the same code to execute different behavior depending on the object. + +### Example 1: Polymorphism with Interfaces + +Let's start with an example where we use an interface called `GamingConsole`. + +We will create two classes, **MarioGame** and **ChessGame**, that implement the same interface but have different behaviors. + +#### Steps: + +1. Create an interface **GamingConsole** with a method `void play()`. + +2. Implement the interface in two classes: + + - **MarioGame**: Implements `play()` method with Mario game-specific behavior. + + - **ChessGame**: Implements `play()` method with Chess game-specific behavior. + +3. Create an array of type `GamingConsole` to store objects of both `MarioGame` and `ChessGame`. + +4. Loop through the array and call the `play()` method for each object. + +#### Code: + +```java +// GamingConsole Interface +interface GamingConsole { + void play(); +} + +// MarioGame class implementing GamingConsole +class MarioGame implements GamingConsole { + @Override + public void play() { + System.out.println("Jump, Goes into hole, Go forward"); + } +} + +// ChessGame class implementing GamingConsole +class ChessGame implements GamingConsole { + @Override + public void play() { + System.out.println("Move piece up, down, left, right"); + } +} + +// Runner class to test polymorphism with interfaces +public class GameRunner { + public static void main(String[] args) { + // Creating an array of GamingConsole objects + GamingConsole[] games = { new MarioGame(), new ChessGame() }; + + // Looping through the array and invoking play() on each object + for (GamingConsole game : games) { + game.play(); + } + } +} +``` + +#### Output: + +```java +Jump, Goes into hole, Go forward +Move piece up, down, left, right +``` + +#### Explanation: + +- The interface **GamingConsole** declares a common method `play()`. + +- Both **MarioGame** and **ChessGame** provide different implementations of the `play()` method. + +- The `GameRunner` class loops through the array of `GamingConsole` objects and invokes `play()` on each one, executing different behavior depending on the object (`MarioGame` or `ChessGame`). + +### Example 2: Polymorphism with Abstract Classes + +Polymorphism can also be achieved through **abstract classes**. + +Let's create an abstract class called `Animal` with an abstract method `void bark()`, and then create two concrete classes, **Dog** and **Cat**, that extend the abstract class. + +#### Steps: + +1. Create an abstract class **Animal** with an abstract method `void bark()`. + +2. Implement two classes: + + - **Dog**: Implements the `bark()` method with `"Bow Bow"`. + + - **Cat**: Implements the `bark()` method with `"Meow Meow"`. + +3. Create an array of type `Animal` to store objects of both `Dog` and `Cat`. + +4. Loop through the array and call the `bark()` method for each object. + +#### Code: + +```java +// Abstract class Animal +abstract class Animal { + abstract void bark(); +} + +// Dog class extending Animal +class Dog extends Animal { + @Override + public void bark() { + System.out.println("Bow Bow"); + } +} + +// Cat class extending Animal +class Cat extends Animal { + @Override + public void bark() { + System.out.println("Meow Meow"); + } +} + +// Runner class to test polymorphism with abstract classes +public class AnimalRunner { + public static void main(String[] args) { + // Creating an array of Animal objects + Animal[] animals = { new Cat(), new Dog() }; + + // Looping through the array and invoking bark() on each object + for (Animal animal : animals) { + animal.bark(); + } + } +} +``` + +#### Output: + +```java +Meow Meow +Bow Bow +``` + +#### Explanation: + +- The abstract class **Animal** defines the abstract method `bark()`. + +- The **Dog** and **Cat** classes provide different implementations of the `bark()` method. + +- The `AnimalRunner` class loops through the array of `Animal` objects and invokes `bark()` on each one, resulting in different behavior based on the actual object (`Cat` or `Dog`). + +### What is Polymorphism? + +- **Polymorphism** allows the same method to exhibit different behavior based on the object it is called on. + +- This enables us to write more flexible and maintainable code by using common interfaces or base classes, while still allowing individual objects to define their specific behavior. + +### Additional Coding Exercises: + +### Exercise 1: Polymorphism with a Shape Interface + +**Objective:** Understand polymorphism by creating a `Shape` interface and implementing it in various shape classes. + +#### Implementation +In this exercise, we will create an interface named `Shape` with a method `draw()`. We will implement this interface in two classes, `Circle` and `Square`, each providing its own implementation of the `draw()` method. We will then create a main class to demonstrate how polymorphism allows us to treat different shapes uniformly. + +#### Code + +1. **Create the `Shape` interface:** + ```java + // Shape.java + public interface Shape { + void draw(); // Method to draw the shape + } + ``` + +2. **Implement the `Shape` interface in the `Circle` class:** + ```java + // Circle.java + public class Circle implements Shape { + @Override + public void draw() { + System.out.println("Drawing a Circle"); + } + } + ``` + +3. **Implement the `Shape` interface in the `Square` class:** + ```java + // Square.java + public class Square implements Shape { + @Override + public void draw() { + System.out.println("Drawing a Square"); + } + } + ``` + +4. **Write a main class to demonstrate polymorphism:** + ```java + // Main.java + public class Main { + public static void main(String[] args) { + // Creating an array of Shape references + Shape[] shapes = new Shape[2]; + + // Instantiating Circle and Square + shapes[0] = new Circle(); + shapes[1] = new Square(); + + // Iterating through the shapes array and calling draw method + for (Shape shape : shapes) { + shape.draw(); // Dynamic method dispatch + } + } + } + ``` + +#### Output +``` +Drawing a Circle +Drawing a Square +``` + +#### Explanation + +- In this exercise, we defined an interface called `Shape`, which declares a method `draw()`. The `Circle` and `Square` classes implement this interface and provide their specific implementations of the `draw()` method. + +- In the `Main` class, we created an array of `Shape` references and instantiated objects of `Circle` and `Square`. By iterating through the array and calling the `draw()` method, we demonstrated polymorphism. + +- This allows us to call the same method on different types of objects, showcasing dynamic method dispatch—where the method that gets executed is determined at runtime based on the actual object type. + +### Exercise 2: Method Overloading in a Calculator Class + +**Objective:** Practice method overloading by creating a `Calculator` class with overloaded methods for addition. + +#### Implementation + +In this exercise, we will implement a `Calculator` class that has multiple `add` methods. Each method will have a different signature, allowing it to handle various types and numbers of parameters. + +This will demonstrate how method overloading enables a class to perform similar operations in different ways. + +#### Code + +1. **Create the `Calculator` class:** + ```java + // Calculator.java + public class Calculator { + + // Method to add two integers + public int add(int a, int b) { + return a + b; + } + + // Method to add three integers + public int add(int a, int b, int c) { + return a + b + c; + } + + // Method to add two double values + public double add(double a, double b) { + return a + b; + } + } + ``` + +2. **Write a main class to test the `Calculator` class:** + ```java + // Main.java + public class Main { + public static void main(String[] args) { + Calculator calculator = new Calculator(); + + // Testing the add methods + int sum1 = calculator.add(5, 10); // Adding two integers + int sum2 = calculator.add(5, 10, 15); // Adding three integers + double sum3 = calculator.add(5.5, 10.5); // Adding two double values + + // Printing results + System.out.println("Sum of 5 and 10 is: " + sum1); // Output: 15 + System.out.println("Sum of 5, 10, and 15 is: " + sum2); // Output: 30 + System.out.println("Sum of 5.5 and 10.5 is: " + sum3); // Output: 16.0 + } + } + ``` + +#### Output + +```java +Sum of 5 and 10 is: 15 +Sum of 5, 10, and 15 is: 30 +Sum of 5.5 and 10.5 is: 16.0 +``` + +#### Explanation + +In this exercise, we created a `Calculator` class that demonstrates method overloading, a core concept in OOP. The `add()` method is overloaded to handle different types and numbers of parameters: + +- **Two integers:** Adds two integers and returns the result. + +- **Three integers:** Adds three integers, showcasing the flexibility of method overloading. + +- **Two doubles:** Adds two double values, illustrating that methods can be differentiated by parameter types. + +In the `Main` class, we instantiated the `Calculator` and tested the overloaded methods, demonstrating that Java can determine which method to call based on the method signature at compile time. This enhances code readability and allows multiple operations to be performed seamlessly. + +--- + +## Section 22: Collections in Java Programming + + +### Additional Coding Exercises: + +### **Exercise 1: Set Operations** + +**Problem Statement:** +Given a list of integers: +```java +List numbers = List.of(5, 10, 5, 20, 10, 15); +``` +1. Display unique integers using a `HashSet`. + +2. Display these integers in insertion order using a `LinkedHashSet`. + +3. Display these integers in sorted order using a `TreeSet`. + +**Solution:** + +```java +import java.util.*; + +public class SetOperations { + public static void main(String[] args) { + List numbers = List.of(5, 10, 5, 20, 10, 15); + + // Using HashSet to display unique integers (order is not guaranteed) + Set hashSet = new HashSet<>(numbers); + System.out.println("HashSet (Unique, Unordered): " + hashSet); + + // Using LinkedHashSet to maintain insertion order + Set linkedHashSet = new LinkedHashSet<>(numbers); + System.out.println("LinkedHashSet (Insertion Order): " + linkedHashSet); + + // Using TreeSet to display integers in sorted order + Set treeSet = new TreeSet<>(numbers); + System.out.println("TreeSet (Sorted Order): " + treeSet); + } +} +``` + +**Output:** + +```java +HashSet (Unique, Unordered): [20, 5, 10, 15] +LinkedHashSet (Insertion Order): [5, 10, 20, 15] +TreeSet (Sorted Order): [5, 10, 15, 20] +``` + +**Explanation:** +- The `HashSet` removes duplicates but does not maintain any order. + +- The `LinkedHashSet` preserves the insertion order. + +- The `TreeSet` stores elements in natural (sorted) order. + +### **Exercise 2: Queue Operations with Custom Comparator** + +**Problem Statement:** + +Create a `PriorityQueue` with the following strings: + +```java +List words = List.of("Elephant", "Dog", "Cat", "Giraffe", "Mouse"); +``` +1. Add these words into a `PriorityQueue` and display them in natural (alphabetical) order. + +2. Use a custom comparator to sort the words by length, and display them in ascending order of length. + +**Solution:** + +```java +import java.util.*; + +public class PriorityQueueOperations { + public static void main(String[] args) { + List words = List.of("Elephant", "Dog", "Cat", "Giraffe", "Mouse"); + + // PriorityQueue with natural ordering (alphabetical order) + PriorityQueue alphabeticalQueue = new PriorityQueue<>(words); + System.out.println("PriorityQueue (Alphabetical Order):"); + while (!alphabeticalQueue.isEmpty()) { + System.out.println(alphabeticalQueue.poll()); + } + + // PriorityQueue with custom comparator for length-based ordering + PriorityQueue lengthQueue = new PriorityQueue<>(Comparator.comparingInt(String::length)); + lengthQueue.addAll(words); + System.out.println("\nPriorityQueue (Length Order):"); + while (!lengthQueue.isEmpty()) { + System.out.println(lengthQueue.poll()); + } + } +} +``` + +**Output:** + +```java +PriorityQueue (Alphabetical Order): +Cat +Dog +Elephant +Giraffe +Mouse + +PriorityQueue (Length Order): +Cat +Dog +Mouse +Giraffe +Elephant +``` + +**Explanation:** + +- The first `PriorityQueue` sorts words alphabetically by default. + +- The second `PriorityQueue` uses a custom comparator to sort words based on their length (`String::length`). + +--- + +## Section 24: Generics in Java Programming + +### Additional Coding Exercises: + +### Exercise 1: Implement a Size Method + +**Task:** Add a method named `size` to the `MyCustomList` class that returns the number of elements currently in the list. + +#### Explanation: + +1. **Purpose:** This method allows users to determine how many elements are present in the custom list. + +2. **Return Type:** The method returns an integer representing the size of the list. + +3. **Implementation Steps:** + - Use the `size()` method from the underlying `ArrayList` to retrieve the count of elements. + - Ensure that the method is accessible and adheres to generics. + +#### Code: + +**MyCustomList.java** +```java +package com.in28minutes.generics; + +import java.util.ArrayList; + +public class MyCustomList { + ArrayList list = new ArrayList<>(); + + // Method to add an element + public void addElement(T element) { + list.add(element); + } + + // Method to remove an element + public void removeElement(T element) { + list.remove(element); + } + + // Method to get an element at a specific index + public T get(int index) { + return list.get(index); + } + + // Method to return the size of the list + public int size() { + return list.size(); // Returns the current number of elements in the list + } + + // Override toString() for better representation + @Override + public String toString() { + return list.toString(); // Returns a string representation of the list + } +} +``` + +**GenericsRunner.java** +```java +package com.in28minutes.generics; + +public class GenericsRunner { + public static void main(String[] args) { + MyCustomList list = new MyCustomList<>(); + list.addElement("Element-1"); + list.addElement("Element-2"); + System.out.println("Size of list: " + list.size()); // Expected output: 2 + + MyCustomList list2 = new MyCustomList<>(); + list2.addElement(Integer.valueOf(5)); + list2.addElement(Integer.valueOf(9)); + System.out.println("Size of list2: " + list2.size()); // Expected output: 2 + } +} +``` + +#### Output: + +```java +Size of list: 2 +Size of list2: 2 +``` + +### Exercise 2: Implement a Clear Method + +**Task:** Add a method named `clear` to the `MyCustomList` class that removes all elements from the list. + +#### Explanation: +1. **Purpose:** This method allows users to empty the custom list of all its elements. + +2. **Return Type:** The method returns void since it modifies the list in place. + +3. **Implementation Steps:** + - Use the `clear()` method from the underlying `ArrayList` to remove all elements. + - Ensure the method is accessible and performs the action effectively. + +#### Code: + +**MyCustomList.java** +```java +package com.in28minutes.generics; + +import java.util.ArrayList; + +public class MyCustomList { + ArrayList list = new ArrayList<>(); + + // Method to add an element + public void addElement(T element) { + list.add(element); + } + + // Method to remove an element + public void removeElement(T element) { + list.remove(element); + } + + // Method to get an element at a specific index + public T get(int index) { + return list.get(index); + } + + // Method to return the size of the list + public int size() { + return list.size(); // Returns the current number of elements in the list + } + + // Method to clear all elements from the list + public void clear() { + list.clear(); // Clears the entire list + } + + // Override toString() for better representation + @Override + public String toString() { + return list.toString(); // Returns a string representation of the list + } +} +``` + +**GenericsRunner.java** +```java +package com.in28minutes.generics; + +public class GenericsRunner { + public static void main(String[] args) { + MyCustomList list = new MyCustomList<>(); + list.addElement("Element-1"); + list.addElement("Element-2"); + System.out.println("List before clear: " + list); // Expected output: [Element-1, Element-2] + list.clear(); // Clearing the list + System.out.println("List after clear: " + list); // Expected output: [] + } +} +``` + +#### Output: +``` +List before clear: [Element-1, Element-2] +List after clear: [] +``` + +--- + +## Section 25: Introduction to Functional Programming in Java + +### Step 12 - Optional class in Java - An Introduction + +In an earlier section, we wrote and ran the following code: + +```java + jshell> List.of(23, 12, 34, 53).stream().max((n1, n2) -> Integer.compare(n1, n2)); + Optional[53] + jshell> +``` + +In order to get the result in a form you would appreciate, we modified this code to look like: + +```java +jshell> List.of(23, 12, 34, 53).stream().max((n1, n2) -> Integer.compare(n1, n2)).get(); +53 +jshell> +``` + +`max()` is a stream operation, that needs to consume a stream. It is possible that the input stream is empty. In that case, the maximum value would be null. It is undesirable in FP to encounter an exception during a stream operation. + +It is extremely inelegant if we are asked to handle an exception in an FP code pipeline. + +--- + +### Step 18 - Introduction to Functional Programming - Conclusion + +In this section, we explored the basics of **functional programming** in Java, a powerful paradigm that allows developers to write more concise, readable, and maintainable code. + +We introduced the concept of **functions as first-class citizens**, enabling the storage of functions in variables, passing functions to methods, and returning functions from methods. + +This opens new opportunities for programming, especially when working with data in a more declarative way. + +### 1. **Functions as First-Class Citizens** + +- In functional programming, functions can be treated like any other variable or object. You can: + + - Store functions in variables. + + - Pass functions as arguments to methods. + + - Return functions as values from methods. + +This flexibility allows developers to build more modular and reusable code by separating **what** to do from **how** to do it. + +### 2. **Imperative vs Declarative Programming** + +We contrasted two different programming styles: + +- **Imperative Programming**: You specify **how** to do something step-by-step. + + - For example, summing a list of numbers involves explicitly creating a variable to store the sum, looping through the numbers, and adding each one. + + ```java + int sum = 0; + for (int number : numbers) { + sum += number; + } + ``` + +- **Declarative Programming**: You focus on **what** to do rather than how to do it. + + - Functional programming allows you to express the same logic at a higher level. For instance, summing a list of numbers using **streams** can be written declaratively. + + ```java + int sum = numbers.stream().reduce(0, Integer::sum); + ``` + +### 3. **Benefits of Functional Programming** + +- **Code Simplicity**: Functional programming simplifies logic by allowing you to write cleaner, more readable code without the need for explicit state management or mutation. + +- **Higher Abstraction**: With functional programming, you can operate at a **higher level of abstraction**, focusing on what the code should do instead of how to implement it. + +- **Immutability**: Functional programming encourages avoiding **mutation**, leading to fewer side effects and more predictable code behavior. + +### Challenges of Adopting Functional Programming + +Functional programming can feel unfamiliar and complex, particularly for programmers accustomed to **imperative** and **object-oriented** paradigms. + +The functional approach is often less intuitive, especially when working with constructs like **streams** and **lambda expressions** for the first time. + +### Additional Coding Exercises: + +### Exercise 1: Race Condition Simulation + +**Objective:** Demonstrate a race condition by implementing a simple counter increment using multiple threads. + +#### Explanation: +In this exercise, we will create a counter that multiple threads will increment. Due to the lack of synchronization, we expect to observe inconsistencies in the final counter value, demonstrating a race condition. + +#### Instructions: +1. Create a class named `RaceConditionDemo`. + +2. Declare a static variable `counter` initialized to `0`. +3. Implement a method `incrementCounter()` that increments the `counter` variable. +4. Create multiple threads that will call the `incrementCounter()` method. +5. Run the threads and print the final value of the `counter` after all threads have finished executing. + +#### Code: + +```java +public class RaceConditionDemo { + static int counter = 0; // Shared counter variable + + // Method to increment the counter + public static void incrementCounter() { + counter++; // Incrementing the counter + } + + public static void main(String[] args) throws InterruptedException { + Thread[] threads = new Thread[10]; // Array to hold threads + + // Creating and starting 10 threads + for (int i = 0; i < 10; i++) { + threads[i] = new Thread(() -> { + for (int j = 0; j < 1000; j++) { // Each thread increments 1000 times + incrementCounter(); + } + }); + threads[i].start(); // Start each thread + } + + // Waiting for all threads to finish + for (Thread thread : threads) { + thread.join(); + } + + // Printing the final value of the counter + System.out.println("Final counter value (without synchronization): " + counter); + } +} +``` + +#### Output: + +You may not always see the expected output of `10000` due to the race condition. For example, you might see: +``` +Final counter value (without synchronization): 9995 +``` + +This exercise shows how concurrent modifications to shared resources can lead to unexpected results due to race conditions. + +### Exercise 2: Thread Safety with Synchronized Block + +**Objective:** Fix the race condition in the previous exercise by using a synchronized block. + +#### Explanation: +In this exercise, we will modify the `incrementCounter()` method to include synchronization. This will ensure that only one thread can execute the method at a time, preventing race conditions. + +#### Instructions: +1. Modify the `incrementCounter()` method to use the `synchronized` keyword. + +2. Run the threads again and print the final value of the `counter` after all threads have finished executing. + +#### Code: + +```java +public class ThreadSafeDemo { + static int counter = 0; // Shared counter variable + + // Synchronized method to increment the counter + public synchronized static void incrementCounter() { + counter++; // Incrementing the counter safely + } + + public static void main(String[] args) throws InterruptedException { + Thread[] threads = new Thread[10]; // Array to hold threads + + // Creating and starting 10 threads + for (int i = 0; i < 10; i++) { + threads[i] = new Thread(() -> { + for (int j = 0; j < 1000; j++) { // Each thread increments 1000 times + incrementCounter(); + } + }); + threads[i].start(); // Start each thread + } + + // Waiting for all threads to finish + for (Thread thread : threads) { + thread.join(); + } + + // Printing the final value of the counter + System.out.println("Final counter value (with synchronization): " + counter); + } +} +``` + +#### Output: + +With the use of synchronization, the output should consistently be `10000`, for example: + +```java +Final counter value (with synchronization): 10000 +``` + +This exercise illustrates how synchronization can prevent race conditions in multithreaded applications, ensuring thread safety when accessing shared resources. + +--- + +## Section 27: Introduction to Threads And Concurrency in Java + +### Step 08 - Need for Controlling the Execution of Threads + +Drawbacks of earlier approaches + +We saw few of the methods for synchronization in the Thread class + +- `start()` +- `join()` +- `sleep()` +- `wait()` + +#### Above approaches have a few drawbacks: + +No Fine-Grained Control: Suppose, for instance , we want Task3 to run after any one of Task1 or Task2 is done. + +#### How do we do it? + +- **Difficult to maintain**: Imagine managing 5-10 threads with code written in earlier examples. It would become very difficult to maintain. + +- **NO Sub-Task Return Mechanism**: With the Thread class or the Runnable interface, there is no way to get the result from a sub-task. + +--- + +### Step 14 - Threads and MultiThreading - Conclusion + +In this section, we explored the concept of **MultiThreading** in Java. + +We began by learning how to create threads, manage their execution, and handle communication between them. + +We also introduced the **ExecutorService** to simplify the process of managing multiple threads. + +This section provided a comprehensive overview of the key features Java offers for multithreading. + +### 1. Creating Threads in Java + +We learned two primary ways to create a thread in Java: + +- **Extending the Thread class**: Create a new class that extends `Thread` and overrides the `run()` method. + +- **Implementing the Runnable interface**: Create a class that implements `Runnable` and pass it to a `Thread` object. + +### 2. Thread States and Management + +We explored the different **states** a thread can be in: + +- **New** +- **Runnable** +- **Blocked/Waiting** +- **Timed Waiting** +- **Terminated** + +We also looked at: + +- **Thread priorities**: How to set different priorities for threads. + +- **Waiting for threads**: Techniques like `join()` to wait for threads to complete their execution. + +- **Thread communication**: Methods such as `wait()`, `notify()`, and `notifyAll()` to synchronize threads. + +### 3. ExecutorService + +Managing multiple threads manually can become complex. + +- **ExecutorService** simplifies this by handling the creation and management of threads efficiently. + +- We discussed how **ExecutorService** allows us to control how many threads are used to process tasks, providing a more scalable and efficient solution. + +### 4. Handling Results with `Future` + +We learned how to retrieve results from a thread using **Future**. By calling the `get()` method on a `Future` object, we can wait for the result of a task and retrieve it once the task is completed. + +### 5. `invokeAll()` and `invokeAny()` + +- **`invokeAll()`**: Executes multiple tasks concurrently and waits for **all** tasks to complete before proceeding. + +- **`invokeAny()`**: Executes multiple tasks concurrently and returns the result of the **first** completed task, canceling the remaining tasks. + +### Additional Coding Exercises: + +### Exercise 1: Synchronizing Multiple Tasks + +**Objective:** Create a Java program that uses threads to execute three tasks. Task 1 and Task 2 should run in parallel, and Task 3 should start only after both Task 1 and Task 2 have completed. + +**Instructions:** + +1. Define three tasks: `Task1`, `Task2`, and `Task3`. + + - **Task1** should print numbers from 1 to 10. + + - **Task2** should print letters from 'A' to 'J'. + - **Task3** should print "All tasks completed!" after Task 1 and Task 2 are done. + +2. In the `main` method, start `Task1` and `Task2`, and use the `join()` method to ensure that `Task3` executes only after both `Task1` and `Task2` are finished. + +**Code:** + +```java +class Task1 extends Thread { + public void run() { + for (int i = 1; i <= 10; i++) { + System.out.print(i + " "); + } + System.out.println("\nTask1 Done"); + } +} + +class Task2 extends Thread { + public void run() { + for (char c = 'A'; c <= 'J'; c++) { + System.out.print(c + " "); + } + System.out.println("\nTask2 Done"); + } +} + +class Task3 { + public void execute() { + System.out.println("All tasks completed!"); + } +} + +public class SynchronizationExample { + public static void main(String[] args) throws InterruptedException { + Task1 task1 = new Task1(); + Task2 task2 = new Task2(); + + task1.start(); + task2.start(); + + task1.join(); + task2.join(); + + Task3 task3 = new Task3(); + task3.execute(); + } +} +``` + +**Output:** + +```java +1 2 3 4 5 6 7 8 9 10 +Task1 Done +A B C D E F G H I J +Task2 Done +All tasks completed! +``` + +### Exercise 2: Using ExecutorService for Parallel Execution + +**Objective:** Create a Java program that uses `ExecutorService` to manage multiple tasks running in parallel. All tasks should print their identifiers (e.g., Task 1, Task 2, etc.) and indicate when they are done. + +**Instructions:** + +1. Define a `Runnable` task that takes a task identifier (e.g., Task 1, Task 2) and prints a message indicating when it starts and when it is done. + +2. Create an `ExecutorService` with a fixed thread pool of 3. +3. Submit multiple tasks (at least 5) to the executor service and observe how they run concurrently. +4. After submitting the tasks, call `shutdown()` on the executor service to stop accepting new tasks and wait for previously submitted tasks to complete. + +**Code:** + +```java +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +class PrintTask implements Runnable { + private final String taskName; + + public PrintTask(String taskName) { + this.taskName = taskName; + } + + public void run() { + System.out.println(taskName + " started."); + try { + Thread.sleep(1000); // Simulate work + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + System.out.println(taskName + " done."); + } +} + +public class ExecutorServiceExample { + public static void main(String[] args) { + ExecutorService executorService = Executors.newFixedThreadPool(3); + + for (int i = 1; i <= 5; i++) { + executorService.execute(new PrintTask("Task " + i)); + } + + executorService.shutdown(); + } +} +``` + +**Output:** + +```java +Task 1 started. +Task 2 started. +Task 3 started. +Task 4 started. +Task 5 started. +Task 1 done. +Task 2 done. +Task 3 done. +Task 4 done. +Task 5 done. +``` + +--- + +## Section 28: Introduction to Exception Handling in Java + +### Step 01 - Introduction to Exception Handling - Your Thought Process during Exceptions + +#### Snippet-1 : Exception Condition + +ExceptionHandlingRunner.java + +```java + + package com.in28minutes.exceptionhandling; + + public class ExceptionHandlingRunner { + public static void main(String[] args) { + callMethod(); + System.out.println("callMethod Done"); + } + + static void callMethod() { + String str = null; + int len = str.length(); + System.out.println("String Length Done"); + } + } +``` + +#### Console Output + +```java +java.lang.NullPointerException + +Exception in thread "main" java.lang.NullPointerException + +at com.in28minutes.exceptionhandling.ExceptionHandlingRunner.callMethod (ExceptionHandlingRunner.java:8) + +at com.in28minutes.exceptionhandling.ExceptionHandlingRunner.main (ExceptionHandlingRunner.java:4) +``` + + +#### Snippet-01 Explained + +A java.lang.NullPointerException is thrown by the Java run-time when we called length() on the null reference. + +If an exception is not handled in the entire call chain, including main, the exception is thrown out and the program terminates. + +System.out.println() statements after the exception are never executed. + +The runtime prints the call stack trace onto the console. + +For instance, consider this simple class Test: + +```java + public class Test { + public static void main(String[] args) { + callOne(); + } + + public static void callOne() { + callTwo(); + } + + public static void callTwo() { + callThree(); + } + + public static void callThree() { + String name; + System.out.println("This name is %d characters long", name.length()); + } + } +``` + +However, the code name.length() used in callThree() caused a NullPointerException to be thrown. + +However, this is not handled, and the console coughs up the following display: + +```java +Exception in thread "main" java.lang.NullPointerException + +at Test.callThree(Test.java:13) + +at Test.callTwo(Test.java:9) + +at Test.callOne(Test.java:6) + +at Test.main(Test.java:3) +``` + +This is nothing but a call trace of the stack, frozen in time. + +--- + +### Step 14 - Exception Handling - Conclusion with Best Practices + +In this section, we covered **exception handling** in Java, focusing on best practices derived from extensive real-world experience. + +Effective exception handling is crucial for building robust applications. This conclusion summarizes key practices that can help in writing better exception handling code. + +### Best Practices for Exception Handling + +### 1. **Never Hide Exceptions** + +- Always log the full **stack trace** of an exception. The stack trace provides invaluable information about where the exception occurred, which is crucial for debugging. + +- Avoid catching an exception and failing to provide the necessary information for someone to trace the problem later. + +### 2. **Do Not Use Exceptions for Flow Control** + +- Avoid using exceptions as a substitute for regular conditional logic (e.g., `if-else` statements). + +- Exceptions are meant to handle **error conditions**, not to control the flow of a program. + +- Exception handling is expensive in terms of resources. Using it as a flow control mechanism can degrade performance. + +### 3. **Consider the End User** + +- Always think about what the **end user** sees when an exception occurs. + +- The user should see a **friendly error message** that indicates what went wrong and what they can do about it, if possible. + +- End users should not see technical details such as stack traces. These are meant for the **support team** or **developers**. + +### 4. **Think About the Support Team** + +- When handling exceptions, ensure you log enough **information** for the support team to debug the issue. + +- Logs should provide the **context**, stack trace, and any relevant details that can help the support team reproduce and fix the issue. + +### 5. **Consider the Calling Method** + +- When throwing exceptions, think about what the **calling method** can do with the exception. + +- If there is nothing meaningful that the calling method can do, consider making the exception a **RuntimeException** (unchecked). + +- **Checked exceptions** should only be used when the caller can potentially handle the exception meaningfully. + +### 6. **Use Global Exception Handling** + +- Ensure that your application has a **global exception handler** to catch any uncaught exceptions. + +- For example, in a console application, make sure the main method handles all exceptions gracefully. + +- In web applications, implement a global exception handler to catch and handle all exceptions centrally, ensuring that no technical details are exposed to the end user. + +### Additional Coding Exercises: + +### Exercise 1: Exception Handling in Currency Addition + +**Objective:** Implement exception handling when trying to add two amounts of different currencies. Use both checked and unchecked exceptions. + +**Instructions:** + +1. Create a class `CurrencyMismatchException` that extends `RuntimeException`. + +2. Create a class `Amount` with the following: + - Fields: `String currency` and `int amount`. + - A method `add(Amount that)` that: + - Throws `CurrencyMismatchException` if the currencies do not match. + - Adds the amounts if the currencies match. + +3. Create a class `CurrencyTest` with a `main` method that: + - Instantiates two `Amount` objects with different currencies. + - Calls the `add()` method and handles the exception by printing a meaningful message. + +**Code:** + +```java +// CurrencyMismatchException.java +public class CurrencyMismatchException extends RuntimeException { + public CurrencyMismatchException(String message) { + super(message); + } +} + +// Amount.java +public class Amount { + private String currency; + private int amount; + + public Amount(String currency, int amount) { + this.currency = currency; + this.amount = amount; + } + + public String getCurrency() { + return currency; + } + + public int getAmount() { + return amount; + } + + public Amount add(Amount that) { + if (!this.currency.equals(that.currency)) { + throw new CurrencyMismatchException("Currency mismatch: Cannot add " + this.amount + " " + this.currency + " and " + that.amount + " " + that.currency); + } + return new Amount(this.currency, this.amount + that.amount); + } +} + +// CurrencyTest.java +public class CurrencyTest { + public static void main(String[] args) { + Amount usdAmount = new Amount("USD", 10); + Amount eurAmount = new Amount("EUR", 20); + + try { + Amount totalAmount = usdAmount.add(eurAmount); + System.out.println("Total Amount: " + totalAmount.getAmount() + " " + totalAmount.getCurrency()); + } catch (CurrencyMismatchException e) { + System.out.println(e.getMessage()); + } + } +} +``` + +**Output:** + +```java +Currency mismatch: Cannot add 10 USD and 20 EUR +``` + +### Exercise 2: Throwing Custom Exceptions + +**Objective:** Create and use a custom checked exception when trying to add two amounts of different currencies. + +**Instructions:** +1. Define a class `CurrencyMismatchException` that extends `Exception`. + +2. Create a class `Amount` with the following: + - Fields: `String currency` and `int amount`. + - A method `add(Amount that)` that: + - Throws `CurrencyMismatchException` if the currencies do not match. + - Adds the amounts if they match. + +3. Create a class `AmountTester` with a `main` method that: + - Instantiates two `Amount` objects with different currencies. + - Calls the `add()` method and handles the `CurrencyMismatchException` with a try-catch block. + - Prints a stack trace of the exception. + +**Code:** + +```java +// CurrencyMismatchException.java +public class CurrencyMismatchException extends Exception { + public CurrencyMismatchException(String message) { + super(message); + } +} + +// Amount.java +public class Amount { + private String currency; + private int amount; + + public Amount(String currency, int amount) { + this.currency = currency; + this.amount = amount; + } + + public String getCurrency() { + return currency; + } + + public int getAmount() { + return amount; + } + + public Amount add(Amount that) throws CurrencyMismatchException { + if (!this.currency.equals(that.currency)) { + throw new CurrencyMismatchException("Currencies Don't Match: " + this.currency + " & " + that.currency); + } + return new Amount(this.currency, this.amount + that.amount); + } +} + +// AmountTester.java +public class AmountTester { + public static void main(String[] args) { + Amount usdAmount = new Amount("USD", 10); + Amount eurAmount = new Amount("EUR", 20); + + try { + Amount totalAmount = usdAmount.add(eurAmount); + System.out.println("Total Amount: " + totalAmount.getAmount() + " " + totalAmount.getCurrency()); + } catch (CurrencyMismatchException e) { + e.printStackTrace(); + } + } +} +``` + +**Output:** + +```java +Exception in thread "main" CurrencyMismatchException: Currencies Don't Match: USD & EUR + at Amount.add(Amount.java:12) + at AmountTester.main(AmountTester.java:15) +``` + +--- + +## Section 29: Files and Directories in Java + +### Step 05 - Files - Conclusion + +In this section, we explored various operations related to **files and directories** in Java. + +We focused on modern file handling techniques using features introduced in Java 7 and Java 8, specifically from the **Java New I/O (NIO)** package. + +This section provided a practical overview of how to interact with files efficiently using the latest APIs and functional programming techniques. + +### 1. **Listing Files in a Directory** + +- We started by learning how to **list files** within a specific directory. + +- We also explored how to **recursively** traverse through all files in nested directories. + +- Filtering files based on attributes, such as file type or size, was demonstrated. + +### 2. **Finding Files with Filters** + +- We used the **Find()** method to apply filters when searching for files. + +- These filters allowed us to search based on attributes like whether the path is a directory, file size, etc. + +### 3. **Reading File Content** + +- We learned how to **read the content** of a file using `readAllLines()`. However, for large files, this approach can be inefficient as it loads all lines into memory. + +- We introduced the more efficient **Files.lines()** method, which returns a **Stream** of lines, allowing for efficient processing of large files with operations like `map()` and `filter()`. + +### 4. **Writing to a File** + +- We also covered how to **write content** to a file, demonstrating how to take data and save it to a file efficiently. + +### Java NIO and Functional Programming Features + +This section primarily used features introduced in **Java 7 (NIO)** and **Java 8**: + +- **Java NIO (New I/O)** package (`java.nio.file`), which provides better scalability and functionality for file operations. + +- **Streams**: We used `Files.lines()` to read large files as streams. + +- **Lambda expressions** and **Predicates**: These functional programming techniques were utilized for filtering and processing file content efficiently. + +### Additional Coding Exercises: + +### Exercise 1: Count Lines in a File + +### Objective: +Write a Java program that reads a text file and counts the total number of lines in it. This exercise helps understand how to read files and perform operations on the data. + +#### File: `LineCountRunner.java` + +```java +package com.in28minutes.files; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.io.IOException; + +public class LineCountRunner { + public static void main(String[] args) throws IOException { + // Specify the path of the file to read + Path pathFileToRead = Paths.get("./resources/data.txt"); + + // Use Files.lines to create a stream of lines from the file + long lineCount = Files.lines(pathFileToRead).count(); + + // Output the total number of lines + System.out.println("Total number of lines: " + lineCount); + } +} +``` + +#### Explanation: +- **Package Declaration**: The class is part of the `com.in28minutes.files` package. + +- **Imports**: The program imports necessary classes from the `java.nio.file` and `java.io` packages to handle file operations. +- **Path Creation**: The `Paths.get` method is used to create a `Path` object representing the file `data.txt`. +- **Line Counting**: The `Files.lines` method reads all lines from the file as a stream, and the `count()` method counts the number of lines in that stream. +- **Output**: The result is printed to the console. + +#### Output: + +```java +Total number of lines: 5 +``` + +### Exercise 2: Append Text to a File + +#### Objective: +Write a Java program that appends a line of text to an existing text file. This exercise demonstrates how to modify files by adding content. + +#### File: `FileAppendRunner.java` + +```java +package com.in28minutes.files; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.io.IOException; +import java.util.List; + +public class FileAppendRunner { + public static void main(String[] args) throws IOException { + // Specify the path of the file to append to + Path pathFileToAppend = Paths.get("./resources/data.txt"); + + // Create a list of new lines to append + List newLines = List.of("Dog", "Elephant"); + + // Use Files.write with StandardOpenOption.APPEND to add new lines to the file + Files.write(pathFileToAppend, newLines, java.nio.file.StandardOpenOption.APPEND); + + // Output confirmation message + System.out.println("New lines appended to the file."); + } +} +``` + +#### Explanation: + +- **Package Declaration**: The class is part of the `com.in28minutes.files` package. + +- **Imports**: The program imports necessary classes from the `java.nio.file` and `java.io` packages. + +- **Path Creation**: The `Paths.get` method is used to create a `Path` object representing the file `data.txt`. + +- **New Lines Creation**: A list of new lines (`Dog` and `Elephant`) is created using `List.of()`. + +- **Appending Lines**: The `Files.write` method is called with the `StandardOpenOption.APPEND` option, which appends the new lines to the existing content in the file. + +- **Output**: A confirmation message is printed to the console. + + +```java +New lines appended to the file. +``` + +--- + +## Section 30: More Concurrency with Concurrent Collections and Atomic Operations + +### Step 09 - Conclusion + +In this section, we explored the concept of **concurrency** in Java. + +The focus was on understanding how to manage shared resources in a multithreaded environment while ensuring thread safety. + +We covered a range of tools and techniques, starting with `synchronized` blocks, moving to locks, and then exploring more advanced concurrency utilities like **Atomic classes** and **Concurrent Collections**. + +### 1. **Synchronized Blocks** + +- We began by using the `synchronized` keyword to control access to shared resources. + +- While synchronization ensures thread safety, we discussed the **disadvantages** such as performance overhead due to contention between threads. + +### 2. **BiCounter with Locks** + +- To address the limitations of `synchronized`, we introduced the concept of **locks**. + +- We implemented a **BiCounter** using `Lock` objects, which provided more fine-grained control over synchronization, allowing greater flexibility. + +### 3. **Atomic Classes** + +- We explored **AtomicInteger**, which provides **atomic operations** without the need for explicit locking. + +- These atomic classes internally use low-level synchronization, ensuring thread safety for operations like `incrementAndGet()`, `compareAndSet()`, etc. + +- Other atomic classes such as **AtomicLong** were also introduced for handling atomic operations on long data types. + +### 4. **Concurrent Collections** + +We moved from atomic classes to exploring **concurrent collections**, which provide built-in thread-safe implementations of commonly used collections. + +#### a. **ConcurrentMap and ConcurrentHashMap** + +- We looked at **ConcurrentHashMap**, a thread-safe version of `HashMap` that splits the map into regions (segments), each of which can be locked independently, promoting higher concurrency. + +- This reduces contention and enhances **performance** when multiple threads access the map simultaneously. + +- We also explored **atomic operations** on concurrent collections, like `computeIfAbsent()`. + +#### b. **CopyOnWriteArrayList** + +- **CopyOnWriteArrayList** is another concurrent collection designed for scenarios with **many reads and few writes**. + +- It synchronizes only during write operations by creating a new copy of the list whenever a modification is made. This avoids the need to lock during read operations, improving performance for read-heavy workloads. + +### Additional Coding Exercises: + +### Exercise 1: Implementing a Thread-Safe Counter + +**Objective**: Create a thread-safe counter using the `synchronized` keyword. + +#### Instructions: +1. Create a class `ThreadSafeCounter` with the following: + - A private integer variable `counter`. + - A method `increment()` that increases `counter` by 1. + - A method `getCounter()` that returns the current value of `counter`. + +2. Create a `Main` class to test `ThreadSafeCounter`: + - Create multiple threads that call the `increment()` method. + - After all threads have finished executing, print the final value of the counter. + +#### Solution: + +```java +class ThreadSafeCounter { + private int counter = 0; + + public synchronized void increment() { + counter++; + } + + public synchronized int getCounter() { + return counter; + } +} + +public class Main { + public static void main(String[] args) throws InterruptedException { + ThreadSafeCounter counter = new ThreadSafeCounter(); + Thread[] threads = new Thread[10]; + + for (int i = 0; i < 10; i++) { + threads[i] = new Thread(() -> { + for (int j = 0; j < 1000; j++) { + counter.increment(); + } + }); + threads[i].start(); + } + + for (Thread thread : threads) { + thread.join(); + } + + System.out.println("Final counter value: " + counter.getCounter()); + } +} +``` + +#### Explanation: + +- **ThreadSafeCounter Class**: + - It has a private integer variable `counter` initialized to 0. + - The `increment()` method is synchronized to ensure that only one thread can execute it at a time, preventing race conditions. + - The `getCounter()` method is also synchronized to provide the current value of `counter` safely. + +- **Main Class**: + - We create an array of 10 threads, each of which increments the counter 1000 times. + - The `join()` method is used to wait for all threads to finish execution before printing the final counter value. + +#### Output: + +```java +Final counter value: 10000 +``` + +### Exercise 2: Using `ConcurrentHashMap` + +**Objective**: Create a simple word frequency counter using `ConcurrentHashMap`. + +#### Instructions: + +1. Create a class `WordFrequencyCounter` with the following: + - A `ConcurrentHashMap` to store words and their frequencies. + - A method `addWord(String word)` that increments the count for the word in the map. + - A method `getFrequency(String word)` that returns the frequency of the word. + +2. Create a `Main` class to test `WordFrequencyCounter`: + + - Create multiple threads that add words to the counter. + - After all threads have finished executing, print the frequencies of specific words. + +#### Solution: +```java +import java.util.concurrent.ConcurrentHashMap; + +class WordFrequencyCounter { + private ConcurrentHashMap wordCounts = new ConcurrentHashMap<>(); + + public void addWord(String word) { + wordCounts.merge(word, 1, Integer::sum); + } + + public int getFrequency(String word) { + return wordCounts.getOrDefault(word, 0); + } +} + +public class Main { + public static void main(String[] args) throws InterruptedException { + WordFrequencyCounter counter = new WordFrequencyCounter(); + String[] words = {"apple", "banana", "apple", "orange", "banana", "banana"}; + + Thread[] threads = new Thread[words.length]; + + for (int i = 0; i < words.length; i++) { + final String word = words[i]; + threads[i] = new Thread(() -> { + counter.addWord(word); + }); + threads[i].start(); + } + + for (Thread thread : threads) { + thread.join(); + } + + System.out.println("Frequency of 'apple': " + counter.getFrequency("apple")); + System.out.println("Frequency of 'banana': " + counter.getFrequency("banana")); + System.out.println("Frequency of 'orange': " + counter.getFrequency("orange")); + } +} +``` + +#### Explanation: + +- **WordFrequencyCounter Class**: + + - It uses `ConcurrentHashMap` to store word frequencies, allowing multiple threads to safely modify it concurrently. + + - The `addWord(String word)` method uses the `merge` function to increment the count of a word or add it if it doesn't exist. + - The `getFrequency(String word)` method retrieves the frequency of a word, returning 0 if the word is not found. + +- **Main Class**: + - We create an array of strings with words. Multiple threads are created to add words concurrently. + + - The `join()` method is used to wait for all threads to finish before printing the frequencies. + +#### Output: +``` +Frequency of 'apple': 2 +Frequency of 'banana': 3 +Frequency of 'orange': 1 +``` --- ## Section 31: Java Tips -> **Note**: Section-31 is not present in GitHub repo. +> **Note**: Section-31 info here. --- ## Section 34: Java New Features - Java 10 to Java 16 -> **Note**: Section-34 is not present in GitHub repo. +> **Note**: Section-34 info here. --- From fcaf39f664d8a8f72c091ecf32e88ecb4205d325 Mon Sep 17 00:00:00 2001 From: Hafeezbaig Date: Mon, 21 Oct 2024 06:32:37 +0530 Subject: [PATCH 4/6] additional documentation updated - 1 --- additional-documentation.md | 1105 +++++++++++++++++++++++++++++++++++ missing-info.md | 331 +---------- 2 files changed, 1107 insertions(+), 329 deletions(-) create mode 100644 additional-documentation.md diff --git a/additional-documentation.md b/additional-documentation.md new file mode 100644 index 00000000..6f652e8b --- /dev/null +++ b/additional-documentation.md @@ -0,0 +1,1105 @@ +## Section 5: Introduction to Java Platform + +#### **Group 1: Steps 01 and 07** +- **Step 01 - Overview Of Java Platform - An Introduction** +- **Step 07 - JDK vs JRE vs JVM** + +**Why Grouped:** +Both steps provide an overview of Java, covering the foundational concepts of the platform, including bytecode, the Java Virtual Machine (JVM), and the distinctions between the JDK, JRE, and JVM. + +### **Puzzle:** (OPTIONAL) +- Write a simple explanation of how Java achieves platform independence using bytecode and the JVM. + +- Can you describe what happens from the moment you compile a Java program to when it is run on a specific operating system? + +### **Quiz Questions:** +1. **What is bytecode?** + - A) Machine code for Windows + - B) Code that runs directly on a CPU + - C) An intermediate representation understood by the JVM (Answer: C) + +2. **What does the JDK contain that the JRE does not?** + - A) Debugging tools and the compiler (Answer: A) + - B) The JVM + - C) Java libraries + +3. **Which component is responsible for converting bytecode to machine-specific instructions?** + - A) JDK + - B) JVM (Answer: B) + - C) Compiler + +### **Fun Fact:** +- **Did you know?** Java was originally developed by James Gosling at Sun Microsystems and was initially called "Oak" after an oak tree that stood outside Gosling's office. It was later renamed to "Java" after the Indonesian coffee. + +--- + +#### **Group 2: Steps 02, 03, 04, 05, and 06** +- **Step 02 - Java Class and Object - First Look** +- **Step 03 - Create a Method in a Java Class** +- **Step 04 - Create and Compile Planet.java Class** +- **Step 05 - Run Planet Class with Java - Using a main method** +- **Step 06 - Play and Learn with Planet Class** + +**Why Grouped:** +These steps introduce learners to creating a basic Java class (`Planet`), adding methods, compiling the code, running it with the `main()` method, and experimenting with the class. These topics flow logically as they guide learners through hands-on programming with Java. + +### **Puzzle 1: Creating a Class and Objects** +- Create a class called `Planet` with a method `revolve()` that prints "Revolving around the sun." Instantiate two objects, `earth` and `mars`, and call the `revolve()` method for both objects. + +**Code Snippet:** +```java +class Planet { + void revolve() { + System.out.println("Revolving around the sun."); + } +} + +public class Main { + public static void main(String[] args) { + Planet earth = new Planet(); + Planet mars = new Planet(); + earth.revolve(); + mars.revolve(); + } +} +``` + +**Expected Output:** +``` +Revolving around the sun. +Revolving around the sun. +``` + +### **Puzzle 2: Add Properties to the Planet Class** +- Extend the `Planet` class to have two properties: `name` and `diameter`. Write a method `displayInfo()` that prints the name and diameter of the planet. Create instances for Earth and Mars with appropriate data. + +**Code Snippet:** +```java +class Planet { + String name; + double diameter; + + Planet(String name, double diameter) { + this.name = name; + this.diameter = diameter; + } + + void displayInfo() { + System.out.println(name + " has a diameter of " + diameter + " kilometers."); + } +} + +public class Main { + public static void main(String[] args) { + Planet earth = new Planet("Earth", 12742); + Planet mars = new Planet("Mars", 6779); + earth.displayInfo(); + mars.displayInfo(); + } +} +``` + +**Expected Output:** +``` +Earth has a diameter of 12742 kilometers. +Mars has a diameter of 6779 kilometers. +``` + +### **Quiz Questions:** + +1. **What is a Java class?** + - A) A template for creating objects (Answer: A) + - B) A block of code that runs methods + - C) A part of the JVM + +2. **How do you create an object in Java?** + - A) Using the `new` keyword (Answer: A) + - B) Using the `class` keyword + - C) By declaring an array + +3. **What is the purpose of the `main()` method?** + - A) It compiles the program. + - B) It is the entry point of the program (Answer: B). + - C) It defines the class. + +### **Fun Fact:** +- **Did you know?** The Java `main()` method is always `public static void main(String[] args)`, and if it's not written exactly like this, Java won't recognize it as the entry point of the program. + +--- + +### Additional Coding Exercises: + + +### **Exercise 1: Exploring Java Platform Components** + +**Objective**: Understanding the role of the JVM, JRE, and JDK through a practical scenario. + +#### Scenario: +You have written a simple Java program `Greeting.java` that prints "Hello, World!" to the console. You want to share this program with two different friends: + +1. **Friend A** only has the JRE installed. + +2. **Friend B** has the JDK installed. + +**Tasks**: + +1. Explain what each friend needs to do to run your program. + +2. For **Friend A**, you should provide the compiled bytecode (`Greeting.class`), explain why this is necessary, and describe how they can run the program with the JRE. + +3. For **Friend B**, explain the steps they need to follow, starting with the source file (`Greeting.java`), and show how they can compile and run the program using the JDK. + +#### Sample Code for `Greeting.java`: + +```java +public class Greeting { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +} +``` + +#### Expected Outcome: +- Learners should be able to describe the differences between the JRE and JDK and how each is used in different contexts (running bytecode vs. compiling and running source code). + +- They should know how to compile a Java program with the JDK using `javac` and run it using `java`, and explain why the JRE alone is sufficient to run pre-compiled bytecode. + +--- + +### **Exercise 2: Creating and Compiling a Class with a Method** + +**Objective**: Writing and compiling Java code outside of JShell, understanding the use of the `javac` and `java` commands. + +#### Tasks: + +1. Write a Java class named `Car` in a file called `Car.java`. The class should have the following features: + + - A method `start()` that prints `"The car has started."`. + + - A method `stop()` that prints `"The car has stopped."`. + +2. Add a `main` method to the class, where you create an instance of `Car` and call both `start()` and `stop()`. + +3. Compile your `Car.java` file using the `javac` command. + +4. Run the compiled class using the `java` command. + +#### Code for `Car.java`: + +```java +public class Car { + void start() { + System.out.println("The car has started."); + } + + void stop() { + System.out.println("The car has stopped."); + } + + public static void main(String[] args) { + Car myCar = new Car(); + myCar.start(); + myCar.stop(); + } +} +``` + +#### Expected Outcome: + +- The learners will write a basic Java class with methods and a `main` method to execute it. + +- They will compile the code using `javac` and understand how the `.class` file is generated. + +- They will run the compiled bytecode using `java Car`, reinforcing the steps of compiling and running a Java program outside of JShell. + +--- + +## Section 9: Introduction To Java Object Oriented Programming + +#### **Group 1: Steps 01, 02, and 03** + +- **Step 01 - Introduction to Object Oriented Programming - Basics** +- **Step 02 - Introduction to Object Oriented Programming - Terminology - Class, Object** +- **Step 03 - Introduction to Object Oriented Programming - Exercise - Online Shopping** + +**Why Grouped**: These lectures provide an introduction to Object-Oriented Programming (OOP) concepts, including the basics, terminology, and a practical exercise on online shopping. + +### **Puzzle: Define a Class for an Online Shopping Item** + +**Problem:** +Create a class called `Item` that represents an item in an online shopping system. + +- The `Item` class should have properties like `name`, `price`, and `quantity`. + +- Write a method to display the details of the item, including the total cost (`price * quantity`). + +**Explanation:** + +1. **Define the Class and Properties:** + The `Item` class will have `name` (String), `price` (double), and `quantity` (int) properties. + + Example: + ```java + class Item { + String name; + double price; + int quantity; + } + ``` + +2. **Constructor for Initialization:** + The constructor will initialize the values for these properties. + + Example: + ```java + Item(String name, double price, int quantity) { + this.name = name; + this.price = price; + this.quantity = quantity; + } + ``` + +3. **Method to Display Item Details:** + A `displayItemDetails()` method will print the name, price, and total cost (price * quantity). + + Example: + ```java + void displayItemDetails() { + double totalCost = price * quantity; + System.out.println("Item: " + name + ", Price: " + price + ", Quantity: " + quantity + ", Total Cost: " + totalCost); + } + ``` + +4. **Create Objects and Call the Method:** + Create instances of `Item` and call `displayItemDetails()` to show details. + + Example: + ```java + public class Main { + public static void main(String[] args) { + Item phone = new Item("Phone", 299.99, 2); + phone.displayItemDetails(); + } + } + ``` + +**Output:** + +```java +Item: Phone, Price: 299.99, Quantity: 2, Total Cost: 599.98 +``` + +### **Quiz Questions:** + +1. **What is the key concept behind Object-Oriented Programming (OOP)?** + - A) Procedural coding + - B) Organizing code around objects and classes (Answer: B) + - C) Structured programming + +2. **What does a class define in OOP?** + - A) Only methods + - B) Attributes and actions (Answer: B) + - C) Objects + +### **Fun Fact:** +- **Did you know?** Java is one of the most widely used Object-Oriented Programming languages, and OOP helps manage large and complex applications by organizing code into reusable objects. + +--- + +#### **Group 2: Steps 04, 05, and 06** + +- **Step 04 - Create Motor Bike Java Class and a couple of objects** +- **Step 05 - Exercise Solutions - Book class and Three instances** +- **Step 06 - Introducing State of an object with speed variable** + +**Why Grouped**: These lectures cover practical exercises and examples (Motor Bike and Book classes), focusing on creating objects and introducing state with variables. + + +### **Puzzle 1: MotorBike Class with Speed** + +**Problem:** +Create a class `MotorBike` with a variable `speed`. Write methods to get and set the speed. + +- Create two objects: `ducati` and `honda`, with different speeds. Then, print out the speeds of both bikes. + +**Explanation:** + +1. **Define the Class:** + Define the `MotorBike` class with the `speed` property. + + Example: + ```java + class MotorBike { + int speed; + } + ``` + +2. **Get and Set Methods:** + Write methods to get and set the speed. + + Example: + ```java + void setSpeed(int speed) { + this.speed = speed; + } + + int getSpeed() { + return this.speed; + } + ``` + +3. **Create Objects and Set Speeds:** + Create two instances of `MotorBike` and set their speeds. + + Example: + ```java + public class Main { + public static void main(String[] args) { + MotorBike ducati = new MotorBike(); + MotorBike honda = new MotorBike(); + + ducati.setSpeed(100); + honda.setSpeed(80); + + System.out.println("Ducati speed: " + ducati.getSpeed()); + System.out.println("Honda speed: " + honda.getSpeed()); + } + } + ``` + +**Output:** + +```java +Ducati speed: 100 +Honda speed: 80 +``` + +--- + +### **Puzzle 2: Create a Book Class and Instances** + +**Problem:** +Create a class `Book` with attributes `title`, `author`, and `noOfCopies`. Write a method to display the book’s details. + +- Create three instances: `Art of Computer Programming`, `Effective Java`, and `Clean Code`. + +**Explanation:** + +1. **Step 1: Define the Class and Attributes:** + The `Book` class will have `title`, `author`, and `noOfCopies`. + + Example: + ```java + class Book { + String title; + String author; + int noOfCopies; + } + ``` + +2. **Step 2: Constructor and Method to Display Book Details:** + Add a constructor and a method to display details. + + Example: + ```java + Book(String title, String author, int noOfCopies) { + this.title = title; + this.author = author; + this.noOfCopies = noOfCopies; + } + + void displayBookDetails() { + System.out.println(title + " by " + author + " has " + noOfCopies + " copies."); + } + ``` + +3. **Step 3: Create Objects and Display Details:** + Create three `Book` objects and display their details. + + Example: + ```java + public class Main { + public static void main(String[] args) { + Book book1 = new Book("Art of Computer Programming", "Donald Knuth", 1000); + Book book2 = new Book("Effective Java", "Joshua Bloch", 500); + Book book3 = new Book("Clean Code", "Robert Martin", 300); + + book1.displayBookDetails(); + book2.displayBookDetails(); + book3.displayBookDetails(); + } + } + ``` + +**Output:** + +```java +Art of Computer Programming by Donald Knuth has 1000 copies. +Effective Java by Joshua Bloch has 500 copies. +Clean Code by Robert Martin has 300 copies. +``` + +### **Quiz Questions:** + +1. **What does the `setSpeed()` method in the MotorBike class do?** + - A) Sets the speed of the bike (Answer: A) + - B) Starts the bike + - C) Increases speed automatically + +2. **What is the purpose of instance variables in OOP?** + - A) To store state data for each object (Answer: A) + - B) To execute methods + - C) To call constructors + +### **Fun Fact:** +- **Did you know?** Each object in Java has its own **state** (stored in instance variables) and **behavior** (defined by methods), which is why each `MotorBike` or `Book` object can have its own unique values. + +--- + +#### **Group 3: Steps 07, 08, and 09** + +- **Step 07 - Understanding basics of Encapsulation with Setter methods** +- **Step 08 - Exercises and Tips - Getters and Generating Getters and Setters with Eclipse** +- **Step 09 - Puzzles on this and initialization of member variables** + +**Why Grouped**: These lectures introduce the concept of encapsulation and provide exercises and puzzles related to using getters and setters. + +### **Puzzle: Encapsulation with Speed and Validation** + +**Problem:** +Modify the `MotorBike` class to use **encapsulation**. Make the `speed` variable private and provide getter and setter methods. Ensure the setter method does not allow negative speeds. + +**Explanation:** + +1. **Encapsulate the Speed Property:** + Make the `speed` variable private. + + Example: + ```java + private int speed; + ``` + +2. **Create Getters and Setters with Validation:** + Create getter and setter methods. The setter should only allow non-negative values for speed. + + Example: + ```java + void setSpeed(int speed) { + if (speed >= 0) { + this.speed = speed; + } + } + + int getSpeed() { + return this.speed; + } + ``` + +3. **Create Objects and Test the Validation:** + Create `MotorBike` objects, set their speeds, and attempt to set a negative speed (which should be ignored). + + Example: + ```java + public class Main { + public static void main(String[] args) { + MotorBike ducati = new MotorBike(); + ducati.setSpeed(100); + ducati.setSpeed + + (-50); // This should be ignored + + System.out.println("Ducati speed: " + ducati.getSpeed()); // Output should be 100 + } + } + ``` + +**Output:** + +```java +Ducati speed: 100 +``` + +### **Quiz Questions:** + +1. **What is encapsulation in Java?** + - A) Hiding implementation details (Answer: A) + - B) Making all variables public + - C) Creating multiple objects + +2. **What does the getter method do?** + - A) Retrieves the value of a variable (Answer: A) + - B) Changes the value of a variable + - C) Deletes a variable + +### **Fun Fact:** + +- **Did you know?** Encapsulation is a way to protect data in a class by restricting direct access to it and using controlled methods (getters and setters) for modification. + +--- + +#### **Group 4: Steps 10, 11, and 12** + +- **Step 10 - First Advantage of Encapsulation** +- **Step 11 - Introduction to Encapsulation - Level 2** +- **Step 12 - Encapsulation Exercises - Better Validation and Book class** + +**Why Grouped:** These steps explore **encapsulation** in more depth, focusing on its advantages and how better validation can be achieved by using it. + +### **Puzzle 1: Book Class with Price Validation** + +**Problem:** +Create a class `Book` with private properties `title`, `author`, and `price`. Use getter and setter methods to access these properties, but ensure the `price` cannot be negative. + +- Create a few instances of the `Book` class and test the validation. + +**Explanation:** + +1. **Private Properties:** + Make the `title`, `author`, and `price` variables private to ensure encapsulation. + + Example: + ```java + class Book { + private String title; + private String author; + private double price; + } + ``` + +2. **Getters and Setters with Validation:** + Write getter and setter methods. The setter for `price` will ensure that it does not accept negative values. + + Example: + ```java + void setPrice(double price) { + if (price >= 0) { + this.price = price; + } + } + + double getPrice() { + return price; + } + ``` + +3. **Create and Test Book Objects:** + Create instances of the `Book` class and test setting the `price`. Try setting both valid and invalid prices to see the validation in action. + + Example: + ```java + public class Main { + public static void main(String[] args) { + Book book1 = new Book(); + book1.setPrice(20); + book1.setPrice(-5); // This should be ignored + + System.out.println("Book price: " + book1.getPrice()); // Should display 20 + } + } + ``` + +**Output:** + +```java +Book price: 20.0 +``` + +--- + +### **Puzzle 2: Better Validation with Book Class** + +**Problem:** +Extend the `Book` class to add a new private property `numberOfPages`. + +- Add a setter for `numberOfPages` that ensures the value must be greater than zero. + +- Create a few book instances and validate the number of pages. + +**Explanation:** + +1. **Add `numberOfPages` Property:** + Make `numberOfPages` private and ensure encapsulation. + + Example: + ```java + private int numberOfPages; + ``` + +2. **Setter with Validation:** + The setter for `numberOfPages` will validate that the number must be greater than zero. + + Example: + ```java + void setNumberOfPages(int numberOfPages) { + if (numberOfPages > 0) { + this.numberOfPages = numberOfPages; + } + } + + int getNumberOfPages() { + return numberOfPages; + } + ``` + +3. **Test Validation:** + Test the validation by creating instances of the `Book` class and setting valid and invalid values for `numberOfPages`. + + Example: + ```java + public class Main { + public static void main(String[] args) { + Book book2 = new Book(); + book2.setNumberOfPages(100); + book2.setNumberOfPages(-10); // This should be ignored + + System.out.println("Number of pages: " + book2.getNumberOfPages()); // Should display 100 + } + } + ``` + +**Output:** + +```java +Number of pages: 100 +``` + +### **Quiz Questions:** + +1. **What is the main advantage of using encapsulation?** + - A) Faster code execution + - B) Better control over data validation (Answer: B) + - C) More readable code + +2. **What does a private variable mean in Java?** + - A) The variable can only be accessed inside its class (Answer: A) + - B) The variable can be accessed by other classes + +### **Fun Fact:** + +- **Did you know?** Encapsulation is one of the key principles of OOP and helps create **safe** and **modular** code by hiding the internal workings of classes and exposing only what is necessary. + +--- + +#### **Group 5: Steps 13, 14, and 15** + +- **Step 13 - Introduction to Abstraction** +- **Step 14 - Introduction to Java Constructors** +- **Step 15 - Introduction to Java Constructors - Exercises and Puzzles** + +**Why Grouped:** These steps cover the concepts of **abstraction** and **constructors** in Java. There are exercises and puzzles related to constructors. + +Sure! Here’s the updated version of the **Puzzle 1: Abstraction with Vehicle Class** example, following the correct approach for **inner classes** and abstract classes, as we've just fixed it. + +### **Puzzle 1: Abstraction with Vehicle Class (Using Inner Classes)** + +#### **Problem:** +Create an abstract class `Vehicle` with an abstract method `move()`. + +- Inside `Vehicle`, create two inner classes `Car` and `Bicycle` that extend `Vehicle` and provide their own implementation of `move()`. + +#### **Explanation:** + +1. **Abstract Class and Method:** + - The `Vehicle` class is abstract and contains an abstract method `move()` that must be implemented by the inner classes. + + **Example:** + ```java + abstract class Vehicle { + abstract void move(); + } + ``` + +2. **Inner Classes Implementing the Abstract Method:** + - Both `Car` and `Bicycle` are inner classes of `Vehicle`, and each implements the `move()` method in its own way. + + **Example:** + ```java + class Car extends Vehicle { + void move() { + System.out.println("Car is moving on the road."); + } + } + + class Bicycle extends Vehicle { + void move() { + System.out.println("Bicycle is pedaling on the street."); + } + } + ``` + +3. **Test the Classes:** + - To test these classes, create an anonymous instance of `Vehicle` and use it to instantiate the inner classes (`Car` and `Bicycle`). Then, call the `move()` methods on each instance. + + **Example:** + ```java + public class Main { + public static void main(String[] args) { + // Create an instance of the outer Vehicle class + Vehicle vehicle = new Vehicle() { + @Override + void move() { + // This block is required but not used + } + }; + + // Use the outer class instance to create inner class objects + Vehicle.Car car = vehicle.new Car(); + Vehicle.Bicycle bicycle = vehicle.new Bicycle(); + + // Call the move method on both inner class instances + car.move(); // Output: Car is moving on the road. + bicycle.move(); // Output: Bicycle is pedaling on the street. + } + } + ``` + +4. **Output:** + ``` + Car is moving on the road. + Bicycle is pedaling on the street. + ``` + +--- + +### **Puzzle 2: Constructor in a Person Class** + +**Problem:** +Create a class `Person` with attributes `name` and `age`. Write a constructor that initializes these attributes. + +- Create instances of `Person` and print the name and age. + +**Explanation:** + +1. **Class with Constructor:** + The `Person` class will have a constructor that initializes `name` and `age`. + + Example: + ```java + class Person { + String name; + int age; + + Person(String name, int age) { + this.name = name; + this.age = age; + } + } + ``` + +2. **Create and Display `Person` Objects:** + Create two `Person` objects and display their details using the constructor. + + Example: + ```java + public class Main { + public static void main(String[] args) { + Person person1 = new Person("Alice", 25); + Person person2 = new Person("Bob", 30); + + System.out.println(person1.name + " is " + person1.age + " years old."); + System.out.println(person2.name + " is " + person2.age + " years old."); + } + } + ``` + +**Output:** + +```java +Alice is 25 years old. +Bob is 30 years old. +``` + +### **Quiz Questions:** + +1. **What is the purpose of a constructor in Java?** + - A) It defines an abstract method + - B) It initializes an object when it is created (Answer: B) + - C) It deletes the object + +2. **What is abstraction in OOP?** + - A) Hiding implementation details and exposing only essential features (Answer: A) + - B) Creating multiple objects + - C) Writing simple code + +### **Fun Fact:** + +- **Did you know?** **Abstraction** allows you to define **general behaviors** in a base class, while **specific behaviors** are left to subclasses. Constructors, on the other hand, help you initialize objects when they are created. + +--- + +#### **Group 6: Step 16** + +- **Step 16 - Introduction to Object Oriented Programming - Conclusion** + +**Why Grouped:** This step wraps up the entire OOP section, summarizing the key concepts learned. + +### **Quiz Questions:** + +1. **Which of the following is NOT one of the four pillars of OOP?** + - A) Encapsulation + - B) Abstraction + - C) Compilation (Answer: C) + +2. **What is polymorphism in OOP?** + - A) The ability of one method to behave differently based on the object (Answer: A) + - B) The inheritance of properties + - C) Writing multiple methods + +### **Fun Fact:** + +- **Did you know?** The four pillars of OOP are designed to help developers **organize, structure, and manage complex code** by providing a framework that promotes flexibility, reusability, and scalability. + +--- + +### Additional Coding Exercises: + +### **Exercise 1: Designing a Simple Banking System Using OOP** + +**Objective**: Practice designing a system with classes, encapsulation, and constructors. + +#### Tasks: + +1. **Create a class `BankAccount`** that models a simple bank account with the following attributes: + + - `accountNumber`: The account number of the bank account (private). + + - `balance`: The current balance in the account (private). + +2. **Add methods** to the `BankAccount` class: + + - `deposit(double amount)`: A method to add money to the balance. + + - `withdraw(double amount)`: A method to withdraw money from the balance. Ensure that the balance does not go below zero. + + - `getBalance()`: A method to retrieve the current balance. + +3. **Add a constructor** to the `BankAccount` class that accepts an account number and an initial balance. + +4. **Create a class `BankAccountRunner`** with the `main()` method where you: + + - Create two instances of `BankAccount` with different account numbers and initial balances. + + - Perform deposit and withdrawal operations and print the balance after each operation. + +#### Code: + +**BankAccount.java**: + +```java +public class BankAccount { + private String accountNumber; + private double balance; + + public BankAccount(String accountNumber, double balance) { + this.accountNumber = accountNumber; + this.balance = balance; + } + + public void deposit(double amount) { + if (amount > 0) { + balance += amount; + } + } + + public void withdraw(double amount) { + if (amount > 0 && amount <= balance) { + balance -= amount; + } else { + System.out.println("Insufficient balance or invalid amount."); + } + } + + public double getBalance() { + return balance; + } +} +``` + +**BankAccountRunner.java**: + +```java +public class BankAccountRunner { + public static void main(String[] args) { + BankAccount account1 = new BankAccount("12345", 1000.00); + BankAccount account2 = new BankAccount("67890", 500.00); + + account1.deposit(500.00); + account1.withdraw(200.00); + System.out.println("Account 1 Balance: " + account1.getBalance()); + + account2.deposit(300.00); + account2.withdraw(100.00); + System.out.println("Account 2 Balance: " + account2.getBalance()); + } +} +``` + +#### Output: + +```java +Account 1 Balance: 1300.0 +Account 2 Balance: 700.0 +``` + +**Explanation**: + +- Account 1 starts with a balance of 1000, then deposits 500, and withdraws 200, resulting in a balance of 1300. + +- Account 2 starts with a balance of 500, then deposits 300, and withdraws 100, resulting in a balance of 700. + +#### Expected Outcome: + +- Learners will practice using constructors to initialize objects. + +- They will reinforce the concept of **encapsulation** by using private variables and methods to interact with object state. + +- They will learn how to handle validation in methods, such as ensuring a withdrawal doesn't leave the account with a negative balance. + +--- + +### **Exercise 2: Object-Oriented Inventory Management System** +**Objective**: Practice creating multiple classes and using objects to simulate an inventory management system. + +#### Tasks: + +1. **Create a class `Product`** with the following attributes: + + - `productId`: A unique identifier for the product (private). + + - `productName`: The name of the product (private). + + - `quantity`: The quantity of the product available in stock (private). + +2. **Add methods** to the `Product` class: + + - `increaseStock(int amount)`: A method to increase the stock of a product. + + - `decreaseStock(int amount)`: A method to decrease the stock of a product. Ensure that the quantity doesn't fall below zero. + + - `getQuantity()`: A method to get the current quantity of the product. + + - `getProductName()`: A method to get the product name. + +3. **Create a class `Inventory`** to manage multiple `Product` objects. The class should: + + - Contain a list of products. + + - Have methods `addProduct(Product product)` to add a product to the inventory and `removeProduct(String productId)` to remove a product by ID. + +4. **Create a class `InventoryManager`** with the `main()` method where: + + - You create a few `Product` objects. + + - You add products to the inventory, increase and decrease stock, and display product details. + +#### Code: + +**Product.java**: + +```java +public class Product { + private String productId; + private String productName; + private int quantity; + + public Product(String productId, String productName, int quantity) { + this.productId = productId; + this.productName = productName; + this.quantity = quantity; + } + + public void increaseStock(int amount) { + if (amount > 0) { + quantity += amount; + } + } + + public void decreaseStock(int amount) { + if (amount > 0 && amount <= quantity) { + quantity -= amount; + } else { + System.out.println("Insufficient stock or invalid amount."); + } + } + + public int getQuantity() { + return quantity; + } + + public String getProductName() { + return productName; + } + + public Object getProductId() { + return null; + } +} +``` + +**Inventory.java**: + +```java +import java.util.ArrayList; + +public class Inventory { + private ArrayList products = new ArrayList<>(); + + public void addProduct(Product product) { + products.add(product); + } + + public void removeProduct(String productId) { + products.removeIf(product -> product.getProductId().equals(productId)); + } + + public void displayInventory() { + for (Product product : products) { + System.out.println("Product: " + product.getProductName() + ", Quantity: " + product.getQuantity()); + } + } +} +``` + +**InventoryManager.java**: + +```java +public class InventoryManager { + public static void main(String[] args) { + Inventory inventory = new Inventory(); + + Product laptop = new Product("101", "Laptop", 10); + Product smartphone = new Product("102", "Smartphone", 20); + + inventory.addProduct(laptop); + inventory.addProduct(smartphone); + + laptop.increaseStock(5); + smartphone.decreaseStock(10); + + inventory.displayInventory(); + } +} +``` + +Output: + +```java +Product: Laptop, Quantity: 15 +Product: Smartphone, Quantity: 10 +``` + +**Explanation**: + +- The Laptop starts with a quantity of 10, and after increasing the stock by 5, its new quantity is 15. + +- The Smartphone starts with a quantity of 20, and after decreasing the stock by 10, its new quantity is 10. + +#### Expected Outcome: + +- Learners will practice object-oriented design by managing relationships between multiple classes (Inventory and Product). + +- They will understand the importance of **code encapsulation** by handling inventory operations through methods. + +- They will explore concepts like managing collections of objects (`ArrayList`). + +--- diff --git a/missing-info.md b/missing-info.md index d9ecffc7..a906fb0c 100644 --- a/missing-info.md +++ b/missing-info.md @@ -427,90 +427,7 @@ This exercise reinforces how to use method arguments to allow for flexibility in ## Section 5: Introduction to Java Platform -### Additional Coding Exercises: - - -### **Exercise 1: Exploring Java Platform Components** - -**Objective**: Understanding the role of the JVM, JRE, and JDK through a practical scenario. - -#### Scenario: -You have written a simple Java program `Greeting.java` that prints "Hello, World!" to the console. You want to share this program with two different friends: - -1. **Friend A** only has the JRE installed. - -2. **Friend B** has the JDK installed. - -**Tasks**: - -1. Explain what each friend needs to do to run your program. - -2. For **Friend A**, you should provide the compiled bytecode (`Greeting.class`), explain why this is necessary, and describe how they can run the program with the JRE. - -3. For **Friend B**, explain the steps they need to follow, starting with the source file (`Greeting.java`), and show how they can compile and run the program using the JDK. - -#### Sample Code for `Greeting.java`: - -```java -public class Greeting { - public static void main(String[] args) { - System.out.println("Hello, World!"); - } -} -``` - -#### Expected Outcome: -- Learners should be able to describe the differences between the JRE and JDK and how each is used in different contexts (running bytecode vs. compiling and running source code). - -- They should know how to compile a Java program with the JDK using `javac` and run it using `java`, and explain why the JRE alone is sufficient to run pre-compiled bytecode. - ---- - -### **Exercise 2: Creating and Compiling a Class with a Method** - -**Objective**: Writing and compiling Java code outside of JShell, understanding the use of the `javac` and `java` commands. - -#### Tasks: - -1. Write a Java class named `Car` in a file called `Car.java`. The class should have the following features: - - - A method `start()` that prints `"The car has started."`. - - - A method `stop()` that prints `"The car has stopped."`. - -2. Add a `main` method to the class, where you create an instance of `Car` and call both `start()` and `stop()`. - -3. Compile your `Car.java` file using the `javac` command. - -4. Run the compiled class using the `java` command. - -#### Code for `Car.java`: - -```java -public class Car { - void start() { - System.out.println("The car has started."); - } - - void stop() { - System.out.println("The car has stopped."); - } - - public static void main(String[] args) { - Car myCar = new Car(); - myCar.start(); - myCar.stop(); - } -} -``` - -#### Expected Outcome: - -- The learners will write a basic Java class with methods and a `main` method to execute it. - -- They will compile the code using `javac` and understand how the `.class` file is generated. - -- They will run the compiled bytecode using `java Car`, reinforcing the steps of compiling and running a Java program outside of JShell. +> No content for this section --- @@ -658,251 +575,7 @@ public class MathRunner { ## Section 9: Introduction To Java Object Oriented Programming -### Additional Coding Exercises: - -### **Exercise 1: Designing a Simple Banking System Using OOP** - -**Objective**: Practice designing a system with classes, encapsulation, and constructors. - -#### Tasks: - -1. **Create a class `BankAccount`** that models a simple bank account with the following attributes: - - - `accountNumber`: The account number of the bank account (private). - - - `balance`: The current balance in the account (private). - -2. **Add methods** to the `BankAccount` class: - - - `deposit(double amount)`: A method to add money to the balance. - - - `withdraw(double amount)`: A method to withdraw money from the balance. Ensure that the balance does not go below zero. - - - `getBalance()`: A method to retrieve the current balance. - -3. **Add a constructor** to the `BankAccount` class that accepts an account number and an initial balance. - -4. **Create a class `BankAccountRunner`** with the `main()` method where you: - - - Create two instances of `BankAccount` with different account numbers and initial balances. - - - Perform deposit and withdrawal operations and print the balance after each operation. - -#### Code: - -**BankAccount.java**: -```java -public class BankAccount { - private String accountNumber; - private double balance; - - public BankAccount(String accountNumber, double balance) { - this.accountNumber = accountNumber; - this.balance = balance; - } - - public void deposit(double amount) { - if (amount > 0) { - balance += amount; - } - } - - public void withdraw(double amount) { - if (amount > 0 && amount <= balance) { - balance -= amount; - } else { - System.out.println("Insufficient balance or invalid amount."); - } - } - - public double getBalance() { - return balance; - } -} -``` - -**BankAccountRunner.java**: - -```java -public class BankAccountRunner { - public static void main(String[] args) { - BankAccount account1 = new BankAccount("12345", 1000.00); - BankAccount account2 = new BankAccount("67890", 500.00); - - account1.deposit(500.00); - account1.withdraw(200.00); - System.out.println("Account 1 Balance: " + account1.getBalance()); - - account2.deposit(300.00); - account2.withdraw(100.00); - System.out.println("Account 2 Balance: " + account2.getBalance()); - } -} -``` - -#### Output: - -```java -Account 1 Balance: 1300.0 -Account 2 Balance: 700.0 -``` - -**Explanation**: - -- Account 1 starts with a balance of 1000, then deposits 500, and withdraws 200, resulting in a balance of 1300. - -- Account 2 starts with a balance of 500, then deposits 300, and withdraws 100, resulting in a balance of 700. - -#### Expected Outcome: - -- Learners will practice using constructors to initialize objects. - -- They will reinforce the concept of **encapsulation** by using private variables and methods to interact with object state. - -- They will learn how to handle validation in methods, such as ensuring a withdrawal doesn't leave the account with a negative balance. - ---- - -### **Exercise 2: Object-Oriented Inventory Management System** -**Objective**: Practice creating multiple classes and using objects to simulate an inventory management system. - -#### Tasks: - -1. **Create a class `Product`** with the following attributes: - - - `productId`: A unique identifier for the product (private). - - - `productName`: The name of the product (private). - - - `quantity`: The quantity of the product available in stock (private). - -2. **Add methods** to the `Product` class: - - - `increaseStock(int amount)`: A method to increase the stock of a product. - - - `decreaseStock(int amount)`: A method to decrease the stock of a product. Ensure that the quantity doesn't fall below zero. - - - `getQuantity()`: A method to get the current quantity of the product. - - - `getProductName()`: A method to get the product name. - -3. **Create a class `Inventory`** to manage multiple `Product` objects. The class should: - - - Contain a list of products. - - - Have methods `addProduct(Product product)` to add a product to the inventory and `removeProduct(String productId)` to remove a product by ID. - -4. **Create a class `InventoryManager`** with the `main()` method where: - - - You create a few `Product` objects. - - - You add products to the inventory, increase and decrease stock, and display product details. - -#### Code: - -**Product.java**: - -```java -public class Product { - private String productId; - private String productName; - private int quantity; - - public Product(String productId, String productName, int quantity) { - this.productId = productId; - this.productName = productName; - this.quantity = quantity; - } - - public void increaseStock(int amount) { - if (amount > 0) { - quantity += amount; - } - } - - public void decreaseStock(int amount) { - if (amount > 0 && amount <= quantity) { - quantity -= amount; - } else { - System.out.println("Insufficient stock or invalid amount."); - } - } - - public int getQuantity() { - return quantity; - } - - public String getProductName() { - return productName; - } -} -``` - -**Inventory.java**: - -```java -import java.util.ArrayList; - -public class Inventory { - private ArrayList products = new ArrayList<>(); - - public void addProduct(Product product) { - products.add(product); - } - - public void removeProduct(String productId) { - products.removeIf(product -> product.getProductId().equals(productId)); - } - - public void displayInventory() { - for (Product product : products) { - System.out.println("Product: " + product.getProductName() + ", Quantity: " + product.getQuantity()); - } - } -} -``` - -**InventoryManager.java**: - -```java -public class InventoryManager { - public static void main(String[] args) { - Inventory inventory = new Inventory(); - - Product laptop = new Product("101", "Laptop", 10); - Product smartphone = new Product("102", "Smartphone", 20); - - inventory.addProduct(laptop); - inventory.addProduct(smartphone); - - laptop.increaseStock(5); - smartphone.decreaseStock(10); - - inventory.displayInventory(); - } -} -``` - -Output: - -```java -Product: Laptop, Quantity: 15 -Product: Smartphone, Quantity: 10 -``` - -**Explanation**: - -- The Laptop starts with a quantity of 10, and after increasing the stock by 5, its new quantity is 15. - -- The Smartphone starts with a quantity of 20, and after decreasing the stock by 10, its new quantity is 10. - -#### Expected Outcome: - -- Learners will practice object-oriented design by managing relationships between multiple classes (Inventory and Product). - -- They will understand the importance of **code encapsulation** by handling inventory operations through methods. - -- They will explore concepts like managing collections of objects (`ArrayList`). +> No content for this section --- From 942b51686ac154eb6b165339b3bb8fb937c6a9c0 Mon Sep 17 00:00:00 2001 From: Hafeezbaig Date: Tue, 22 Oct 2024 05:59:21 +0530 Subject: [PATCH 5/6] quiz and coding exercises updated --- additional-documentation.md | 881 ++++++++++++++++++++++++++++-------- 1 file changed, 683 insertions(+), 198 deletions(-) diff --git a/additional-documentation.md b/additional-documentation.md index 6f652e8b..8b63d883 100644 --- a/additional-documentation.md +++ b/additional-documentation.md @@ -12,7 +12,8 @@ Both steps provide an overview of Java, covering the foundational concepts of th - Can you describe what happens from the moment you compile a Java program to when it is run on a specific operating system? -### **Quiz Questions:** +### **New Quiz Questions:** + 1. **What is bytecode?** - A) Machine code for Windows - B) Code that runs directly on a CPU @@ -105,7 +106,7 @@ Earth has a diameter of 12742 kilometers. Mars has a diameter of 6779 kilometers. ``` -### **Quiz Questions:** +### **New Quiz Questions:** 1. **What is a Java class?** - A) A template for creating objects (Answer: A) @@ -129,88 +130,276 @@ Mars has a diameter of 6779 kilometers. ### Additional Coding Exercises: +### **Exercise 1: Create a "Device" Class with Multiple Methods and Compile It** + +#### **Problem:** +Create a Java class called `Device` that represents different electronic devices. The class should: + +- Have attributes for the `deviceName`, `brand`, and `powerStatus` (on/off). -### **Exercise 1: Exploring Java Platform Components** +- Implement methods: -**Objective**: Understanding the role of the JVM, JRE, and JDK through a practical scenario. + - `turnOn()` that prints "Device is turned ON." -#### Scenario: -You have written a simple Java program `Greeting.java` that prints "Hello, World!" to the console. You want to share this program with two different friends: + - `turnOff()` that prints "Device is turned OFF." -1. **Friend A** only has the JRE installed. + - `showDetails()` that prints the device's name and brand. -2. **Friend B** has the JDK installed. +- Create instances of the `Device` class for a few devices like "Smartphone", "Laptop", and "Tablet". Turn these devices on and off, and display their details. -**Tasks**: +Once you've created the class, follow these steps: -1. Explain what each friend needs to do to run your program. +1. Save the file as `Device.java`. -2. For **Friend A**, you should provide the compiled bytecode (`Greeting.class`), explain why this is necessary, and describe how they can run the program with the JRE. +2. Compile the file using `javac Device.java`. -3. For **Friend B**, explain the steps they need to follow, starting with the source file (`Greeting.java`), and show how they can compile and run the program using the JDK. +3. Run the program using `java Device`. -#### Sample Code for `Greeting.java`: +#### **Code:** ```java -public class Greeting { +public class Device { + // Attributes of the Device class + String deviceName; + String brand; + boolean powerStatus; + + // Constructor to initialize the device + public Device(String deviceName, String brand) { + this.deviceName = deviceName; + this.brand = brand; + this.powerStatus = false; // default is off + } + + // Method to turn on the device + public void turnOn() { + if (!powerStatus) { + powerStatus = true; + System.out.println(deviceName + " is turned ON."); + } else { + System.out.println(deviceName + " is already ON."); + } + } + + // Method to turn off the device + public void turnOff() { + if (powerStatus) { + powerStatus = false; + System.out.println(deviceName + " is turned OFF."); + } else { + System.out.println(deviceName + " is already OFF."); + } + } + + // Method to show details of the device + public void showDetails() { + System.out.println("Device Name: " + deviceName + ", Brand: " + brand); + } + + // Main method to test the Device class public static void main(String[] args) { - System.out.println("Hello, World!"); + // Creating instances of Device class + Device smartphone = new Device("Smartphone", "Samsung"); + Device laptop = new Device("Laptop", "Dell"); + Device tablet = new Device("Tablet", "Apple"); + + // Turning devices on and showing details + smartphone.turnOn(); + smartphone.showDetails(); + + laptop.turnOn(); + laptop.showDetails(); + + tablet.turnOn(); + tablet.showDetails(); + + // Turning devices off + smartphone.turnOff(); + laptop.turnOff(); + tablet.turnOff(); } } ``` -#### Expected Outcome: -- Learners should be able to describe the differences between the JRE and JDK and how each is used in different contexts (running bytecode vs. compiling and running source code). +#### **Explanation:** + +**Attributes (deviceName, brand, powerStatus)**: These are the properties of the Device class that hold information about the device’s name, brand, and whether it’s ON or OFF. + +**Constructor**: The constructor (`Device()`) initializes each object with a specific `deviceName` and `brand`, and sets the `powerStatus` to OFF by default. -- They should know how to compile a Java program with the JDK using `javac` and run it using `java`, and explain why the JRE alone is sufficient to run pre-compiled bytecode. +**Methods**: +- `turnOn()`: Turns on the device by setting `powerStatus` to `true`. + +- `turnOff()`: Turns off the device by setting `powerStatus` to `false`. + +- `showDetails()`: Displays the device's name and brand. + +**Main method**: This is where objects are created, methods are called, and the program is run. + +#### **Steps to Compile and Run:** + +1. Save the file as `Device.java`. + +2. In the terminal, compile the code: + + ``` + javac Device.java + ``` + +3. Run the code: + + ``` + java Device + ``` + +#### **Output:** + +```java +Smartphone is turned ON. +Device Name: Smartphone, Brand: Samsung +Laptop is turned ON. +Device Name: Laptop, Brand: Dell +Tablet is turned ON. +Device Name: Tablet, Brand: Apple +Smartphone is turned OFF. +Laptop is turned OFF. +Tablet is turned OFF. +``` --- -### **Exercise 2: Creating and Compiling a Class with a Method** +### **Exercise 2: Create a "Game" Class with a Scoring System** -**Objective**: Writing and compiling Java code outside of JShell, understanding the use of the `javac` and `java` commands. +#### **Problem:** -#### Tasks: +Write a class called `Game` that models a simple game system. The class should: -1. Write a Java class named `Car` in a file called `Car.java`. The class should have the following features: +- Have attributes for `gameName`, `maxScore`, and `currentScore`. - - A method `start()` that prints `"The car has started."`. +- Include methods to: - - A method `stop()` that prints `"The car has stopped."`. + - `startGame()` to initialize the game. -2. Add a `main` method to the class, where you create an instance of `Car` and call both `start()` and `stop()`. + - `playGame()` to increase the current score. -3. Compile your `Car.java` file using the `javac` command. + - `endGame()` to print the game details and final score. -4. Run the compiled class using the `java` command. +- Create instances for games like "Soccer", "Basketball", and "Tennis". Start each game, play to increase the score, and then end the game by displaying the final score. -#### Code for `Car.java`: +#### Compile and run the program after saving the file. +#### **Code:** ```java -public class Car { - void start() { - System.out.println("The car has started."); +public class Game { + // Attributes for the Game class + String gameName; + int maxScore; + int currentScore; + + // Constructor to initialize the game + public Game(String gameName, int maxScore) { + this.gameName = gameName; + this.maxScore = maxScore; + this.currentScore = 0; } - - void stop() { - System.out.println("The car has stopped."); + + // Method to start the game + public void startGame() { + System.out.println("Starting the game: " + gameName); + currentScore = 0; // Reset the score to 0 + } + + // Method to play the game and increase score + public void playGame() { + if (currentScore < maxScore) { + currentScore += 10; // Increment score by 10 + System.out.println("Playing " + gameName + "... Current Score: " + currentScore); + } else { + System.out.println("Game Over! Maximum score reached."); + } } + // Method to end the game and show the final score + public void endGame() { + System.out.println("Ending the game: " + gameName + ". Final Score: " + currentScore); + } + + // Main method to test the Game class public static void main(String[] args) { - Car myCar = new Car(); - myCar.start(); - myCar.stop(); + // Creating instances of Game class + Game soccer = new Game("Soccer", 50); + Game basketball = new Game("Basketball", 60); + Game tennis = new Game("Tennis", 40); + + // Starting and playing games + soccer.startGame(); + soccer.playGame(); + soccer.playGame(); + soccer.endGame(); + + basketball.startGame(); + basketball.playGame(); + basketball.playGame(); + basketball.playGame(); + basketball.endGame(); + + tennis.startGame(); + tennis.playGame(); + tennis.playGame(); + tennis.endGame(); } } ``` -#### Expected Outcome: +#### **Explanation:** + +**Attributes (gameName, maxScore, currentScore)**: These hold the information about the name of the game, the maximum score limit, and the current score during the game. + +**Constructor**: Initializes the game with the given `gameName` and `maxScore`, and sets the `currentScore` to 0 when the game starts. + +**Methods**: -- The learners will write a basic Java class with methods and a `main` method to execute it. +- `startGame()`: Starts the game and resets the score to 0. -- They will compile the code using `javac` and understand how the `.class` file is generated. +- `playGame()`: Increases the score by 10 points. If the `maxScore` is reached, it prints a message indicating the game is over. -- They will run the compiled bytecode using `java Car`, reinforcing the steps of compiling and running a Java program outside of JShell. +- `endGame()`: Prints the final score and ends the game. + +**Main method**: Creates instances of Game, calls the methods to start, play, and end the game, and displays the final score. + +#### **Steps to Compile and Run:** + +1. Save the file as `Game.java`. + +2. In the terminal, compile the code: + + ``` + javac Game.java + ``` + +3. Run the code: + + ``` + java Game + ``` + +#### **Output:** + +```java +Starting the game: Soccer +Playing Soccer... Current Score: 10 +Playing Soccer... Current Score: 20 +Ending the game: Soccer. Final Score: 20 +Starting the game: Basketball +Playing Basketball... Current Score: 10 +Playing Basketball... Current Score: 20 +Playing Basketball... Current Score: 30 +Ending the game: Basketball. Final Score: 30 +Starting the game: Tennis +Playing Tennis... Current Score: 10 +Playing Tennis... Current Score: 20 +Ending the game: Tennis. Final Score: 20 +``` --- @@ -289,7 +478,19 @@ Create a class called `Item` that represents an item in an online shopping syste Item: Phone, Price: 299.99, Quantity: 2, Total Cost: 599.98 ``` -### **Quiz Questions:** +### **Existing Quiz Questions:** + +1. **What is a class in Object Oriented Programming?** + - A) An instance of an object + - B) template for creating objects (Answer: B) + - C) function to perform actions + +2. **What are the two main components of an object in Object Oriented Programming?** + - A) State and Behavior (Answer: A) + - B) Template and Instance + - C) Functions and Variables + +### **New Quiz Questions:** 1. **What is the key concept behind Object-Oriented Programming (OOP)?** - A) Procedural coding @@ -439,7 +640,18 @@ Effective Java by Joshua Bloch has 500 copies. Clean Code by Robert Martin has 300 copies. ``` -### **Quiz Questions:** +### **Existing Quiz Questions:** + +1. **Which of the following methods in a class is the recommended approach to set the title attribute?** + - A) setTitle(String title) (Answer: A) + - B) getTitle() + - C) setBook(String book) + +2. **In a Java class, what is the purpose of a getter method?** + - A) To modify the value of a private member variable + - B) To access the value of a private member variable (Answer: B) + +### **New Quiz Questions:** 1. **What does the `setSpeed()` method in the MotorBike class do?** - A) Sets the speed of the bike (Answer: A) @@ -519,7 +731,18 @@ Modify the `MotorBike` class to use **encapsulation**. Make the `speed` variable Ducati speed: 100 ``` -### **Quiz Questions:** +### **Existing Quiz Questions:** + +1. **What is the purpose of private keyword in Java?** + - A) To make a variable or method accessible only within the class (Answer: A) + - B) To make a variable or method accessible outside the class + - C) To make a variable or method static + +2. **What is the main principle that is violated when an object directly accesses the state of another object without using any methods?** + - A) Inheritance + - B) Encapsulation (Answer: B) + +### **New Quiz Questions:** 1. **What is encapsulation in Java?** - A) Hiding implementation details (Answer: A) @@ -663,7 +886,14 @@ Extend the `Book` class to add a new private property `numberOfPages`. Number of pages: 100 ``` -### **Quiz Questions:** +### **Existing Quiz Questions:** + +1. **What are the default values for object member variables when they are not explicitly initialized?** + - A) null for reference types, true for boolean and the type's minimum value for numeric primitive types + - B) null for reference types, false for boolean, and 0 for numeric primitive types (Answer: B) + - C) The type's maximum value for primitive types, true for boolean and null for reference types + +### **New Quiz Questions:** 1. **What is the main advantage of using encapsulation?** - A) Faster code execution @@ -809,7 +1039,18 @@ Alice is 25 years old. Bob is 30 years old. ``` -### **Quiz Questions:** +### **Existing Quiz Questions:** + +1. **What is a constructor in Java?** + - A) A special method that is called when an object of a class is created. (Answer: A) + - B) A method that is used to destroy an object. + +2. **How is a constructor invoked in Java?** + - A) By calling the method directly + - B) By using the new keyword to create an object of the class (Answer: B) + - C) By declaring the constructor as static + +### **New Quiz Questions:** 1. **What is the purpose of a constructor in Java?** - A) It defines an abstract method @@ -833,7 +1074,7 @@ Bob is 30 years old. **Why Grouped:** This step wraps up the entire OOP section, summarizing the key concepts learned. -### **Quiz Questions:** +### **New Quiz Questions:** 1. **Which of the following is NOT one of the four pillars of OOP?** - A) Encapsulation @@ -853,253 +1094,497 @@ Bob is 30 years old. ### Additional Coding Exercises: -### **Exercise 1: Designing a Simple Banking System Using OOP** - -**Objective**: Practice designing a system with classes, encapsulation, and constructors. - -#### Tasks: - -1. **Create a class `BankAccount`** that models a simple bank account with the following attributes: - - - `accountNumber`: The account number of the bank account (private). - - - `balance`: The current balance in the account (private). +### **Exercise 1: Create a "`GuessTheNumber`" Game** -2. **Add methods** to the `BankAccount` class: +#### **Problem:** - - `deposit(double amount)`: A method to add money to the balance. +Create a class called `GuessTheNumber` that allows a player to guess a randomly generated number within a certain range. The class should: - - `withdraw(double amount)`: A method to withdraw money from the balance. Ensure that the balance does not go below zero. +- Have private attributes for the target number, the number of attempts, and a range (minimum and maximum numbers). - - `getBalance()`: A method to retrieve the current balance. - -3. **Add a constructor** to the `BankAccount` class that accepts an account number and an initial balance. +- Implement methods: -4. **Create a class `BankAccountRunner`** with the `main()` method where you: + - `startGame()` – to start the game and generate a random target number within the range. - - Create two instances of `BankAccount` with different account numbers and initial balances. + - `guess(int number)` – to accept a guess and provide feedback (too high, too low, or correct). - - Perform deposit and withdrawal operations and print the balance after each operation. + - `displayResult()` – to display the total number of attempts made by the player. -#### Code: +The game ends when the player guesses the correct number. -**BankAccount.java**: +#### **Code:** ```java -public class BankAccount { - private String accountNumber; - private double balance; - - public BankAccount(String accountNumber, double balance) { - this.accountNumber = accountNumber; - this.balance = balance; +import java.util.Random; +import java.util.Scanner; + +public class GuessTheNumber { + // Private attributes of the GuessTheNumber class + private int targetNumber; // The random number to be guessed + private int numberOfAttempts; // Number of attempts made by the player + private int minRange; // Minimum value of the range + private int maxRange; // Maximum value of the range + + // Constructor to initialize the game with a range + public GuessTheNumber(int minRange, int maxRange) { + this.minRange = minRange; + this.maxRange = maxRange; + this.numberOfAttempts = 0; // Initialize attempts to 0 } - public void deposit(double amount) { - if (amount > 0) { - balance += amount; - } + // Method to start the game and generate a random number within the range + public void startGame() { + Random random = new Random(); + targetNumber = random.nextInt(maxRange - minRange + 1) + minRange; + System.out.println("Game started! Try to guess the number between " + minRange + " and " + maxRange); } - public void withdraw(double amount) { - if (amount > 0 && amount <= balance) { - balance -= amount; + // Method to accept a guess and provide feedback + public void guess(int number) { + numberOfAttempts++; // Increment the number of attempts with each guess + if (number == targetNumber) { + System.out.println("Congratulations! You guessed the correct number."); + displayResult(); + } else if (number < targetNumber) { + System.out.println("Too low! Try again."); } else { - System.out.println("Insufficient balance or invalid amount."); + System.out.println("Too high! Try again."); } } - public double getBalance() { - return balance; + // Method to display the result (number of attempts made) + public void displayResult() { + System.out.println("You guessed the correct number in " + numberOfAttempts + " attempts."); } -} -``` - -**BankAccountRunner.java**: -```java -public class BankAccountRunner { + // Main method to test the GuessTheNumber game public static void main(String[] args) { - BankAccount account1 = new BankAccount("12345", 1000.00); - BankAccount account2 = new BankAccount("67890", 500.00); + // Create a Scanner to read input from the player + Scanner scanner = new Scanner(System.in); + + // Create a GuessTheNumber object with a range between 1 and 10 + GuessTheNumber game = new GuessTheNumber(1, 10); + + // Start the game + game.startGame(); + + // Loop until the player guesses the correct number + boolean correctGuess = false; + while (!correctGuess) { + System.out.print("Enter your guess: "); + int playerGuess = scanner.nextInt(); + game.guess(playerGuess); // Call the guess method with the player's input - account1.deposit(500.00); - account1.withdraw(200.00); - System.out.println("Account 1 Balance: " + account1.getBalance()); + if (playerGuess == game.targetNumber) { + correctGuess = true; // Break the loop if the guess is correct + } + } - account2.deposit(300.00); - account2.withdraw(100.00); - System.out.println("Account 2 Balance: " + account2.getBalance()); + // Close the scanner + scanner.close(); } } ``` -#### Output: +#### **Explanation:** -```java -Account 1 Balance: 1300.0 -Account 2 Balance: 700.0 -``` +- The `GuessTheNumber` class encapsulates the game logic, including the randomly generated target number, the number of attempts, and the range. -**Explanation**: +- The constructor initializes the game by setting the range (`minRange`, `maxRange`) and resetting the attempt counter. -- Account 1 starts with a balance of 1000, then deposits 500, and withdraws 200, resulting in a balance of 1300. +- The `startGame()` method generates a random number within the given range. -- Account 2 starts with a balance of 500, then deposits 300, and withdraws 100, resulting in a balance of 700. +- The `guess(int number)` method accepts the player's guess, compares it to the target number, and provides feedback (too high, too low, or correct). It also increments the number of attempts. -#### Expected Outcome: +- The game loop runs until the player guesses the correct number, at which point the game displays the result. -- Learners will practice using constructors to initialize objects. +**Attributes (`targetNumber`, `numberOfAttempts`, `minRange`, `maxRange`):** These store the target number to guess, how many guesses the player has made, and the range within which the number is generated. -- They will reinforce the concept of **encapsulation** by using private variables and methods to interact with object state. +**Constructor:** Initializes the game's range and resets the attempt counter. -- They will learn how to handle validation in methods, such as ensuring a withdrawal doesn't leave the account with a negative balance. +**Methods:** ---- + - `startGame()`: Randomly generates the target number and starts the game. -### **Exercise 2: Object-Oriented Inventory Management System** -**Objective**: Practice creating multiple classes and using objects to simulate an inventory management system. + - `guess(int number)`: Takes a guess and gives feedback (too high, too low, or correct). -#### Tasks: + - `displayResult()`: Displays the number of attempts made once the player guesses correctly. -1. **Create a class `Product`** with the following attributes: +**Main method:** Sets up the game, takes input from the player, and loops until the correct guess is made. - - `productId`: A unique identifier for the product (private). +#### **Steps to Run:** - - `productName`: The name of the product (private). +1. Save the file as `GuessTheNumber.java`. - - `quantity`: The quantity of the product available in stock (private). - -2. **Add methods** to the `Product` class: +2. Compile using: - - `increaseStock(int amount)`: A method to increase the stock of a product. + ``` + javac GuessTheNumber.java + ``` - - `decreaseStock(int amount)`: A method to decrease the stock of a product. Ensure that the quantity doesn't fall below zero. +3. Run the program: - - `getQuantity()`: A method to get the current quantity of the product. + ``` + java GuessTheNumber + ``` - - `getProductName()`: A method to get the product name. - -3. **Create a class `Inventory`** to manage multiple `Product` objects. The class should: +#### **Output:** - - Contain a list of products. +``` +Game started! Try to guess the number between 1 and 100 +Enter your guess: 4 +Too high! Try again. +Enter your guess: 1 +Too low! Try again. +Enter your guess: 3 +Congratulations! You guessed the correct number. +You guessed the correct number in 3 attempts. +``` + +--- - - Have methods `addProduct(Product product)` to add a product to the inventory and `removeProduct(String productId)` to remove a product by ID. +### **Exercise 2: Rock, Paper, Scissors Game** + +#### **Problem:** +Write a class called `RockPaperScissors` that allows the player to compete against the computer in a game of Rock, Paper, Scissors. The game should: -4. **Create a class `InventoryManager`** with the `main()` method where: +- Randomly generate the computer’s choice (rock, paper, or scissors). - - You create a few `Product` objects. +- Accept the player’s choice. - - You add products to the inventory, increase and decrease stock, and display product details. +- Compare the choices to determine the winner. -#### Code: +- Track the player's **wins**, **losses**, and **ties** over multiple rounds. -**Product.java**: +The game should allow the player to play multiple rounds and display the final score when the player chooses to stop. + +#### **Code:** ```java -public class Product { - private String productId; - private String productName; - private int quantity; - - public Product(String productId, String productName, int quantity) { - this.productId = productId; - this.productName = productName; - this.quantity = quantity; +import java.util.Random; +import java.util.Scanner; + +public class RockPaperScissors { + // Attributes to track player's wins, losses, and ties + private int wins; + private int losses; + private int ties; + + // Constructor to initialize the game with 0 wins, losses, and ties + public RockPaperScissors() { + wins = 0; + losses = 0; + ties = 0; } - public void increaseStock(int amount) { - if (amount > 0) { - quantity += amount; + // Method to randomly generate the computer's choice + public String getComputerChoice() { + Random random = new Random(); + int choice = random.nextInt(3); // Generates a number between 0 and 2 + switch (choice) { + case 0: + return "rock"; + case 1: + return "paper"; + case 2: + return "scissors"; + default: + return ""; // This should never happen } } - public void decreaseStock(int amount) { - if (amount > 0 && amount <= quantity) { - quantity -= amount; + // Method to determine the winner of a round + public void playRound(String playerChoice, String computerChoice) { + System.out.println("Computer chose: " + computerChoice); + + if (playerChoice.equals(computerChoice)) { + System.out.println("It's a tie!"); + ties++; + } else if ( + (playerChoice.equals("rock") && computerChoice.equals("scissors")) || + (playerChoice.equals("paper") && computerChoice.equals("rock")) || + (playerChoice.equals("scissors") && computerChoice.equals("paper")) + ) { + System.out.println("You win!"); + wins++; } else { - System.out.println("Insufficient stock or invalid amount."); + System.out.println("You lose!"); + losses++; } } - public int getQuantity() { - return quantity; + // Method to display the player's score + public void displayScore() { + System.out.println("Wins: " + wins + ", Losses: " + losses + ", Ties: " + ties); } - public String getProductName() { - return productName; - } + // Main method to run the game + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + RockPaperScissors game = new RockPaperScissors(); + + boolean keepPlaying = true; + + // Game loop for multiple rounds + while (keepPlaying) { + System.out.print("Enter your choice (rock, paper, or scissors): "); + String playerChoice = scanner.nextLine().toLowerCase(); // Get player's choice and convert to lowercase + + // Validate player input + if (!playerChoice.equals("rock") && !playerChoice.equals("paper") && !playerChoice.equals("scissors")) { + System.out.println("Invalid choice. Please enter rock, paper, or scissors."); + continue; + } + + // Get computer's choice and play the round + String computerChoice = game.getComputerChoice(); + game.playRound(playerChoice, computerChoice); + + // Ask if the player wants to play again + System.out.print("Do you want to play again? (yes or no): "); + String playAgain = scanner.nextLine().toLowerCase(); + + if (!playAgain.equals("yes")) { + keepPlaying = false; // End the game loop if the player says "no" + } + } + + // Display the final score after the game ends + System.out.println("\nGame Over! Final Score:"); + game.displayScore(); - public Object getProductId() { - return null; + // Close the scanner + scanner.close(); } } ``` -**Inventory.java**: +#### **Explanation:** -```java -import java.util.ArrayList; +- **Attributes:** + - `wins`, `losses`, `ties`: These variables track the player's performance over multiple rounds. + +- **Methods:** + - `getComputerChoice()`: Generates a random choice for the computer (either "rock", "paper", or "scissors"). -public class Inventory { - private ArrayList products = new ArrayList<>(); + - `playRound()`: Compares the player's choice and the computer's choice, determines the winner, and updates the scores (wins, losses, ties). - public void addProduct(Product product) { - products.add(product); - } + - `displayScore()`: Displays the total number of wins, losses, and ties after the game ends. - public void removeProduct(String productId) { - products.removeIf(product -> product.getProductId().equals(productId)); - } +- **Main Method:** - public void displayInventory() { - for (Product product : products) { - System.out.println("Product: " + product.getProductName() + ", Quantity: " + product.getQuantity()); - } - } -} + - The game runs in a loop, allowing the player to play multiple rounds. The loop continues until the player chooses to stop. + + - The player's input is validated to ensure it's either "rock", "paper", or "scissors". + + - After each round, the player is asked if they want to play again. + +#### **Steps to Run:** + +1. Save the file as `RockPaperScissors.java`. + +2. Compile using: + + ``` + javac RockPaperScissors.java + ``` + +3. Run the program: + + ``` + java RockPaperScissors + ``` + +#### **Output:** + +```java +Enter your choice (rock, paper, or scissors): rock +Computer chose: paper +You lose! +Do you want to play again? (yes or no): yes + +Enter your choice (rock, paper, or scissors): scissors +Computer chose: paper +You win! +Do you want to play again? (yes or no): no + +Game Over! Final Score: +Wins: 1, Losses: 1, Ties: 0 ``` -**InventoryManager.java**: +--- + +### **Exercise 3: Math Quiz Challenge** + +#### **Problem:** +Create a game where the player is presented with random math problems (addition, subtraction, multiplication, or division). + +The player must solve as many problems as possible within a time limit (e.g., 10 seconds). The game tracks the player's score based on correct answers. + +### **Code:** ```java -public class InventoryManager { - public static void main(String[] args) { - Inventory inventory = new Inventory(); +import java.util.Random; +import java.util.Scanner; +import java.util.Timer; +import java.util.TimerTask; - Product laptop = new Product("101", "Laptop", 10); - Product smartphone = new Product("102", "Smartphone", 20); +public class MathQuizChallenge { + private static int score = 0; // Keeps track of the player's score + private static boolean timeUp = false; // Keeps track of whether the time is up - inventory.addProduct(laptop); - inventory.addProduct(smartphone); + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + Random random = new Random(); + + System.out.println("Welcome to the Math Quiz Challenge!"); + System.out.println("Solve as many math problems as you can within 10 seconds."); + System.out.println("Press Enter to start..."); + scanner.nextLine(); // Wait for the player to press Enter + + // Start the timer for 10 seconds + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + timeUp = true; + System.out.println("\nTime's up!"); + } + }, 10000); // Timer set for 10 seconds + + // Main game loop + while (!timeUp) { + // Generate random numbers and a random operation + int num1 = random.nextInt(10) + 1; // Random number between 1 and 10 + int num2 = random.nextInt(10) + 1; // Random number between 1 and 10 + int operator = random.nextInt(4); // 0 for +, 1 for -, 2 for *, 3 for / + + String operation = ""; + int correctAnswer = 0; + + switch (operator) { + case 0: + operation = "+"; + correctAnswer = num1 + num2; + break; + case 1: + operation = "-"; + correctAnswer = num1 - num2; + break; + case 2: + operation = "*"; + correctAnswer = num1 * num2; + break; + case 3: + operation = "/"; + // Ensure that num2 is not zero to avoid division by zero + if (num2 == 0) num2 = 1; + correctAnswer = num1 / num2; + break; + } + + // Display the math problem to the player + System.out.print(num1 + " " + operation + " " + num2 + " = "); + + // Check if time has run out before accepting input + if (scanner.hasNextInt() && !timeUp) { + int playerAnswer = scanner.nextInt(); // Get the player's answer + + // Check if the player's answer is correct + if (playerAnswer == correctAnswer) { + System.out.println("Correct!"); + score++; + } else { + System.out.println("Wrong. The correct answer was " + correctAnswer); + } + } else { + break; // Exit the loop if the time is up or no valid input is provided + } + } - laptop.increaseStock(5); - smartphone.decreaseStock(10); + // Print the final score after the game loop ends + System.out.println("\nYour final score is: " + score); - inventory.displayInventory(); + // Close the scanner + scanner.close(); } } ``` -Output: +### **Explanation:** -```java -Product: Laptop, Quantity: 15 -Product: Smartphone, Quantity: 10 -``` +1. **Attributes:** + + - `score`: This variable tracks the number of correct answers the player gives. -**Explanation**: + - `timeUp`: This boolean tracks whether the 30-second timer has ended, signaling that the game is over. -- The Laptop starts with a quantity of 10, and after increasing the stock by 5, its new quantity is 15. +2. **Main Method:** -- The Smartphone starts with a quantity of 20, and after decreasing the stock by 10, its new quantity is 10. + - **Timer**: A `Timer` is used to count down 30 seconds. Once the time is up, the game stops, and no more problems are presented to the player. -#### Expected Outcome: + - **Random Math Problem Generation**: The game randomly generates two numbers (`num1` and `num2`) and selects a random operation (`+`, `-`, `*`, `/`) for the player to solve. -- Learners will practice object-oriented design by managing relationships between multiple classes (Inventory and Product). + - **Game Loop**: The game keeps running until the timer expires. The player's answers are compared to the correct answers, and their score is updated accordingly. -- They will understand the importance of **code encapsulation** by handling inventory operations through methods. +3. **Game Flow:** -- They will explore concepts like managing collections of objects (`ArrayList`). + - The player presses **Enter** to start. + + - Math problems are generated one by one, and the player inputs their answer. + + - The game provides feedback for each answer (correct or wrong). + + - After 30 seconds, the game ends, and the player's final score is displayed. + +### **Steps to Run:** + +1. Save the file as `MathQuizChallenge.java`. + +2. Compile the program: + + ``` + javac MathQuizChallenge.java + ``` + +3. Run the program: + + ``` + java MathQuizChallenge + ``` + +### **Output:** + +```java +Welcome to the Math Quiz Challenge! +Solve as many math problems as you can within 10 seconds. +Press Enter to start... + +3 + 7 = 10 +Correct! +6 * 5 = 30 +Correct! +8 / 2 = 4 +Correct! +4 - 9 = -5 +Correct! +2 * 2 = 5 +Wrong. The correct answer was 4 +7 + 8 = 15 +Correct! + +Time's up! +Your final score is: 5 +``` + +### **Possible Enhancements:** + +1. **Different Levels:** Adding difficulty levels (easy, medium, hard) where the range of numbers or types of operations becomes more challenging. + +2. **Scoring System:** Award more points for solving harder problems (e.g., multiplication and division). + +3. **High Score Tracker:** Storing the player's highest score and display it at the end of each game. --- + +> End of this document - Last updated 05:58 10/22 \ No newline at end of file From 3d95356bfffc98f548530fbf0e60191a695a2fde Mon Sep 17 00:00:00 2001 From: Hafeezbaig Date: Sat, 26 Oct 2024 18:48:12 +0530 Subject: [PATCH 6/6] additional document updated (all sections added except section 3, 6) --- additional-documentation.md | 9208 ++++++++++++++++++++++++++++++++++- 1 file changed, 9207 insertions(+), 1 deletion(-) diff --git a/additional-documentation.md b/additional-documentation.md index 8b63d883..c8d847ad 100644 --- a/additional-documentation.md +++ b/additional-documentation.md @@ -1587,4 +1587,9210 @@ Your final score is: 5 --- -> End of this document - Last updated 05:58 10/22 \ No newline at end of file +## Section 11: Primitive Data Types And Alternatives in Java Programming + +#### **Group 1: Integer Data Types (Steps 01, 02, 03)** + +- **Step 01: Basics about Java Integer Data Types - Casting, Operators and More** +- **Step 02: Java Integer Data Types - Puzzles - Octal, Hexadecimal, Post and Pre Increment** +- **Step 03: Java Integer Data Types - Exercises - BiNumber - add, multiply and double** + +**Why Grouped**: These steps focus on integer data types, including the basics, puzzles on number systems (octal, hexadecimal), and exercises with operations on integers (like adding, multiplying, and doubling). + + + +### **Puzzle 1: Octal and Hexadecimal Conversion** +**Problem:** Convert the following values into decimal: +1. Octal value `010` (Hint: Base 8) +2. Hexadecimal value `0xA2` (Hint: Base 16) + +**Answer:** +1. Octal `010` = Decimal `8` +2. Hexadecimal `0xA2` = Decimal `162` + +### **Puzzle 2: Pre and Post-Increment Operators** +**Problem:** Predict the output of the following code based on the discussion of pre- and post-increment: +```java +int x = 5; +int y = ++x; +System.out.println(x); // ? +System.out.println(y); // ? +``` + +**Answer:** +- `x = 6` +- `y = 6` + +### **Existing Quiz Questions:** + +1. Which of these wrapper classes corresponds to the 'int' primitive type in Java? + + - A) Byte + - B) Integer (Answer: B) + - C) Short + +2. What is the maximum value of a 'short' data type in Java? + + - A) 127 + - B) 32767 (Answer: B) + - C) 2147483647 + +3. Which of the following is the correct representation for the value 16 in a hexadecimal system? + + - A) 0x10 (Answer: A) + - B) 010 + - C) 0х16 + +### **New Quiz Questions:** + +1. What is the difference between pre-increment and post-increment in Java? + + - A) Pre-increment uses the value first, then increments + - B) Post-increment increments the value first, then uses it + - C) Pre-increment increments the value before using it in the expression (Answer: C) + +2. How are octal and hexadecimal numbers represented in Java? + + - A) Octal with `0` and Hexadecimal with `0x` (Answer: A) + - B) Both with `0` + - C) Octal with `x` and Hexadecimal with `h` + +### **Fun Fact:** +- **Fun Fact:** The Java platform supports number systems like binary, octal, decimal, and hexadecimal, which are often used in low-level programming. + +--- + +#### **Group 2: (Steps 04, 05, 06, 07)** + +- Step 04: Java Floating Point Data Types - Casting, Conversion and Accuracy +- Step 05: Introduction to BigDecimal Java Class +- Step 06: BigDecimal Puzzles - Adding Integers +- Step 07: BigDecimal Exercises - Simple Interest Calculation + +**Why Grouped**: These steps focus on floating-point numbers and BigDecimal, covering topics like accuracy with floating-point numbers, casting, conversion, and calculations using the BigDecimal class. + +### **Puzzle 1: Floating Point Precision** + +**Problem:** Why does the following code print `false`? +```java +double a = 0.1; +double b = 0.2; +System.out.println((a + b) == 0.3); // Why is this false? +``` + +**Answer:** Floating-point numbers are not represented exactly in binary, which results in imprecision. The sum of `a` and `b` is slightly off from `0.3`. + +### **Puzzle 2: BigDecimal Addition** + +**Problem:** What is the output of the following code? +```java +BigDecimal a = new BigDecimal("0.1"); +BigDecimal b = new BigDecimal("0.2"); +BigDecimal result = a.add(b); +System.out.println(result); +``` +**Answer:** The output is `0.3`. This ties into the importance of using `BigDecimal` for financial or precise calculations. + +### **Existing Quiz Questions:** + +1. What is the default type for floating-point literals in Java? + + - A) float + - B) double (Answer: B) +1. How can you create a float literal in Java? + + - A) float f = 34.5; + - B) float f = 34.5f; (Answer: B) + +2. What is the main reason for using the BigDecimal data type in Java? + + - A) To represent floating-point numbers with higher precision (Answer: A) + - B) To perform faster calculations + - C) To store large integer values + +3. What is the best way to construct a BigDecimal object to achieve high precision? + + - A) Using double literals + - B) Using String literals (Answer: B) + +4. Which of the following methods can be used for arithmetic operations on BigDecimal objects? + + - A) add() + - B) multiply() + - C) subtract() + - D) All of the above (Answer: D) + +### **New Quiz Questions:** + +1. What is the main benefit of using the `BigDecimal` class over floating-point data types? + + - A) It is faster + - B) It allows better precision for large and exact calculations (Answer: B) + - C) It uses less memory + +2. Why does floating-point arithmetic sometimes produce unexpected results? + + - A) Because Java is not accurate enough + - B) Because certain numbers cannot be represented exactly in binary (Answer: B) + - C) Because the computer runs out of memory + +### **Fun Fact:** +- **Fun Fact:** The Java `BigDecimal` class was introduced to handle precise decimal calculations, which are critical in applications like banking or scientific computing. + +--- + +#### **Group 3: Boolean Data Types (Steps 08, 09)** + +- Step 08: Java Boolean Data Type - Relational and Logical Operators +- Step 09: Java Boolean Data Type - Puzzles - Short Circuit Operators + +**Why Grouped**: These steps introduce Boolean data types and the use of logical and relational operators, including puzzles on short-circuit operators. + +### **Puzzle 1: Short-Circuit Operators** +**Problem:** What is the output of the following code? +```java +int i = 10, j = 20; +if (j > 25 && i++ > 5) { + System.out.println(i); +} +``` +**Answer:** The output will be `10`, because the first condition (`j > 25`) is false, so the second part (`i++ > 5`) is not evaluated due to short-circuiting. + +### **Puzzle 2: Boolean Comparison** +**Problem:** Predict the output of this code: +```java +int x = 5; +boolean result = (x > 3) && (x < 10); +System.out.println(result); // ? +``` +**Answer:** The output is `true` because both conditions are satisfied (`x` is greater than 3 and less than 10). + +### **Existing Quiz Questions:** + +1. Which of the following operators is a logical operator in Java? + + - A) `>` + - B) `&&` (Answer: B) + - C) `<=` + +### **New Quiz Questions:** + +1. What is a short-circuit operator in Java? + + - A) An operator that always evaluates both conditions + - B) An operator that stops evaluating once the result is determined (Answer: B) + - C) An operator used for short expressions + +2. What is the difference between `&&` and `&` operators? + + - A) `&&` evaluates both sides of the condition + - B) `&` is used only for numbers + - C) `&&` short-circuits, and `&` evaluates both sides even if the first condition is false (Answer: C) + + +### **Fun Fact:** + +- **Fun Fact:** Boolean algebra was developed by George Boole in the mid-1800s, and it forms the foundation of logic gates and decision-making in programming. + +--- + +#### **Group 4: Character Data Types (Steps 10, 11, 12, 13)** + +- Step 10: Java Character Data Type char - Representation and Conversion +- Step 11: Java char Data Type - Exercises 1 - isVowel +- Step 12: Java char Data Type - Exercises 2 - isDigit +- Step 13: Java char Data Type - Exercises 3 - isConsonant, List Upper Case and Lower Case + +**Why Grouped**: These steps focus on the char data type, including exercises that involve checking characters (vowel, digit, consonant), as well as representation and conversion of characters in Java. + +### **Puzzle 1: isVowel Method** +**Problem:** Write a method that checks if a character is a vowel. +```java +public static boolean isVowel(char c) { + c = Character.toLowerCase(c); + return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'); +} +``` +**Test Case:** +```java +System.out.println(isVowel('A')); // true +System.out.println(isVowel('b')); // false +``` + +### **Puzzle 2: isDigit Method** +**Problem:** Write a method to check if a character is a digit. +```java +public static boolean isDigit(char c) { + return Character.isDigit(c); +} +``` +**Test Case:** +```java +System.out.println(isDigit('5')); // true +System.out.println(isDigit('a')); // false +``` + +### **New Quiz Questions:** + +1. What is the difference between a character literal and a string literal in Java? + + - A) A character literal is enclosed in single quotes, and a string literal in double quotes (Answer: A) + - B) There is no difference + - C) A character literal is used for numbers + +2. How can you convert a char to its uppercase equivalent? + + - A) Use the `Character.toUpperCase(char)` method (Answer: A) + - B) Add `32` to the `char` value + - C) Use `String.toUpperCase()` + +### **Fun Fact:** + +- **Fun Fact:** Java uses the Unicode character set, which can represent characters from nearly every writing system in the world, allowing over 65,000 characters to be represented in the `char` data type. + +--- + +#### **Group 5: Primitive Data Types in Depth (Step 14)** + +- Step 14: Primitive Data Types in Depth - Conclusion + +**Why Grouped**: This is the conclusion of the entire section, summarizing the key points about primitive data types in Java. + +#### **New Quiz Question:** + +1. Why are primitive data types used in Java? + - A) They are more efficient and use less memory (Answer: A) + - B) They are easier to use than objects + - C) They do not need to be initialized + +### **Fun Fact:** + +- **Fun Fact:** Java has 8 primitive data types: `byte`, `short`, `int`, `long`, `float`, `double`, `boolean`, and `char`. + +--- + +### Additional Coding Exercises + +### **Exercise 1: Currency Converter Using BigDecimal** + +#### **Description:** +This exercise is a simple **currency converter** that uses the `BigDecimal` class to perform precise conversions between different currencies. It teaches the importance of using `BigDecimal` for financial applications where precision matters. + +#### **Code:** +```java +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Scanner; + +public class CurrencyConverter { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + // Exchange rates + BigDecimal usdToEur = new BigDecimal("0.85"); // 1 USD = 0.85 EUR + BigDecimal usdToGbp = new BigDecimal("0.75"); // 1 USD = 0.75 GBP + + // Input amount in USD + System.out.print("Enter amount in USD: "); + BigDecimal amountInUsd = scanner.nextBigDecimal(); + + // Convert to EUR and GBP + BigDecimal amountInEur = amountInUsd.multiply(usdToEur).setScale(2, RoundingMode.HALF_UP); + BigDecimal amountInGbp = amountInUsd.multiply(usdToGbp).setScale(2, RoundingMode.HALF_UP); + + // Display results + System.out.println("Amount in EUR: " + amountInEur); + System.out.println("Amount in GBP: " + amountInGbp); + + scanner.close(); + } +} +``` + +#### **Output:** +``` +Enter amount in USD: 100 +Amount in EUR: 85.00 +Amount in GBP: 75.00 +``` + +--- + +### **Exercise 2: Guess the Character Game** + +#### **Description:** +This is a **character guessing game** where the player has to guess whether the randomly selected character is a vowel or consonant. It reinforces working with the `char` primitive type. + +#### **Code:** +```java +import java.util.Scanner; +import java.util.Random; + +public class GuessTheCharacterGame { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + Random random = new Random(); + + // List of random characters to guess from + char[] letters = {'a', 'e', 'i', 'o', 'u', 'b', 'c', 'd', 'f', 'g'}; + char selectedChar = letters[random.nextInt(letters.length)]; + + // Prompt user to guess + System.out.println("Guess if the character is a vowel or consonant."); + System.out.print("Character: " + selectedChar + " (Type 'vowel' or 'consonant'): "); + String guess = scanner.next().toLowerCase(); + + // Check if the character is a vowel + boolean isVowel = selectedChar == 'a' || selectedChar == 'e' || selectedChar == 'i' || selectedChar == 'o' || selectedChar == 'u'; + + // Compare player's guess with the correct answer + if ((isVowel && guess.equals("vowel")) || (!isVowel && guess.equals("consonant"))) { + System.out.println("Correct! " + selectedChar + " is a " + (isVowel ? "vowel." : "consonant.")); + } else { + System.out.println("Wrong! " + selectedChar + " is a " + (isVowel ? "vowel." : "consonant.")); + } + + scanner.close(); + } +} +``` + +#### **Output:** +``` +Guess if the character is a vowel or consonant. +Character: o (Type 'vowel' or 'consonant'): vowel +Correct! o is a vowel. +``` + +--- + +### **Exercise 3: Temperature Conversion Game** + +#### **Description:** + +In this game, the player must convert a randomly generated temperature from Celsius, Fahrenheit, or Kelvin to the desired unit. The game helps players understand **primitive types** like `float` and `double`, and practice **casting** between data types when needed. + +--- + +### **Code:** + +```java +import java.util.Scanner; +import java.util.Random; + +public class TemperatureConversionGame { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + Random random = new Random(); + + // Introduction + System.out.println("Welcome to the Temperature Conversion Game!"); + System.out.println("You will be asked to convert temperatures between Celsius, Fahrenheit, and Kelvin."); + System.out.println("Try to get as many correct answers as possible!"); + + // Keep track of score + int score = 0; + + // Game loop + for (int i = 0; i < 5; i++) { // Play 5 rounds + // Generate random temperature and unit + float temperature = random.nextInt(100) + random.nextFloat(); // Random temperature between 0 and 100 + int unit = random.nextInt(3); // 0 = Celsius, 1 = Fahrenheit, 2 = Kelvin + String originalUnit = ""; + String targetUnit = ""; + + switch (unit) { + case 0: + originalUnit = "Celsius"; + targetUnit = "Fahrenheit"; + System.out.printf("Convert %.2f degrees Celsius to Fahrenheit: ", temperature); + break; + case 1: + originalUnit = "Fahrenheit"; + targetUnit = "Celsius"; + System.out.printf("Convert %.2f degrees Fahrenheit to Celsius: ", temperature); + break; + case 2: + originalUnit = "Kelvin"; + targetUnit = "Celsius"; + System.out.printf("Convert %.2f Kelvin to Celsius: ", temperature); + break; + } + + // Player's answer + float playerAnswer = scanner.nextFloat(); + + // Correct answer calculation + float correctAnswer = 0; + switch (unit) { + case 0: // Celsius to Fahrenheit + correctAnswer = (temperature * 9 / 5) + 32; + break; + case 1: // Fahrenheit to Celsius + correctAnswer = (temperature - 32) * 5 / 9; + break; + case 2: // Kelvin to Celsius + correctAnswer = temperature - 273.15f; + break; + } + + // Check if player's answer is close enough (allow for small precision errors) + if (Math.abs(playerAnswer - correctAnswer) < 0.1) { + System.out.println("Correct!"); + score++; + } else { + System.out.printf("Wrong! The correct answer was %.2f %s.%n", correctAnswer, targetUnit); + } + } + + // Game over - Show final score + System.out.println("Game over! Your final score is: " + score + " out of 5."); + + scanner.close(); + } +} +``` + +### **Output:** + +``` +Welcome to the Temperature Conversion Game! +You will be asked to convert temperatures between Celsius, Fahrenheit, and Kelvin. +Try to get as many correct answers as possible! + +Convert 45.72 degrees Celsius to Fahrenheit: 113.5 +Correct! + +Convert 78.34 degrees Fahrenheit to Celsius: 25.5 +Wrong! The correct answer was 25.74 Celsius. + +Convert 294.12 Kelvin to Celsius: 20.9 +Correct! + +Convert 12.59 degrees Celsius to Fahrenheit: 54.0 +Wrong! The correct answer was 54.66 Fahrenheit. + +Convert 103.12 degrees Fahrenheit to Celsius: 39.5 +Correct! + +Game over! Your final score is: 3 out of 5. +``` + +--- + +## Section 12: Conditionals in Java Programming + +#### **Group 1: (Steps 01, 02, 03)** + +- **Step 01:** Introduction to If Else Statement +- **Step 02:** Introduction to Nested If Else +- **Step 03:** If Else Statement - Puzzles + +**Why Grouped:** These steps introduce **basic if-else** and **nested if-else** structures and how to handle multiple conditions. + +### **Puzzle 1: Fix the Block Structure** +**Problem:** Write an if-else statement to check if a number is positive or negative. +```java +int number = -5; +if (number > 0) { + System.out.println("Positive"); +} else { + System.out.println("Negative"); +} +``` + +### **Puzzle 2: Nested If-Else Example** +**Problem:** Modify the code to add a check for zero and print "Zero" if the number is zero. +```java +int number = 0; +if (number > 0) { + System.out.println("Positive"); +} else if (number < 0) { + System.out.println("Negative"); +} else { + System.out.println("Zero"); +} +``` + +### **Existing Quiz Questions:** + +1. What is the output of the following code snippet? + +```java +int i = 10; +if(i < 5) { + System.out.println("i is less than 5"); +} else if(i > 20) { + System.out.println("i is greater than 20"); +} else { + System.out.println("i is between 5 and 20"); +} +``` + +- A) i is less than 5 +- B) i is greater than 20 +- C) i is between 5 and 20 (Answer: C) + +2. What is the output of the following code snippet? + +```java +int i = 15; +if(i < 5) { + System.out.println("i is less than 5"); +} else if(i > 20) { + System.out.println("i is greater than 20"); +} else if(i < 10) { + System.out.println("i is less than 10"); +} else { + System.out.println("i is between 10 and 20"); +} +``` + +- A) i is less than 5 +- B) i is greater than 20 +- C) i is less than 10 +- D) i is between 10 and 20 (Answer: D) + +3. What is the output of the following code snippet? + +```java +public static void puzzleOne() { + int k = 15; + if(k > 20) { + System.out.println(1); + } else if(k > 10) { + System.out.println(2); + } else if(k < 20) { + System.out.println(3); + } else { + System.out.println(4); + } +} +``` + +- A) 1 +- B) 2 (Answer: B) +- C) 3 +- D) 4 + +4. What is the output of the following code snippet? + +```java +int i = 0; +if(i) { + System.out.println("i"); +} +``` + +- A) i +- B) Compiler Error (Answer: B) +- C) Nothing is printed. + +### **New Quiz Questions:** + +1. **What is the purpose of the `else` block in Java?** + - A) It executes if the `if` condition is true. + - B) It executes if the `if` condition is false. (Answer: B) + - C) It checks another condition. + +2. **What happens if an assignment operator (`=`) is used instead of a comparison operator (`==`) in an if condition?** + - A) It causes a syntax error. + - B) The value is assigned, and the if condition might always be true. (Answer: B) + - C) It causes a runtime error. + +#### **Fun Fact:** +- **Fun Fact:** In older languages like C, if conditions could accept integers as "true" or "false." However, in Java, conditions must explicitly return a boolean, improving clarity. + +--- + +#### **Group 2: (Steps 04, 05, 06)** + +- **Step 04:** If Else Problem - How to get User Input in Java? +- **Step 05:** If Else Problem - How to get number 2 and choice from user? +- **Step 06:** If Else Problem - Implementing with Nested If Else + +**Why Grouped:** These steps focus on interacting with the user via the **Scanner class** to get input and use conditional logic to solve user-driven problems, like making a basic calculator. + +### **Puzzle 1: Implement a Simple Calculator** +**Problem:** Write a program that asks the user to enter two numbers and choose an operation (addition, subtraction). Based on the user's choice, perform the operation using nested if-else. +```java +Scanner scanner = new Scanner(System.in); +System.out.print("Enter first number: "); +int num1 = scanner.nextInt(); +System.out.print("Enter second number: "); +int num2 = scanner.nextInt(); +System.out.print("Enter choice (1 for addition, 2 for subtraction): "); +int choice = scanner.nextInt(); + +if (choice == 1) { + System.out.println("Result: " + (num1 + num2)); +} else if (choice == 2) { + System.out.println("Result: " + (num1 - num2)); +} else { + System.out.println("Invalid choice"); +} +``` + +### **Puzzle 2: Get User's Age and Check if Adult** +**Problem:** Write a program that gets the user’s age and prints whether the user is an adult (age >= 18) or not. +```java +Scanner scanner = new Scanner(System.in); +System.out.print("Enter your age: "); +int age = scanner.nextInt(); + +if (age >= 18) { + System.out.println("You are an adult."); +} else { + System.out.println("You are not an adult."); +} +``` + +### **Existing Quiz Questions:** + +1. What is the purpose of using the Scanner class in Java? + + - A) To read/scan user input from the console (Answer: A) + - B) To read input from a file + - C) To generate random numbers + +2. How do you read an integer input from the console using the Scanner class? + + - A) scanner.nextInt() (Answer: A) + - B) scanner.readInt() + - C) scanner.getint() + +### **New Quiz Questions:** + +1. **Which of the following is used to get user input in Java?** + - A) `Scanner` (Answer: A) + - B) `BufferedReader` + - C) `System.out` + +2. **What would happen if you forget to close the `Scanner` object?** + - A) The program will crash. + - B) Resources may not be released properly. (Answer: B) + - C) The input will not work. + +### **Fun Fact:** +- **Fun Fact:** The `Scanner` class is not only for reading user input but can also read from files and other input sources, making it very versatile. + +--- + +#### **Group 3: (Steps 07, 08, 09)** + +- **Step 07:** Java Switch Statement - An Introduction +- **Step 08:** Java Switch Statement - Puzzles - Default, Break and Fall Through +- **Step 09:** Java Switch Statement - Exercises - isWeekDay, nameOfMonth, nameOfDay + +**Why Grouped:** These steps cover the **switch statement**, how it compares to if-else, common pitfalls (e.g., forgetting the break statement), and exercises that apply switch to real-world problems like determining days of the week or months of the year. + +### **Puzzle 1: Switch on Days of the Week** +**Problem:** Write a switch statement that takes a number (1-7) and prints the corresponding day of the week. +```java +int day = 3; +switch (day) { + case 1: + System.out.println("Monday"); + break; + case 2: + System.out.println("Tuesday"); + break; + case 3: + System.out.println("Wednesday"); + break; + case 4: + System.out.println("Thursday"); + break; + case 5: + System.out.println("Friday"); + break; + case 6: + System.out.println("Saturday"); + break; + case 7: + System.out.println("Sunday"); + break; + default: + System.out.println("Invalid day"); +} +``` + +### **Puzzle 2: Name of the Month** +**Problem:** Write a switch statement that takes an integer (1-12) and prints the corresponding month. +```java +int month = 5; +switch (month) { + case 1: + System.out.println("January"); + break; + case 2: + System.out.println("February"); + break; + case 3: + System.out.println("March"); + break; + case 4: + System.out.println("April"); + break; + case 5: + System.out.println("May"); + break; + // Continue for other months... + default: + System.out.println("Invalid month"); +} +``` + +### **Existing Quiz Questions:** + +1. What is the purpose of the break statement in a switch statement in Java? + + - A) To break out of the switch after a successful match (Answer: A) + - B) To continue to the next case in the switch + - C) To stop the execution of the program + +### **New Quiz Questions:** + +1. **What happens if you forget to include a `break` statement in a switch case?** + - A) Only the matching case is executed. + - B) All the cases below the matching case are executed (fall-through). (Answer: B) + - C) It causes a runtime error. + +2. **Which data types can be used in a switch statement?** + - A) `int`, `char`, `String`, `enum` (Answer: A) + - B) `float`, `double` + - C) `boolean` + +#### **Fun Fact:** +- **Fun Fact:** Java switch statements used to only work with `int` and `char` types, but starting with Java 7, they were expanded to support `String` and `enum`. + +--- + +#### **Group 4: Ternary Operator (Step 10)** + +- **Step 10:** Java Ternary Operation - An Introduction + +**Why Grouped:** This step explains the **ternary operator** as a shorthand form of if-else for simple conditions. + +### **Puzzle: Use the Ternary Operator** +**Problem:** Rewrite the following if-else statement using the ternary operator: +```java +if (age >= 18) { + result = "Adult"; +} else { + result = "Not Adult"; +} +``` + +**Answer:** +```java +result = (age >= 18) ? "Adult" : "Not Adult"; +``` + +### **Existing Quiz Question:** + +1. What is the return type of both expressions in the ternary operator ?: in Java? + + - A) They CAN be different types. + - B) They MUST be different types. + - C) They MUST be the same type. (Answer: C) + +### **New Quiz Question:** + +1. **What is the purpose of the ternary operator in Java?** + - A) To perform simple if-else conditions in a single line. (Answer: A) + - B) To replace the switch statement. + - C) To perform bitwise operations. + +### **Fun Fact:** +- **Fun Fact:** The ternary operator is one of the few operators in Java that takes three operands: a condition, a true result, and a false result. + +--- + +#### **Group 5: Conclusion (Step 11)** + +- **Step 11:** Conditionals with Java - Conclusion + +**Why Grouped:** This is the **conclusion**, summarizing the key takeaways from conditionals in Java. + +### **New Quiz Question:** + +1. **What is the main benefit of using switch over if-else in certain situations?** + - A) It is easier to read when there are multiple conditions to check. (Answer: A) + - B) It is faster in all cases. + - C) It uses less memory. + +--- + +### Additional Coding Exercises + +### **Exercise 1: Simple Calculator Using Nested If-Else** + +#### **Description:** +Write a program that simulates a basic calculator. The program should: +1. Prompt the user to enter two numbers. +2. Ask the user to choose an operation: add, subtract, multiply, divide. +3. Use **nested if-else** statements to perform the correct operation. +4. Handle division by zero cases and show appropriate error messages. + +#### **Code:** +```java +import java.util.Scanner; + +public class SimpleCalculator { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + // Get user inputs + System.out.print("Enter first number: "); + double num1 = scanner.nextDouble(); + + System.out.print("Enter second number: "); + double num2 = scanner.nextDouble(); + + System.out.println("Choose operation: 1) Add 2) Subtract 3) Multiply 4) Divide"); + int choice = scanner.nextInt(); + + double result = 0; + boolean validOperation = true; + + // Use nested if-else for operations + if (choice == 1) { + result = num1 + num2; + } else if (choice == 2) { + result = num1 - num2; + } else if (choice == 3) { + result = num1 * num2; + } else if (choice == 4) { + if (num2 != 0) { + result = num1 / num2; + } else { + System.out.println("Error: Division by zero is not allowed."); + validOperation = false; + } + } else { + System.out.println("Invalid operation selected."); + validOperation = false; + } + + // Print result if the operation is valid + if (validOperation) { + System.out.println("Result: " + result); + } + + scanner.close(); + } +} +``` + +#### **Output:** + +```java +Enter first number: 10 +Enter second number: 5 +Choose operation: 1) Add 2) Subtract 3) Multiply 4) Divide +3 +Result: 50.0 +``` + +--- + +### **Exercise 2: Day of the Week Checker Using Switch** + +#### **Description:** +Create a program that takes an integer input (1-7) from the user and displays the corresponding day of the week (1 = Sunday, 2 = Monday, ..., 7 = Saturday). + +Use a **switch statement** to implement this. Include error handling for invalid inputs (numbers outside 1-7). + +#### **Code:** +```java +import java.util.Scanner; + +public class DayOfWeekChecker { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + // Prompt user to enter a number between 1 and 7 + System.out.print("Enter a number (1-7) to get the day of the week: "); + int dayNumber = scanner.nextInt(); + + // Use switch to check the day of the week + switch (dayNumber) { + case 1: + System.out.println("Sunday"); + break; + case 2: + System.out.println("Monday"); + break; + case 3: + System.out.println("Tuesday"); + break; + case 4: + System.out.println("Wednesday"); + break; + case 5: + System.out.println("Thursday"); + break; + case 6: + System.out.println("Friday"); + break; + case 7: + System.out.println("Saturday"); + break; + default: + System.out.println("Invalid input. Please enter a number between 1 and 7."); + } + + scanner.close(); + } +} +``` + +#### **Output:** +```java +Enter a number (1-7) to get the day of the week: 3 +Tuesday +``` + +--- + +### **Exercise 3: Guess the Number Game (Game Exercise)** + +#### **Description:** +Create a **Guess the Number** game where: +1. The computer randomly selects a number between 1 and 100. +2. The user tries to guess the number. +3. The program provides feedback on whether the guess is too high, too low, or correct. +4. Use **if-else** and **while loops** to implement this game. + +#### **Code:** +```java +import java.util.Scanner; +import java.util.Random; + +public class GuessTheNumberGame { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + Random random = new Random(); + + // Computer randomly picks a number between 1 and 100 + int secretNumber = random.nextInt(100) + 1; + int userGuess = 0; + int attempts = 0; + + System.out.println("Welcome to the Guess the Number Game!"); + System.out.println("Try to guess the number between 1 and 100."); + + // Game loop + while (userGuess != secretNumber) { + System.out.print("Enter your guess: "); + userGuess = scanner.nextInt(); + attempts++; + + // Provide feedback + if (userGuess < secretNumber) { + System.out.println("Too low! Try again."); + } else if (userGuess > secretNumber) { + System.out.println("Too high! Try again."); + } else { + System.out.println("Congratulations! You guessed the number in " + attempts + " attempts."); + } + } + + scanner.close(); + } +} +``` + +#### **Output:** +```java +Welcome to the Guess the Number Game! +Try to guess the number between 1 and 100. +Enter your guess: 50 +Too high! Try again. +Enter your guess: 25 +Too low! Try again. +Enter your guess: 37 +Congratulations! You guessed the number in 3 attempts. +``` + +--- + +### **Exercise 4: "Guess the Animal" Game** + +#### **Description:** + +In this game: +- The computer "thinks" of an animal. + +- The player asks **yes** or **no** questions to figure out which animal it is. + +- The player continues asking questions until they correctly guess the animal. + +- We'll use **if-else statements** to simulate the computer's responses and guide the player toward the right answer. + +### **Code:** + +```java +import java.util.Scanner; + +public class GuessTheAnimal { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + String animal = "elephant"; // The animal the computer is thinking of + + System.out.println("Welcome to the 'Guess the Animal' game!"); + System.out.println("I am thinking of an animal. Ask yes/no questions to guess which one!"); + + // Game loop + boolean guessedCorrectly = false; + while (!guessedCorrectly) { + System.out.println("\nAsk a yes/no question: "); + String question = scanner.nextLine().toLowerCase(); + + // Use if-else statements to simulate the computer's responses based on the question + if (question.contains("mammal")) { + System.out.println("Yes, it's a mammal."); + } else if (question.contains("large")) { + System.out.println("Yes, it's large."); + } else if (question.contains("four legs")) { + System.out.println("Yes, it has four legs."); + } else if (question.contains("trunk")) { + System.out.println("Yes, it has a trunk."); + } else if (question.contains("africa")) { + System.out.println("Yes, it lives in Africa."); + } else if (question.contains("elephant")) { + System.out.println("Congratulations! You guessed it. It's an elephant!"); + guessedCorrectly = true; + } else { + System.out.println("I don't know the answer to that."); + } + } + + scanner.close(); + System.out.println("Thanks for playing 'Guess the Animal'!"); + } +} +``` + +### **Output:** + +```java +Welcome to the 'Guess the Animal' game! +I am thinking of an animal. Ask yes/no questions to guess which one! + +Ask a yes/no question: +Is it a mammal? +Yes, it's a mammal. + +Ask a yes/no question: +Does it have a trunk? +Yes, it has a trunk. + +Ask a yes/no question: +Is it an elephant? +Congratulations! You guessed it. It's an elephant! +Thanks for playing 'Guess the Animal'! +``` + +--- + +## Section 14: Loops in Java Programming + +#### **Group 1: (Steps 01, 02, 03, 04)** + +- **Step 01:** Java For Loop - Syntax and Puzzles +- **Step 02:** Java For Loop - Exercises Overview and First Exercise Prime Numbers +- **Step 03:** Java For Loop - Exercise - Sum Upto N Numbers and Sum of Divisors +- **Step 04:** Java For Loop - Exercise - Print a Number Triangle + +**Why Grouped**: These steps focus on the for loop structure, including its syntax and various exercises, such as checking prime numbers, calculating sums, and printing number patterns. + +### **Puzzle 1: Prime Number Checker** + - Write a program to check if a number is prime using a **for loop**. + + **Solution:** + ```java + int number = 17; + boolean isPrime = true; + + for (int i = 2; i <= number / 2; i++) { + if (number % i == 0) { + isPrime = false; + break; + } + } + + if (isPrime) { + System.out.println(number + " is a prime number."); + } else { + System.out.println(number + " is not a prime number."); + } + ``` + +### **Puzzle 2: Sum of Divisors** + + - Write a program that uses a **for loop** to find the sum of all divisors of a number excluding 1 and the number itself. + + **Solution:** + ```java + int number = 12; + int sum = 0; + + for (int i = 2; i < number; i++) { + if (number % i == 0) { + sum += i; + } + } + + System.out.println("Sum of divisors of " + number + " is: " + sum); + ``` + +### **New Quiz Questions:** + +1. **What is the correct syntax of a `for` loop in Java?** + - A) `for(initialization; condition; update) { statement }` (Answer: A) + - B) `for(condition; initialization; update)` + - C) `for(initialization condition update)` + +2. **What will the following code print?** + ```java + for (int i = 0; i < 3; i++) { + System.out.print(i + " "); + } + ``` + - A) `0 1 2 ` (Answer: A) + - B) `0 1 2 3` + - C) `1 2 3` + +### **Fun Fact:** +- **Fun Fact:** The **for loop** can be completely empty (`for(;;)`) and still function as an infinite loop. + +--- + +#### **Group 2: (Steps 05, 06)** + +- **Step 05:** While Loop in Java - An Introduction +- **Step 06:** While Loop - Exercises - Cubes and Squares upto limit + +**Why Grouped**: These steps introduce the while loop, explaining its syntax and providing exercises that calculate cubes and squares within a given limit. + +### **Puzzle 1: Print Squares Using While Loop** + - Write a program that prints squares of numbers up to a given limit using a **while loop**. + + **Solution:** + ```java + int limit = 20; + int number = 1; + + while (number * number <= limit) { + System.out.println(number * number); + number++; + } + ``` + +### **Puzzle 2: Sum of Even Numbers Using While Loop** + - Write a program to find the sum of even numbers up to a limit using a **while loop**. + + **Solution:** + ```java + int limit = 10; + int sum = 0; + int number = 1; + + while (number <= limit) { + if (number % 2 == 0) { + sum += number; + } + number++; + } + + System.out.println("Sum of even numbers: " + sum); + ``` + +### **New Quiz Questions:** + +1. **Which of the following is true about a `while` loop?** + - A) It may not execute even once if the condition is false initially. (Answer: A) + - B) It always executes at least once. + - C) It is used for counting loops. + +2. **What is the output of the following code?** + ```java + int i = 0; + while (i < 3) { + System.out.println(i); + i++; + } + ``` + - A) 0 1 2 (Answer: A) + - B) 1 2 3 + - C) 0 1 2 3 + +### **Fun Fact:** +- **Fun Fact:** The **while loop** is used when the number of iterations is unknown and determined by a condition. + +--- + +### **Group 3: (Steps 07, 08)** + +- **Step 07:** Do While Loop in Java - An Introduction +- **Step 08:** Do While Loop in Java - An Example - Cube while user enters positive numbers + +**Why Grouped**: These steps focus on the do-while loop, its syntax, and a practical example where the loop continues based on user input. + +### **Puzzle 1: Cube Calculator with Do-While Loop** + - Write a program that asks the user for a number and prints the cube of the number. Continue until the user enters a negative number. + + **Solution:** + ```java + Scanner scanner = new Scanner(System.in); + int number; + + do { + System.out.print("Enter a number: "); + number = scanner.nextInt(); + if (number >= 0) { + System.out.println("Cube: " + (number * number * number)); + } + } while (number >= 0); + + System.out.println("Program ended."); + ``` + +### **Puzzle 2: Guess the Number Using Do-While** + - Write a program that keeps asking the user to guess a number until they guess correctly using a **do-while loop**. + + **Solution:** + ```java + Scanner scanner = new Scanner(System.in); + int secretNumber = 7; + int guess; + + do { + System.out.print("Guess the number: "); + guess = scanner.nextInt(); + if (guess != secretNumber) { + System.out.println("Try again."); + } + } while (guess != secretNumber); + + System.out.println("You guessed it!"); + ``` + +### **New Quiz Questions:** + +1. **What is the key difference between a `while` and a `do-while` loop?** + - A) `while` checks the condition first, `do-while` checks it after. (Answer: A) + - B) Both execute at least once. + - C) They are identical. + +2. **Which of the following scenarios best suits a `do-while` loop?** + - A) Executing a loop when the number of iterations is known beforehand. + - B) Ensuring the loop body executes at least once. (Answer: B) + - C) Looping based on a counter. + +### **Fun Fact:** +- **Fun Fact:** The **do-while loop** is often used when the code inside the loop needs to be executed at least once before any condition is checked. + +--- + +### **Group 4: Break, Continue, and Loop Selection (Steps 09, 10)** + +- **Step 09:** Introduction to Break and Continue +- **Step 10:** Selecting Loop in Java - For vs While vs Do While + +**Why Grouped**: These steps explain break and continue statements and compare the different types of loops, helping learners understand when to use each loop. + +### **Puzzle 1: Break a Loop** + - Write a program that prints numbers from 1 to 10 but stops when it reaches 5 using the `break` statement. + + **Solution:** + ```java + for (int i = 1; i <= 10; i++) { + if (i == 5) { + break; + } + System.out.println(i); + } + ``` + +### **Puzzle 2: Continue in a Loop** + - Write a program that prints numbers from 1 to 10 but skips the number 5 using the `continue` statement. + + **Solution:** + ```java + for (int i = 1; i <= 10; i++) { + if (i == 5) { + continue; + } + System.out.println(i); + } + ``` + +### **New Quiz Questions:** + +1. **What does the `break` statement do in a loop?** + - A) Exits the loop immediately. (Answer: A) + - B) Skips to the next iteration. + - C) Continues the loop. + +2. **What is the difference between a `continue` and a `break` statement?** + - A) `continue` skips the rest of the loop body and proceeds to the next iteration, while `break` exits the loop entirely. (Answer: A) + - B) They both exit the loop. + - C) Both skip to the next iteration. + +### **Fun Fact:** +- **Fun Fact:** Using **break** and **continue** can make code harder to understand, so it’s often recommended to avoid them when possible. + +--- + +### Additional Coding Exercises + +### **Exercise 1: Prime Number Finder with Break and Continue** +**Objective:** Write a program that finds and prints prime numbers between 1 and a user-defined limit using a **for loop**. + +The program should break the loop if the prime count reaches a specific number (e.g., stop after finding 5 primes) and use **continue** to skip non-prime numbers. + +**Code:** +```java +import java.util.Scanner; + +public class PrimeNumberFinder { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + System.out.print("Enter a limit: "); + int limit = scanner.nextInt(); + System.out.print("Enter the number of primes to find: "); + int primeCount = scanner.nextInt(); + + int count = 0; + for (int i = 2; i <= limit; i++) { + if (!isPrime(i)) { + continue; // Skip non-prime numbers + } + System.out.println(i + " is a prime number."); + count++; + if (count == primeCount) { + break; // Stop after finding the required number of primes + } + } + } + + private static boolean isPrime(int number) { + for (int i = 2; i <= number / 2; i++) { + if (number % i == 0) { + return false; + } + } + return true; + } +} +``` + +**Output:** +```java +Enter a limit: 20 +Enter the number of primes to find: 5 +2 is a prime number. +3 is a prime number. +5 is a prime number. +7 is a prime number. +11 is a prime number. +``` + +--- + +### **Exercise 2: Sum of Odd Numbers Using While Loop** +**Objective:** Create a program that calculates the sum of all odd numbers between 1 and a user-defined number using a **while loop**. + +**Code:** +```java +import java.util.Scanner; + +public class SumOfOddNumbers { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + System.out.print("Enter the limit: "); + int limit = scanner.nextInt(); + + int number = 1; + int sum = 0; + + while (number <= limit) { + if (number % 2 != 0) { // Check if the number is odd + sum += number; + } + number++; + } + + System.out.println("Sum of odd numbers up to " + limit + " is: " + sum); + } +} +``` + +**Output:** +``` +Enter the limit: 10 +Sum of odd numbers up to 10 is: 25 +``` + +--- + +### **Exercise 3: Guess the Number with Do-While Loop** +**Objective:** Write a guessing game where the computer selects a random number between 1 and 100, and the player has to guess the number. + +The game continues until the correct number is guessed, using a **do-while loop**. + +**Code:** +```java +import java.util.Scanner; + +public class GuessTheNumberGame { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + int secretNumber = (int) (Math.random() * 100 + 1); + int guess; + + System.out.println("Guess the number between 1 and 100!"); + + do { + System.out.print("Enter your guess: "); + guess = scanner.nextInt(); + + if (guess < secretNumber) { + System.out.println("Too low! Try again."); + } else if (guess > secretNumber) { + System.out.println("Too high! Try again."); + } + } while (guess != secretNumber); + + System.out.println("Congratulations! You guessed the number: " + secretNumber); + } +} +``` + +**Output:** +```java +Guess the number between 1 and 100! +Enter your guess: 50 +Too low! Try again. +Enter your guess: 75 +Too high! Try again. +Enter your guess: 63 +Congratulations! You guessed the number: 63 +``` + +--- + +### **Exercise 4 (Game): Multiplication Quiz Using For Loop** +**Objective:** Create a simple multiplication quiz game where the player answers a series of multiplication problems. The game should provide feedback and calculate the score at the end. + +**Code:** +```java +import java.util.Scanner; + +public class MultiplicationQuizGame { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + int score = 0; + + for (int i = 1; i <= 5; i++) { + int num1 = (int) (Math.random() * 10 + 1); + int num2 = (int) (Math.random() * 10 + 1); + + System.out.print("Question " + i + ": What is " + num1 + " * " + num2 + "? "); + int answer = scanner.nextInt(); + + if (answer == num1 * num2) { + System.out.println("Correct!"); + score++; + } else { + System.out.println("Wrong! The correct answer is " + (num1 * num2)); + } + } + + System.out.println("Your final score is: " + score + "/5"); + } +} +``` + +**Output:** +```java +Question 1: What is 3 * 7? 21 +Correct! +Question 2: What is 5 * 6? 30 +Correct! +... +Your final score is: 4/5 +``` + +--- + +## Section 16: Reference Types in Java Programming + +#### **Group 1: Steps 01, 02 – Introduction to Reference Types and Memory** +- **Step 01:** Reference Types - How are they stored in Memory? +- **Step 02:** Java Reference Types - Puzzles + +**Why Grouped**: These steps focus on how reference types are stored in memory and introduce puzzles to test learners' understanding. + +### **Puzzle 1: What is stored in reference variables?** + - Given the code snippet: + ```java + Animal dog = new Animal(12); + Animal cat = new Animal(15); + ``` + What is actually stored in `dog` and `cat`? + + **Answer:** + - `dog` and `cat` store the memory addresses (references) of the actual `Animal` objects in the heap, not the values themselves. + +### **Puzzle 2: What happens when reference variables are copied?** + - If you set `nothing = cat;` and modify `nothing.id = 10;`, what happens to `cat.id`? + + **Answer:** + - `cat.id` also becomes `10` because `nothing` and `cat` are both pointing to the same object in memory. + + +### Existing Quiz Questions: + +1. What is the purpose of reference variables in Java? + + - A) To store primitive values + - B) To store objects on the Heap + - C) To store the memory location of an object (Answer: C) + +2. What is the value of a reference variable that is not initialized by the programmer in Java? + + - A) 0 + - B) Empty + - C) Null (Answer: C) + +3. What happens when you compare two reference variables in Java? + + - A) It compares the values stored inside the referenced objects. + - B) It compares the memory locations where the objects are stored. (Answer: B) + - C) It compares the size of the objects. + +4. What happens when you assign one reference variable to another in Java? + + - A) It creates a copy of the entire referenced object. + - B) It only copies the reference. (Answer: B) + - C) It creates a new object with the same values as the referenced object. + +### New Quiz Questions: + +1. **How are reference types stored in memory in Java?** + + - A) By storing the value directly + - B) By storing a reference to the value (Answer: B) + - C) By storing both the value and the reference + +2. **What does the == operator compare for reference types?** + + - A) The memory reference (Answer: A) + - B) The actual value + - C) The type of object + +### Fun Fact: + +In Java, strings are stored in a string pool for memory optimization, meaning identical string literals can share the same memory reference. + +--- + +#### **Group 2: Steps 03, 04, 05, 06, 07 – String Class and String Handling** +- **Step 03:** String class - Introduction and Exercise - Print each word and char +- **Step 04:** String class - Exercise Solution and Some More Important Methods +- **Step 05:** Understanding String is Immutable and String Concat, Upper Case, Lower Case +- **Step 06:** String Concatenation and Join, Replace Methods +- **Step 07:** Java String Alternatives - StringBuffer and StringBuilder + +**Why Grouped**: These steps explore the String class, its immutability, key methods for manipulating strings, and introduce StringBuffer and StringBuilder for mutable string handling. + +### **Puzzle 1: Print Each Word in a String** + - Write a program to print each word and character of the string "Java is awesome" on a new line. + + **Code:** + ```java + String sentence = "Java is awesome"; + String[] words = sentence.split(" "); + for (String word : words) { + System.out.println("Word: " + word); + for (char c : word.toCharArray()) { + System.out.println("Character: " + c); + } + } + ``` + **Output** +``` +Word: Java +Character: J +Character: a +Character: v +Character: a +Word: is +Character: i +Character: s +Word: awesome +Character: a +Character: w +Character: e +Character: s +Character: o +Character: m +Character: e +``` + + +### **Puzzle 2: Compare `StringBuilder` and `StringBuffer`** + - Write code that demonstrates the performance difference between **StringBuilder** and **StringBuffer** for appending multiple strings. + + **Code:** + ```java + StringBuilder sb = new StringBuilder(); + long startTime = System.nanoTime(); + for (int i = 0; i < 10000; i++) { + sb.append("Java"); + } + long endTime = System.nanoTime(); + System.out.println("StringBuilder time: " + (endTime - startTime) + " ns"); + + StringBuffer sbf = new StringBuffer(); + startTime = System.nanoTime(); + for (int i = 0; i < 10000; i++) { + sbf.append("Java"); + } + endTime = System.nanoTime(); + System.out.println("StringBuffer time: " + (endTime - startTime) + " ns"); + ``` + +**Output** + +```java +StringBuilder time: 260000 ns +StringBuffer time: 340000 ns +``` + +### Existing Quiz Questions: + +1. What is the output of the following code: + +```java +String str = "Test"; +System.out.println(str.charAt(2)); +``` + +- A) e' +- B) s (Answer: B) +- C) T + +2. What is the meaning of the word “immutable”? + + - A) Changeable + - B) Unchangeable (Answer: B) + +3. What is the difference between StringBuffer and StringBuilder? + + - A) StringBuffer is thread-safe while StringBuilder is not (Answer: A) + - B) StringBuilder is thread-safe while StringBuffer is not + - C) Both StringBuffer and StringBuilder are thread-safe + + +### New Quiz Questions: + +1. **What is the main difference between StringBuilder and StringBuffer?** + + - A) StringBuilder is synchronized, StringBuffer is not + - B) StringBuffer is synchronized, StringBuilder is not (Answer: B) + - C) Both are synchronized + +2. **Why are strings immutable in Java?** + + - A) To make strings more efficient for memory management (Answer: A) + - B) To make strings changeable + - C) To make strings thread-safe + +### Fun Fact: + +String immutability in Java ensures that strings can be shared safely between multiple threads without worrying about data corruption. + +--- + +#### **Group 3: Steps 08, 09, 10 – Wrapper Classes** +- **Step 08:** Java Wrapper Classes - An Introduction - Why and What? +- **Step 09:** Java Wrapper Classes - Creation - Constructor and valueOf +- **Step 10:** Java Wrapper Classes - Auto Boxing and a Few Wrapper Constants + +**Why Grouped**: These steps introduce wrapper classes, their usage, creation, and the concept of auto-boxing in Java. + +### **Puzzle 1: Create a Wrapper Object** + - Write code that demonstrates how to create a wrapper object using both the `new` keyword and the `valueOf` method. + + **Code:** + ```java + Integer integer1 = new Integer(5); + Integer integer2 = Integer.valueOf(5); + System.out.println(integer1 == integer2); // false, because different objects + ``` +**Output** + +```java +false +``` + +### **Puzzle 2: Explore Wrapper Class Constants** + - Use the **Integer.MAX_VALUE** and **Integer.MIN_VALUE** constants to print the maximum and minimum integer values. + + **Code:** + ```java + System.out.println("Max int value: " + Integer.MAX_VALUE); + System.out.println("Min int value: " + Integer.MIN_VALUE); + ``` + +**Output** + +```java +Max int value: 2147483647 +Min int value: -2147483648 +``` + +### Existing Quiz Questions: + +1. Which of these statements about creating Wrapper objects is TRUE? + + - A) new and valueOf() both create new objects every time. + - B) There is no difference + - C) new creates a new object every time, but valueOf() tries to reuse existing objects with the same value. + - D) valueOf() creates a new object every time, but new reuses existing objects with the same value. + +### New Quiz Questions: + +1. **What is auto-boxing in Java?** + + - A) Automatically converting a primitive type to its corresponding wrapper class (Answer: A) + - B) Automatically converting a wrapper class to a primitive type + - C) Boxing multiple classes together + +2. **Which of the following is a valid wrapper class in Java?** + + - A) Integer (Answer: A) + - B) intWrapper + - C) Primitive + +### Fun Fact: + +Java automatically converts between primitives and their wrapper class equivalents thanks to auto-boxing and unboxing, reducing the need for manual conversion. + +--- + +#### **Group 4: Steps 11, 12, 13 – Java Dates** +- **Step 11:** Java Dates - Introduction to LocalDate, LocalTime and LocalDateTime +- **Step 12:** Java Dates - Exploring LocalDate - Creation and Methods to play with Dates +- **Step 13:** Java Dates - Exploring LocalDate - Comparing Dates and Creating Specific Dates + +**Why Grouped**: These steps focus on Java's date and time classes and explain how to work with LocalDate, LocalTime, and LocalDateTime. + +### **Puzzle 1: Print Current Date and Time** + - Write a program to print the current date, time, and date-time using **LocalDate**, **LocalTime**, and **LocalDateTime**. + + **Code:** + ```java + import java.time.LocalDate; + import java.time.LocalTime; + import java.time.LocalDateTime; + + public class DateTimeExample { + public static void main(String[] args) { + LocalDate date = LocalDate.now(); + LocalTime time = LocalTime.now(); + LocalDateTime dateTime = LocalDateTime.now(); + System.out.println("Current Date: " + date); + System.out.println("Current Time: " + time); + System.out.println("Current DateTime: " + dateTime); + } + } + ``` + +**Output** + +```java +Current Date: 2024-10-22 +Current Time: 14:35:45.234 +Current DateTime: 2024-10-22T14:35:45.234 +``` + + +### **Puzzle 2: Create and Compare Dates** + - Write a program that creates two **LocalDate** objects and compares them. + + **Answer:** + ```java + import java.time.LocalDate; + + public class DateComparison { + public static void main(String[] args) { + LocalDate date1 = LocalDate.of(2020, 5, 15); + LocalDate date2 = LocalDate.of(2023, 8, 10); + System.out.println("Is date1 before date2? " + date1.isBefore(date2)); + } + } + ``` + +**Output** + +```java +Is date1 before date2? true +``` + +### New Quiz Questions: + +1. **Which class is used to represent a date in Java 8?** + + - A) Date + - B) LocalDate (Answer: B) + - C) DateTime + +2. **How do you get the current date in Java 8?** + + - A) LocalDate.now() (Answer: A) + - B) System.currentDate() + - C) Date.new() + +### Fun Fact: + +Java's LocalDate and LocalDateTime classes introduced in Java 8 provide an immutable and thread-safe way to handle date and time information. + +--- + +#### **Group 5: Step 14 – Conclusion of Reference Types** +- **Step 14:** Java Reference Types - Conclusion + +**Why Grouped**: This is the conclusion of the Reference Types section, summarizing everything covered. + +### **Fun Fact:** + +Java introduced the **LocalDate** and **LocalDateTime** classes in **Java 8**, improving the handling of dates and times by making them thread-safe and immutable, unlike the older `java.util.Date` class. + +--- + +### Additional Coding Exercises + +### **Exercise 1: Creating and Managing Animals in a Zoo** +**Description:** Create a system for managing animals in a zoo. Each animal has an ID, name, and type (e.g., Mammal, Bird, Reptile). + +Use a `Map` to store animals, where the key is the animal's name and the value is an `Animal` object. Implement functions to add animals, display all animals, and find an animal by name. + +**Code :** +```java +import java.util.HashMap; +import java.util.Map; + +class Animal { + private int id; + private String name; + private String type; + + public Animal(int id, String name, String type) { + this.id = id; + this.name = name; + this.type = type; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + @Override + public String toString() { + return "Animal[ID=" + id + ", Name=" + name + ", Type=" + type + "]"; + } +} + +public class Zoo { + private Map animals = new HashMap<>(); + + public void addAnimal(Animal animal) { + animals.put(animal.getName(), animal); + } + + public void displayAnimals() { + for (Animal animal : animals.values()) { + System.out.println(animal); + } + } + + public Animal findAnimalByName(String name) { + return animals.get(name); + } + + public static void main(String[] args) { + Zoo zoo = new Zoo(); + zoo.addAnimal(new Animal(1, "Lion", "Mammal")); + zoo.addAnimal(new Animal(2, "Parrot", "Bird")); + zoo.addAnimal(new Animal(3, "Crocodile", "Reptile")); + + zoo.displayAnimals(); + + Animal animal = zoo.findAnimalByName("Parrot"); + System.out.println("Found Animal: " + animal); + } +} +``` + +**Output:** +```java +Animal[ID=1, Name=Lion, Type=Mammal] +Animal[ID=2, Name=Parrot, Type=Bird] +Animal[ID=3, Name=Crocodile, Type=Reptile] +Found Animal: Animal[ID=2, Name=Parrot, Type=Bird] +``` + +--- + +### **Exercise 2: Word Frequency Counter using Strings** +**Description:** Write a program that takes a paragraph as input and calculates the frequency of each word in the paragraph. Ignore case sensitivity and punctuation. + +**Code:** +```java +import java.util.HashMap; +import java.util.Map; + +public class WordFrequencyCounter { + public static void main(String[] args) { + String paragraph = "Java is awesome. Java is versatile. Java is widely used."; + String[] words = paragraph.toLowerCase().replaceAll("[^a-z ]", "").split(" "); + + Map wordCount = new HashMap<>(); + for (String word : words) { + wordCount.put(word, wordCount.getOrDefault(word, 0) + 1); + } + + for (Map.Entry entry : wordCount.entrySet()) { + System.out.println(entry.getKey() + ": " + entry.getValue()); + } + } +} +``` + +**Output:** +```java +java: 3 +is: 3 +awesome: 1 +versatile: 1 +widely: 1 +used: 1 +``` + +--- + +### **Exercise 3: Wrapper Class Challenge – Finding Maximum Integer** +**Description:** Create a program that reads a list of integers (as strings) and determines the maximum value using wrapper classes. + +The input should be handled as strings and converted to integers using `Integer.parseInt()`. + +**Code:** +```java +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class MaxIntegerFinder { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + List inputs = new ArrayList<>(); + + System.out.println("Enter integers (type 'done' to stop):"); + while (true) { + String input = scanner.nextLine(); + if (input.equals("done")) { + break; + } + inputs.add(input); + } + + int max = Integer.MIN_VALUE; + for (String input : inputs) { + int number = Integer.parseInt(input); + if (number > max) { + max = number; + } + } + + System.out.println("The maximum number is: " + max); + } +} +``` + +**Output:** +```java +Enter integers (type 'done' to stop): +5 +12 +7 +19 +done +The maximum number is: 19 +``` + +--- + +### **Exercise 4 (Game): "Guess the Animal" Game** +**Description:** Create a simple "Guess the Animal" game where the player thinks of an animal, and the program tries to guess it by asking yes/no questions. + +Use an `ArrayList` to store a small set of animals, and the program eliminates options based on user responses. + +**Code Snippet:** +```java +import java.util.ArrayList; +import java.util.Scanner; + +public class GuessTheAnimalGame { + public static void main(String[] args) { + ArrayList animals = new ArrayList<>(); + animals.add("Lion"); + animals.add("Elephant"); + animals.add("Eagle"); + animals.add("Shark"); + + Scanner scanner = new Scanner(System.in); + + System.out.println("Think of an animal from this list: Lion, Elephant, Eagle, Shark."); + System.out.println("I will try to guess it by asking yes/no questions."); + + String guessedAnimal = null; + + for (String animal : animals) { + System.out.println("Is it a " + animal + "? (yes/no)"); + String answer = scanner.nextLine(); + + if (answer.equalsIgnoreCase("yes")) { + guessedAnimal = animal; + break; + } + } + + if (guessedAnimal != null) { + System.out.println("I guessed it! The animal is a " + guessedAnimal + "!"); + } else { + System.out.println("I couldn't guess the animal."); + } + } +} +``` + +**Output:** +``` +Think of an animal from this list: Lion, Elephant, Eagle, Shark. +I will try to guess it by asking yes/no questions. +Is it a Lion? (yes/no) +no +Is it an Elephant? (yes/no) +yes +I guessed it! The animal is a Elephant! +``` + +--- + +## Arrays and ArrayLists in Java Programming + +#### **Group 1: Steps 01, 02, 03, 04 – Basics of Arrays and Array Manipulation** +- **Step 01**: Understanding the need and Basics about an Array +- **Step 02**: Java Arrays - Creating and Accessing Values - Introduction +- **Step 03**: Java Arrays - Puzzles - Arrays of Objects, Primitive Data Types, toString +- **Step 04**: Java Arrays - Compare, Sort and Fill + +**Why grouped:** Basics of Arrays and Array Manipulation: Focuses on introducing arrays, accessing values, performing operations, and basic manipulations like sorting and filling. + +### 1. **Puzzle: Calculate the Sum of Array Elements** + - Write a program to calculate the sum of elements in an integer array. Given an array of integers, find the total sum using a loop. + ```java + int[] numbers = {10, 20, 30, 40}; + int sum = 0; + for (int num : numbers) { + sum += num; + } + System.out.println("Total sum: " + sum); + ``` + **Output:** + ``` + Total sum: 100 + ``` + +### 2. **Puzzle: Sorting an Array of Strings** + - Given an array of strings, use the `Arrays.sort()` method to arrange them in alphabetical order. Test it with a set of words. + ```java + String[] words = {"banana", "apple", "cherry", "date"}; + Arrays.sort(words); + System.out.println(Arrays.toString(words)); + ``` + **Output:** + ``` + [apple, banana, cherry, date] + ``` + +### **Existing Quiz Questions:** + +1. Why do we use arrays? + + - A) To store different types of data + - B) To store similar types of data in a structured and organized manner. (Answer: B) + - C) To store data in an unorganized manner. + +2. What is the purpose of enhanced for loop in arrays? + + - A) Stores elements in the array. + - B) Accesses elements from the array. + - C) Iterate through all elements in the array with very simple syntax (Answer: C) + +3. How can we access elements from an array? + + - A) By using the indexing operator, [] (Answer: A) + - B) By using the length property of the array. + +4. What is the length property in arrays used for? + + - A) To find the number of elements in an array. (Answer: A) + - B) To find the value of an element in an array. + +5. What is the value of an array element of type int when it is NOT initialized? + + - A) Null + - B) False + - C) 0 (Answer: C) + +6. What is the purpose of the method Arrays.fill? + + - A) To compare two arrays + - B) To fill an array with a specified value (Answer: B) + - C) To perform an in-position sorting of elements + - D) To store zero or more number of elements in an array + +7. What is the output of the following code? + +```java + int[] marks = new int[5]; + Arrays.fill(marks, 100); + System.out.println(marks); +``` + +- A) [100,100,100,100,100] (Answer: A) +- B) [0,0,0,0,0] + +8. What is the result of the following code? + +```java +int [] +array1 = {1, 2, 3}; +int [] +array2 = {1, 2, 3}; +System.out.println(Arrays.equals(array1, array2)); +``` + +- A) false +- B) true (Answer: B) + +### **New Quiz Questions:** + + +1. What is the primary advantage of using an array? + - **A)** It allows storing different data types. + - **B)** It allows storing multiple values of the same data type. **(Answer: B)** + - **C)** It automatically resizes itself. + +2. Which of these is the correct syntax to create an array in Java? + - **A)** `int[] numbers = new int[5];` **(Answer: A)** + - **B)** `int numbers[5];` + - **C)** `int numbers = new int(5);` + +3. What will happen if you try to access an element outside the bounds of an array? + - **A)** The program will compile with a warning. + - **B)** An `ArrayIndexOutOfBoundsException` will be thrown. **(Answer: B)** + - **C)** The program will ignore the out-of-bound access. + +### **Fun Fact:** +- **Arrays in Ancient Programming:** Arrays were first formally introduced in the FORTRAN language in the 1950s and have since become fundamental in almost every programming language. + +--- + +#### **Group 2: Steps 05, 06, 07, 08, 09 – Array Exercises and Variable Arguments** +- **Step 05**: Java Arrays - Exercise - Create Student Class - Part 1 - Total and Average +- **Step 06**: Java Arrays - Exercise - Create Student Class - Part 2 - Maximum and Minimum +- **Step 07**: Introduction to Variable Arguments - Need +- **Step 08**: Introduction to Variable Arguments - Basics +- **Step 09**: Introduction to Variable Arguments - Enhancing Student Class + +**Why grouped:** Array Exercises and Variable Arguments: Covers exercises using arrays in a Student class, including calculations like total, average, maximum, minimum, and an introduction to variable arguments to enhance flexibility. + +### 1. **Puzzle: Calculating the Average Score** + - Create an array of scores and write a method to calculate the average score. Use variable arguments to allow flexibility in the number of scores passed. + ```java + public class AverageScore { + public static double calculateAverage(int... scores) { + int sum = 0; + for (int score : scores) { + sum += score; + } + return (double) sum / scores.length; + } + + public static void main(String[] args) { + System.out.println("Average Score: " + calculateAverage(85, 90, 78, 92)); + } + } + ``` + **Output:** + ``` + Average Score: 86.25 + ``` + +### 2. **Puzzle: Finding Maximum and Minimum Marks** + - Write a `Student` class with an array of marks. Create methods to calculate the maximum and minimum marks. + ```java + class Student { + int[] marks = {88, 74, 96, 85, 91}; + + public int getMaxMark() { + int max = marks[0]; + for (int mark : marks) { + if (mark > max) max = mark; + } + return max; + } + + public int getMinMark() { + int min = marks[0]; + for (int mark : marks) { + if (mark < min) min = mark; + } + return min; + } + } + + public class Main { + public static void main(String[] args) { + Student student = new Student(); + System.out.println("Max Mark: " + student.getMaxMark()); + System.out.println("Min Mark: " + student.getMinMark()); + } + } + ``` + **Output:** + ``` + Max Mark: 96 + Min Mark: 74 + ``` + +### **Existing Quiz Questions:** + +1. Where should the variable arguments list be placed in the list of arguments passed to a function? + + - A) At the beginning + - B) In the middle + - C) At the end (Answer: C) + +2. Which of these is an example of a variable argument method? + + - A) public int getNumberOfMarks() + - B) public int[] getMarks() + - C) public Student(String name, int... marks) (Answer: C) + +3. What happens if you pass the wrong data type to a variable argument method? + + - A) The Java compiler will throw an error. (Answer: A) + - B) The program will run, but with unexpected results. + - C) The program will crash. + + +### **New Quiz Questions:** + +1. What is the benefit of using variable arguments in a method? + - **A)** It allows a method to accept a variable number of parameters. **(Answer: A)** + - **B)** It restricts the method to accept only integers. + - **C)** It simplifies the method to accept arrays only. + +2. When using `variable arguments`, which of the following is correct? + - **A)** Variable arguments can be placed anywhere in the parameter list. + - **B)** Variable arguments must be the last parameter. **(Answer: B)** + - **C)** Variable arguments must be the first parameter. + +### **Fun Fact:** +- **Variable Arguments in Java 5:** Variable arguments (varargs) were introduced in Java 5 to simplify working with methods that accept an unknown number of parameters, a feature influenced by languages like Python. + +--- + +#### **Group 3: Steps 10, 11, 12 – Arrays of Objects and Limitations** +- **Step 10**: Java Arrays - Using Person Objects and String Elements with Exercises +- **Step 11**: Java String Arrays - Exercise Solutions - Print Day of Week with Most Occurrences +- **Step 12**: Adding and Removing Marks - Problem with Arrays + +**Why grouped:** Arrays of Objects and Limitations: Delves into handling arrays of objects (e.g., Person), string array exercises, and discusses the limitations of arrays, such as fixed size. + +### 1. **Puzzle: Identify Longest Day of the Week** + - Create an array of the days of the week and identify the day with the most characters. + ```java + String[] daysOfWeek = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; + String longestDay = ""; + for (String day : daysOfWeek) { + if (day.length() > longestDay.length()) { + longestDay = day; + } + } + System.out.println("Longest day: " + longestDay); + ``` + **Output:** + ``` + Longest day: Wednesday + ``` + +### 2. **Puzzle: Reversing Days of the Week** + - Print the days of the week in reverse order. + ```java + for (int i = daysOfWeek.length - 1; i >= 0; i--) { + System.out.println(daysOfWeek[i]); + } + ``` + **Output:** + ``` + Saturday + Friday + Thursday + Wednesday + Tuesday + Monday + Sunday + ``` + +### **Existing Quiz Questions:** + +1. When creating an array of objects, what does the array hold? + + - A) The actual objects themselves + - B) Copies of the objects + - C) References to the created objects (Answer: C) + +2. Why is it difficult to add or remove elements in an array? + + - A) Because the size of an array is fixed (Answer: A) + - B) Because arrays are only for primitive types + - C) Because arrays cannot store non-homogeneous types + +### **New Quiz Questions:** + +1. What will be the default value for unassigned elements in an array of integers? + - **A)** `null` + - **B)** `0` **(Answer: B)** + - **C)** `undefined` + +2. Which exception is thrown if you try to access an invalid index in an array? + - **A)** `NullPointerException` + - **B)** `IndexOutOfBoundsException` **(Answer: B)** + - **C)** `ArrayIndexOutOfBoundsException` + +### **Fun Fact:** +- **Fixed-Size Array Limitation:** In many programming languages, including Java, arrays have a fixed size, which led to the development of dynamic data structures like ArrayLists. + +--- + +#### **Group 4: Steps 13, 14, 15, 16 – ArrayList Basics and Student Class Refactoring** +- **Step 13**: First Look at ArrayList - An Introduction +- **Step 14**: First Look at ArrayList - Refactoring Student Class to use ArrayList +- **Step 15**: First Look at ArrayList - Enhancing Student Class with Add and Remove +- **Step 16**: Introduction to Array and ArrayList - Conclusion + +**Why grouped:** ArrayList Basics and Student Class Refactoring: Introduces ArrayLists, refactors the Student class to use ArrayLists instead of arrays, and explores enhanced functionality like adding and removing elements. + +### 1. **Puzzle: Manage a List of Favorite Books** + - Create an ArrayList to store your favorite books. Add, remove, and display books using ArrayList methods. + ```java + ArrayList books = new ArrayList<>(); + books.add("The Hobbit"); + books.add("1984"); + books.add("To Kill a Mockingbird"); + books.remove("1984"); + System.out.println(books); + ``` + **Output:** + ``` + [The Hobbit, To Kill a Mockingbird] + ``` + +### 2. **Puzzle: Convert an Array to an ArrayList** + - Convert an array of integers into an ArrayList and find the sum of its elements. + ```java + Integer[] array = {5, 10, 15, 20}; + ArrayList list = new ArrayList<>(Arrays.asList(array)); + int sum = 0; + for (int num : list) { + sum += num; + } + System.out.println("Sum: " + sum); + ``` + **Output:** + ``` + Sum: 50 + ``` + +### **Existing Quiz Questions:** + +1. What is the main advantage of ArrayList over arrays? + + - A) Arrays can store only primitive types + - B) ArrayList provides operations to add and remove elements (Answer: B) + - C) ArrayList has a fixed size + +2. How do you remove an element from an ArrayList? + + - A) Using the remove() method (Answer: A) + - B) Using the delete() method + - C) Using the clear() method + +3. What method can be used to find the maximum value in an ArrayList? + + - A) Collections.max() (Answer: A) + - B) ArrayList.max() + - C) ArrayList.getMaximum() + +### **New Quiz Questions:** + +1. Which method is used to add an element to an ArrayList? + - **A)** `put()` + - **B)** `add()` **(Answer: B)** + - **C)** `insert()` + +2. How can you initialize an ArrayList with values? + - **A)** `new ArrayList(Arrays.asList(values))` **(Answer: A)** + - **B)** `ArrayList(values)` + - **C)** `new ArrayList{values}` + +### **Fun Fact:** +- **ArrayLists in Java Collections:** The ArrayList in Java is part of the Collections Framework and provides a dynamic alternative to arrays, allowing resizing, addition, and removal of elements at any point. + +--- + +### Additional Coding Exercises + +### **Exercise 1: Student Gradebook with ArrayList** + +**Description**: Create a `Gradebook` class where students’ names and their respective grades are stored in an ArrayList. The program should allow adding new students with grades, updating grades, and removing students. + +This exercise reinforces ArrayList operations, such as adding, updating, and removing elements. + +**Code**: + +```java +import java.util.ArrayList; + +class Gradebook { + private ArrayList students; + private ArrayList grades; + + public Gradebook() { + students = new ArrayList<>(); + grades = new ArrayList<>(); + } + + public void addStudent(String name, int grade) { + students.add(name); + grades.add(grade); + } + + public void updateGrade(String name, int newGrade) { + int index = students.indexOf(name); + if (index != -1) { + grades.set(index, newGrade); + System.out.println("Updated grade for " + name); + } else { + System.out.println("Student not found."); + } + } + + public void removeStudent(String name) { + int index = students.indexOf(name); + if (index != -1) { + students.remove(index); + grades.remove(index); + System.out.println("Removed " + name + " from gradebook."); + } else { + System.out.println("Student not found."); + } + } + + public void display() { + System.out.println("\nGradebook:"); + for (int i = 0; i < students.size(); i++) { + System.out.println(students.get(i) + ": " + grades.get(i)); + } + } +} + +public class Main { + public static void main(String[] args) { + Gradebook gradebook = new Gradebook(); + gradebook.addStudent("Alice", 88); + gradebook.addStudent("Bob", 92); + gradebook.addStudent("Charlie", 76); + + gradebook.display(); + + gradebook.updateGrade("Alice", 90); + gradebook.display(); + + gradebook.removeStudent("Bob"); + gradebook.display(); + } +} +``` + +**Output**: + +``` +Gradebook: +Alice: 88 +Bob: 92 +Charlie: 76 + +Updated grade for Alice + +Gradebook: +Alice: 90 +Bob: 92 +Charlie: 76 + +Removed Bob from gradebook. + +Gradebook: +Alice: 90 +Charlie: 76 +``` + +--- + +### **Exercise 2: Dynamic Inventory System with Arrays** + +**Description**: Implement an inventory system for a store using arrays to store product names and quantities. Allow the user to add new items, update item quantities, and view the inventory. + +This exercise enhances skills in accessing and updating array elements. + +**Code**: + +```java +import java.util.Arrays; + +class Inventory { + private String[] products; + private int[] quantities; + private int size; + + public Inventory(int capacity) { + products = new String[capacity]; + quantities = new int[capacity]; + size = 0; + } + + public void addProduct(String product, int quantity) { + if (size < products.length) { + products[size] = product; + quantities[size] = quantity; + size++; + } else { + System.out.println("Inventory full! Cannot add more products."); + } + } + + public void updateQuantity(String product, int quantity) { + for (int i = 0; i < size; i++) { + if (products[i].equals(product)) { + quantities[i] = quantity; + System.out.println("Updated quantity for " + product); + return; + } + } + System.out.println("Product not found in inventory."); + } + + public void displayInventory() { + System.out.println("\nInventory:"); + for (int i = 0; i < size; i++) { + System.out.println(products[i] + ": " + quantities[i] + " units"); + } + } +} + +public class Main { + public static void main(String[] args) { + Inventory inventory = new Inventory(5); + + inventory.addProduct("Apple", 50); + inventory.addProduct("Banana", 30); + inventory.displayInventory(); + + inventory.updateQuantity("Apple", 70); + inventory.displayInventory(); + } +} +``` + +**Output**: + +``` +Inventory: +Apple: 50 units +Banana: 30 units + +Updated quantity for Apple + +Inventory: +Apple: 70 units +Banana: 30 units +``` + +--- + +### **Exercise 3: Rock-Paper-Scissors Game** + +**Description**: Develop a simple Rock-Paper-Scissors game where the player competes against the computer. Use an array to store the game choices. + +This exercise focuses on comparing values within arrays. + +**Code**: + +```java +import java.util.Random; +import java.util.Scanner; + +public class RockPaperScissors { + public static void main(String[] args) { + String[] choices = {"Rock", "Paper", "Scissors"}; + Random random = new Random(); + Scanner scanner = new Scanner(System.in); + + System.out.println("Let's play Rock, Paper, Scissors!"); + System.out.println("Enter Rock, Paper, or Scissors:"); + + String userChoice = scanner.nextLine(); + String computerChoice = choices[random.nextInt(3)]; + + System.out.println("Computer chose: " + computerChoice); + + if (userChoice.equalsIgnoreCase(computerChoice)) { + System.out.println("It's a tie!"); + } else if ((userChoice.equalsIgnoreCase("Rock") && computerChoice.equals("Scissors")) || + (userChoice.equalsIgnoreCase("Paper") && computerChoice.equals("Rock")) || + (userChoice.equalsIgnoreCase("Scissors") && computerChoice.equals("Paper"))) { + System.out.println("You win!"); + } else { + System.out.println("Computer wins!"); + } + scanner.close(); + } +} +``` + +**Output**: + +``` +Let's play Rock, Paper, Scissors! +Enter Rock, Paper, or Scissors: +Rock +Computer chose: Scissors +You win! +``` + +--- + +### **Exercise 4: Temperature Conversion Tracker (ArrayList)** + +**Description**: Design a program that tracks temperature conversions. It accepts temperatures in Celsius and converts them to Fahrenheit, storing each conversion in an ArrayList. + +This exercise emphasizes using ArrayList for dynamic storage and retrieval. + +**Code**: + +```java +import java.util.ArrayList; +import java.util.Scanner; + +class TemperatureConversion { + private ArrayList celsiusTemps; + private ArrayList fahrenheitTemps; + + public TemperatureConversion() { + celsiusTemps = new ArrayList<>(); + fahrenheitTemps = new ArrayList<>(); + } + + public void addTemperature(double celsius) { + double fahrenheit = celsius * 9/5 + 32; + celsiusTemps.add(celsius); + fahrenheitTemps.add(fahrenheit); + } + + public void displayConversions() { + System.out.println("\nTemperature Conversions:"); + for (int i = 0; i < celsiusTemps.size(); i++) { + System.out.println(celsiusTemps.get(i) + "°C = " + fahrenheitTemps.get(i) + "°F"); + } + } +} + +public class Main { + public static void main(String[] args) { + TemperatureConversion converter = new TemperatureConversion(); + Scanner scanner = new Scanner(System.in); + + System.out.println("Enter temperatures in Celsius to convert to Fahrenheit (type 'done' to finish):"); + + while (true) { + String input = scanner.nextLine(); + if (input.equalsIgnoreCase("done")) { + break; + } + try { + double celsius = Double.parseDouble(input); + converter.addTemperature(celsius); + } catch (NumberFormatException e) { + System.out.println("Invalid input. Please enter a numeric value."); + } + } + + converter.displayConversions(); + scanner.close(); + } +} +``` + +**Output**: + +``` +Enter temperatures in Celsius to convert to Fahrenheit (type 'done' to finish): +25 +100 +done + +Temperature Conversions: +25.0°C = 77.0°F +100.0°C = 212.0°F +``` + +--- + +### **Exercise 5: Word Scramble Game** + +**Description**: Create a word scramble game where the program presents a scrambled version of a word, and the player has to guess the original word. + +Use an array to store a list of words, and shuffle the letters of a word randomly each time it’s presented. + +**Code**: + +```java +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Scanner; + +public class WordScrambleGame { + public static void main(String[] args) { + String[] words = {"java", "array", "list", "object", "method"}; + Scanner scanner = new Scanner(System.in); + + for (String word : words) { + String scrambledWord = scrambleWord(word); + System.out.println("Guess the word: " + scrambledWord); + + String guess = scanner.nextLine(); + if (guess.equalsIgnoreCase(word)) { + System.out.println("Correct!"); + } else { + System.out.println("Incorrect. The word was: " + word); + } + } + System.out.println("Game over!"); + scanner.close(); + } + + public static String scrambleWord(String word) { + List letters = Arrays.asList(word.split("")); + Collections.shuffle(letters); + return String.join("", letters); + } +} +``` + +**Output**: +``` +Guess the word: jvaa +java +Correct! + +Guess the word: btjeco +object +Correct! + +Guess the word: htomed +method +Correct! + +Game over! +``` + +--- + +### **Exercise 6: Number Memory Game** + +**Description**: Develop a memory game where the program presents a sequence of numbers that the player must memorize. After a short delay, the numbers are hidden, and the player must input them in the correct order. + +Use an ArrayList to store the sequence, and increase the length of the sequence as the player progresses. + +**Code**: + +```java +import java.util.ArrayList; +import java.util.Random; +import java.util.Scanner; +import java.util.concurrent.TimeUnit; + +public class NumberMemoryGame { + public static void main(String[] args) throws InterruptedException { + ArrayList sequence = new ArrayList<>(); + Scanner scanner = new Scanner(System.in); + Random random = new Random(); + + int level = 1; + boolean playing = true; + + System.out.println("Welcome to the Number Memory Game!"); + + while (playing) { + // Generate a new number and add it to the sequence + sequence.add(random.nextInt(10)); // Numbers 0-9 + System.out.print("Memorize this sequence: "); + + // Display the sequence to the player + for (int num : sequence) { + System.out.print(num + " "); + } + System.out.println(); + + // Wait 3 seconds before clearing the screen + TimeUnit.SECONDS.sleep(3); + System.out.print("\033[H\033[2J"); // Clear console screen (may vary by environment) + System.out.flush(); + + System.out.println("Enter the sequence:"); + ArrayList playerSequence = new ArrayList<>(); + + // Get the player's input + for (int i = 0; i < sequence.size(); i++) { + playerSequence.add(scanner.nextInt()); + } + + // Check if the player's input matches the sequence + if (playerSequence.equals(sequence)) { + System.out.println("Correct! Moving to the next level."); + level++; + } else { + System.out.println("Incorrect sequence. Game over! You reached level " + level + "."); + playing = false; + } + } + scanner.close(); + } +} +``` + +**Output**: +``` +Welcome to the Number Memory Game! +Memorize this sequence: 7 2 + +Enter the sequence: +7 2 +Correct! Moving to the next level. + +Memorize this sequence: 7 2 4 + +Enter the sequence: +7 2 4 +Correct! Moving to the next level. + +Memorize this sequence: 7 2 4 9 + +Incorrect sequence. Game over! You reached level 3. +``` + +--- + +## Section 20: Java - Oriented Programming Again + +### **Group 1: Steps 01, 02, and 03 – Basics of Designing a Class and Behavior** + +- **Step 01 - Basics of Designing a Class - Class, Object, State, and Behavior** +- **Step 02 - OOPS Example - Fan Class - Deciding State and Constructors** +- **Step 03 - OOPS Example - Fan Class - Deciding Behavior with Methods** + +**Why grouped**: These steps provide a foundational overview of object-oriented concepts like class, object, state, and behavior, and apply these to design the `Fan` class. This group covers the basics of constructing a class, establishing its state, and defining methods for behavior. + +### 1. **Puzzle: Creating a Fan Class** + - Create a simple `Fan` class with attributes `speed`, `isOn`, and `color`. Write methods to turn the fan on, change speed, and turn it off. + ```java + class Fan { + private int speed; + private boolean isOn; + private String color; + + public Fan(String color) { + this.speed = 0; + this.isOn = false; + this.color = color; + } + + public void turnOn() { + isOn = true; + speed = 1; + System.out.println("Fan is on."); + } + + public void changeSpeed(int newSpeed) { + if (isOn) { + speed = newSpeed; + System.out.println("Fan speed changed to " + speed); + } else { + System.out.println("Turn the fan on first."); + } + } + + public void turnOff() { + isOn = false; + speed = 0; + System.out.println("Fan is off."); + } + } + + public class Main { + public static void main(String[] args) { + Fan fan = new Fan("Blue"); + fan.turnOn(); + fan.changeSpeed(3); + fan.turnOff(); + } + } + ``` + **Output:** + ``` + Fan is on. + Fan speed changed to 3 + Fan is off. + ``` + +### **Existing Quiz Questions:** + +1. What are used to send instructions/messages to an object? + + - A) Attributes + - B) Methods (Answer: B) + - C) Constructors + +2. What corresponds to the state of an object? + + - A) Member variables (Answer: A) + - B) Methods + - C) Constructors + +3. What is the purpose of constructors in a class? + + - A) To define behavior + - B) To create objects (Answer: B) + + +### **New Quiz Questions:** + +1. **What is the purpose of defining a constructor in a class?** + - A) To provide an alternate name for the class + - B) To initialize object state when created **(Answer: B)** + - C) To define the class’s default behavior + +2. **What does an object represent in OOP?** + - A) An instance of a class with specific state and behavior **(Answer: A)** + - B) A blueprint for creating classes + - C) A set of rules for program structure + +### **Fun Fact:** +- **Fun Fact:** The term "object" in OOP comes from real-life objects, as OOP was designed to mimic the way humans perceive entities with attributes and actions. + +--- + +### **Group 2: Steps 04, 05, and 06 – Object Composition and Class Exercises** + +- **Step 04 - OOPS Exercise - Rectangle Class** +- **Step 05 - Understanding Object Composition with Customer Address Example** +- **Step 06 - Understanding Object Composition - An Exercise - Books and Reviews** + +**Why grouped**: This set delves into more practical exercises in class design, focusing on the `Rectangle` class and understanding object composition. These exercises introduce how classes can hold other classes as components, enhancing understanding of composite relationships in OOP. + +### 1. **Puzzle: Rectangle Area and Perimeter Calculator** + - Write a `Rectangle` class with `width` and `height` attributes. Create methods to calculate the area and perimeter. + ```java + class Rectangle { + private int width; + private int height; + + public Rectangle(int width, int height) { + this.width = width; + this.height = height; + } + + public int area() { + return width * height; + } + + public int perimeter() { + return 2 * (width + height); + } + } + + public class Main { + public static void main(String[] args) { + Rectangle rectangle = new Rectangle(5, 7); + System.out.println("Area: " + rectangle.area()); + System.out.println("Perimeter: " + rectangle.perimeter()); + } + } + ``` + **Output:** + ``` + Area: 35 + Perimeter: 24 + ``` + +### 2. **Puzzle: Book and Review Composition** + - Design a `Book` class with a list of `Review` objects. Each review should have a reviewer name and text. Demonstrate adding reviews and displaying book details with reviews. + ```java + import java.util.ArrayList; + + class Review { + private String reviewer; + private String text; + + public Review(String reviewer, String text) { + this.reviewer = reviewer; + this.text = text; + } + + public String toString() { + return reviewer + ": " + text; + } + } + + class Book { + private String title; + private ArrayList reviews; + + public Book(String title) { + this.title = title; + this.reviews = new ArrayList<>(); + } + + public void addReview(String reviewer, String text) { + reviews.add(new Review(reviewer, text)); + } + + public void showBook() { + System.out.println("Title: " + title); + for (Review review : reviews) { + System.out.println(review); + } + } + } + + public class Main { + public static void main(String[] args) { + Book book = new Book("Java Programming"); + book.addReview("Alice", "Great book for beginners!"); + book.addReview("Bob", "Comprehensive and well-written."); + book.showBook(); + } + } + ``` + **Output:** + ``` + Title: Java Programming + Alice: Great book for beginners! + Bob: Comprehensive and well-written. + ``` + +### **New Quiz Questions:** + +1. **What is object composition in OOP?** + - A) Inheriting properties from another class + - B) Using other objects as fields within a class **(Answer: B)** + - C) Overriding methods in a class + +2. **What is the purpose of the `ArrayList` in the Book and Review example?** + - A) To store a dynamic list of reviews for a book **(Answer: A)** + - B) To provide faster access to reviews + - C) To create a fixed list of reviews + +### **Fun Fact:** +- **Fun Fact:** Object composition is sometimes preferred over inheritance in OOP because it allows for more flexible relationships between objects. + +--- + +### **Group 3: Steps 07, 08, and 09 – Understanding Inheritance** + +- **Step 07 - Understanding Inheritance - Why do we need it?** +- **Step 08 - Object is at the Top of the Inheritance Hierarchy** +- **Step 09 - Inheritance and Overriding - with toString() method** + +**Why grouped**: These steps explore the concept of inheritance, including why it is useful, the role of the Object superclass, and how to override methods. Together, they establish the fundamentals of inheritance and demonstrate how subclasses inherit and customize behavior from their superclass. + +### 1. **Puzzle: Override `toString` Method** + - Create a `Person` superclass with attributes `name` and `age`, and a `toString()` method. Subclass it with `Student` and override `toString` to include the grade level. + ```java + class Person { + protected String name; + protected int age; + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public String toString() { + return "Person[name=" + name + ", age=" + age + "]"; + } + } + + class Student extends Person { + private String grade; + + public Student(String name, int age, String grade) { + super(name, age); + this.grade = grade; + } + + public String toString() { + return "Student[name=" + name + ", age=" + age + ", grade=" + grade + "]"; + } + } + + public class Main { + public static void main(String[] args) { + Student student = new Student("Alice", 20, "Sophomore"); + System.out.println(student); + } + } + ``` + **Output:** + ``` + Student[name=Alice, age=20, grade=Sophomore] + ``` + +### **Existing Quiz Questions:** + +1. What is Inheritance in Object Oriented Programming? + + - A) A mechanism of code reuse (Answer: A) + - B) A mechanism to create new objects + - C) A mechanism to modify existing objects + +2. What is the Object class in Java? + + - A) A user-defined class. + - B) A package in Java system. + - C) A built-in Java library class. (Answer: C) + +3. Which methods of the Object class are available to objects of other Java classes? + + - A) toString(), hashCodel(), and notify() (Answer: A) + - B) setString(), and setint() + - C) getName(), and setEmail() + +4. What happens when the statement System.out.println(person) is executed with an object person? + + - A) The 'toString() method of the Person class is called. (Answer: A) + - B) The 'hashCode()' method of the Person class is called. + - C) The 'notify() ' method of the Person class is called. + +5. Can a Java class directly inherit from two or more classes? + + - A) Yes + - B) No (Answer: B) + +6. What is the purpose of the toString() method in a class? + + - A) To define behavior. + - B) To create objects. + - C) To provide a String representation of an object. (Answer: C) + +### **New Quiz Questions:** + +1. **What is the purpose of overriding a method?** + - A) To replace a superclass method with a subclass-specific implementation **(Answer: A)** + - B) To call a superclass method + - C) To rename a superclass method + +2. **What is the top class in Java’s inheritance hierarchy?** + - A) `Object` **(Answer: A)** + - B) `Class` + - C) `Hierarchy` + +### **Fun Fact:** +- **Fun Fact:** Every Java class is a descendant of `Object`, making `Object` the ancestor of all Java classes. + +--- + +### **Group 4: Steps 10, 11, and 12 – Advanced Inheritance Concepts** + +- **Step 10 - Java Inheritance - Exercise - Student and Employee Classes** +- **Step 11 - Java Inheritance - Default Constructors and super() method call** +- **Step 12 - Java Inheritance - Puzzles - Multiple Inheritance, Reference Variables** + +**Why grouped**: This group focuses on practical applications of inheritance through exercises on constructing subclasses (`Student` and `Employee`) and understanding constructors, super calls, and reference variables. The puzzles add depth by tackling complex scenarios like multiple inheritance and referencing. + +### 1. **Puzzle: Implementing Inheritance with Constructors** + - Create a `Person` superclass with `name` and `age` attributes, and use a constructor to initialize them. Extend it with an `Employee` class that includes an `employeeId` attribute and demonstrates the use of `super()` to call the superclass constructor. + ```java + class Person { + protected String name; + protected int age; + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + } + + class Employee extends Person { + private int employeeId; + + public Employee(String name, int age, int employeeId) { + super(name, age); // Calling the superclass constructor + this.employeeId = employeeId; + } + + public void display() { + System.out.println("Name: " + name + ", Age: " + age + ", Employee ID: " + employeeId); + } + } + + public class Main { + public static void main(String[] args) { + Employee employee = new Employee("John Doe", 30, 1023); + employee.display(); + } + } + ``` + **Output:** + ``` + Name: John Doe, Age: 30, Employee ID: 1023 + ``` + +### 2. **Puzzle: Understanding Reference Variables and Inheritance** + - Given a superclass reference variable pointing to a subclass object, demonstrate how methods are called based on the object’s actual type. + ```java + class Animal { + public void makeSound() { + System.out.println("Animal sound"); + } + } + + class Dog extends Animal { + @Override + public void makeSound() { + System.out.println("Bark"); + } + } + + public class Main { + public static void main(String[] args) { + Animal myDog = new Dog(); + myDog.makeSound(); // Expected to print "Bark" + } + } + ``` + **Output:** + ``` + Bark + ``` + +### **New Quiz Questions:** + +1. **What does the `super` keyword do in a subclass?** + - A) Calls a method in the subclass + - B) Calls a constructor or method in the superclass **(Answer: B)** + - C) Creates a new instance of the superclass + +2. **When using a superclass reference to hold a subclass object, which methods are called?** + - A) Superclass methods only + - B) Subclass methods if overridden **(Answer: B)** + - C) Only default methods + +### **Fun Fact:** +- **Fun Fact:** Java does not support multiple inheritance to avoid the “diamond problem,” where a class could inherit conflicting methods from two parent classes. + +--- + +### **Group 5: Steps 13, 14, and 15 – Abstract Classes and Methods** + +- **Step 13 - Java Abstract Class - Introduction** +- **Step 14 - Java Abstract Class - First Example - Creating Recipes with Template Method** +- **Step 15 - Java Abstract Class - Puzzles** + +**Why grouped**: This group introduces abstract classes and their use cases, emphasizing the flexibility they offer in class hierarchies. These steps cover the basics of defining abstract methods, their role in subclasses, and related puzzles to reinforce the concept. + +### 1. **Puzzle: Create an Abstract `Appliance` Class with a `turnOn` Method** + - Define an abstract `Appliance` class with an abstract method `turnOn()` and a concrete `plugIn()` method. Create a `WashingMachine` subclass that implements `turnOn`. + ```java + abstract class Appliance { + public void plugIn() { + System.out.println("Appliance plugged in."); + } + + public abstract void turnOn(); + } + + class WashingMachine extends Appliance { + @Override + public void turnOn() { + System.out.println("Washing machine is now running."); + } + } + + public class Main { + public static void main(String[] args) { + WashingMachine washer = new WashingMachine(); + washer.plugIn(); + washer.turnOn(); + } + } + ``` + **Output:** + ``` + Appliance plugged in. + Washing machine is now running. + ``` + +### 2. **Puzzle: Implementing a Recipe Template with an Abstract Class** + - Design an abstract `Recipe` class with a `prepare` method. Create a `PastaRecipe` class that provides details for making pasta. + ```java + abstract class Recipe { + public void prepareRecipe() { + boilWater(); + addIngredients(); + serve(); + } + + private void boilWater() { + System.out.println("Boiling water..."); + } + + public abstract void addIngredients(); + + private void serve() { + System.out.println("Serving the dish."); + } + } + + class PastaRecipe extends Recipe { + @Override + public void addIngredients() { + System.out.println("Adding pasta and sauce."); + } + } + + public class Main { + public static void main(String[] args) { + Recipe pasta = new PastaRecipe(); + pasta.prepareRecipe(); + } + } + ``` + **Output:** + ``` + Boiling water... + Adding pasta and sauce. + Serving the dish. + ``` + +### **Existing Quiz Questions:** + +1. What is an abstract method? + + - A) A method without any parameters + - B) A method with a method definition + - C) A method without a method definition (Answer: C) + +2. Can an abstract class be instantiated? + + - A) Yes + - B) No (Answer: B) + +3. What are the advantages of using an abstract class to create a recipe hierarchy? + + - A) Allows for the flexibility and customization of recipes. + - B) Allows for the common structure of recipes to be maintained. + - C) Allows for the creation of multiple recipe types easily. + - D) All of the above (Answer: D) + +4. Which design pattern is used in the recipe hierarchy example? + + - A) Observer pattern + - B) Decorator pattern + - C) Template method pattern (Answer: C) + +5. Can an abstract class have member variables? + + - A) Yes (Answer: A) + - B) No + +6. Can an abstract class have non-abstract methods? + + - A) Yes (Answer: A) + - B) No + +### **New Quiz Questions:** + +1. **What is the purpose of an abstract class?** + - A) To provide partial implementation for subclasses **(Answer: A)** + - B) To define a full implementation for all subclasses + - C) To be instantiated directly + +2. **Which of the following statements about abstract methods is true?** + - A) Abstract methods must have a body + - B) Abstract methods do not have a body and must be implemented by subclasses **(Answer: B)** + - C) Abstract methods can be overridden by any class + +### **Fun Fact:** +- **Fun Fact:** The Template Method design pattern, often implemented with abstract classes, helps create a predefined sequence of steps for subclasses to follow with custom implementations. + +--- + +### **Group 6: Steps 16, 17, 18, 19, 20, and 21 – Interfaces and Polymorphism** + +- **Step 16 - Java Interface - Example 1 - Gaming Console - How to think about Interfaces** +- **Step 17 - Java Interface - Example 2 - Complex Algorithm - API defined by externals** +- **Step 18 - Java Interface - Puzzles - Unimplemented methods, Abstract Classes, Variability** +- **Step 19 - Java Interface vs Abstract Class - A Comparison** +- **Step 20 - Java Interface Flyable and Abstract Class Animal - An Exercise** +- **Step 21 - Polymorphism - An introduction** + +**Why grouped**: This final group dives into interfaces, exploring their usage, differences from abstract classes, and application in polymorphism. By comparing interfaces with abstract classes, it builds a comprehensive understanding of interface-based design and the flexibility of polymorphic behaviors in OOP. + +### 1. **Puzzle: Define a Gaming Console Interface** + - Create an interface `GamingConsole` with methods `start()`, `stop()`, and `reset()`. Implement it in a `PlayStation` class. + ```java + interface GamingConsole { + void start(); + void stop(); + void reset(); + } + + class PlayStation implements GamingConsole { + public void start() { + System.out.println("PlayStation starting..."); + } + + public void stop() { + System.out.println("PlayStation stopping..."); + } + + public void reset() { + System.out.println("PlayStation resetting..."); + } + } + + public class Main { + public static void main(String[] args) { + GamingConsole ps = new PlayStation(); + ps.start(); + ps.reset(); + ps.stop(); + } + } + ``` + **Output:** + ``` + PlayStation starting... + PlayStation resetting... + PlayStation stopping... + ``` + +### 2. **Puzzle: Implementing a Flyable Interface with Polymorphism** + - Create an interface `Flyable` with a `fly()` method. Implement `Flyable` in `Bird` and `Airplane` classes and demonstrate polymorphism by using a `Flyable` reference. + ```java + interface Flyable { + void fly(); + } + + class Bird implements Flyable { + public void fly() { + System.out.println("Bird is flying."); + } + } + + class Airplane implements Flyable { + public void fly() { + System.out.println("Airplane is flying."); + } + } + + public class Main { + public static void main(String[] args) { + Flyable bird = new Bird(); + Flyable airplane = new Airplane(); + + bird.fly(); + airplane.fly(); + } + } + ``` + **Output:** + ``` + Bird is flying. + Airplane is flying. + ``` + +--- + +### **Existing Quiz Questions:** + +1. Who provides the implementation of methods declared in an interface? + + - A) The implementing classes (Answer: A) + - B) The super class of the interface + +### **New Quiz Questions:** + +1. **Which keyword is used to implement an interface?** + - A) `extends` + - B) `implements` **(Answer: B)** + - C) `inherit` + +2. **What is polymorphism in Java?** + - A) The ability for a method to take many forms **(Answer: A)** + - B) Using multiple classes in a project + - C) A process of encapsulation + +### **Fun Fact:** +- **Fun Fact:** Java allows multiple inheritance of interfaces, making it easier to compose behaviors without the complications of multiple inheritance from classes. + +--- + +### Additional Coding Exercises + +### Exercise 1: “Library Management System” – Class and Object Composition +**Description**: Develop a simple library system to manage books, authors, and reviews. This exercise will reinforce object composition, constructors, and `toString()` method usage. + +**Requirements**: +- Create a `Book` class with `title`, `author`, and a list of `Review` objects. +- Implement methods to add reviews and display book details. +- Include an `Author` class that’s part of the `Book` class composition. + +**Code**: +```java +import java.util.ArrayList; +import java.util.List; + +class Author { + private String name; + private String nationality; + + public Author(String name, String nationality) { + this.name = name; + this.nationality = nationality; + } + + public String getName() { + return name; + } + + public String getNationality() { + return nationality; + } + + @Override + public String toString() { + return "Author: " + name + ", Nationality: " + nationality; + } +} + +class Review { + private int rating; + private String comment; + + public Review(int rating, String comment) { + this.rating = rating; + this.comment = comment; + } + + @Override + public String toString() { + return "Rating: " + rating + "/5, Comment: " + comment; + } +} + +class Book { + private String title; + private Author author; + private List reviews; + + public Book(String title, Author author) { + this.title = title; + this.author = author; + this.reviews = new ArrayList<>(); + } + + public void addReview(Review review) { + reviews.add(review); + } + + public void displayBookInfo() { + System.out.println("Title: " + title); + System.out.println(author); + System.out.println("Reviews:"); + for (Review review : reviews) { + System.out.println("- " + review); + } + } +} + +public class LibraryManager { + public static void main(String[] args) { + Author author = new Author("George Orwell", "British"); + Book book = new Book("1984", author); + + book.addReview(new Review(5, "A timeless classic.")); + book.addReview(new Review(4, "Thought-provoking and profound.")); + + book.displayBookInfo(); + } +} +``` + +**Output**: +``` +Title: 1984 +Author: George Orwell, Nationality: British +Reviews: +- Rating: 5/5, Comment: A timeless classic. +- Rating: 4/5, Comment: Thought-provoking and profound. +``` + +--- + +### Exercise 2: “Zoo Animals” – Using Inheritance and Polymorphism +**Description**: Create a `Zoo` class with different types of animals, demonstrating polymorphism and method overriding. + +**Requirements**: +- Create an abstract `Animal` class with a `sound()` method. +- Develop subclasses `Lion`, `Elephant`, and `Monkey` that override `sound()`. +- Use polymorphism to store animals in a list and call their `sound()` methods. + +**Code**: +```java +import java.util.ArrayList; +import java.util.List; + +abstract class Animal { + abstract void sound(); +} + +class Lion extends Animal { + @Override + void sound() { + System.out.println("Lion: Roar!"); + } +} + +class Elephant extends Animal { + @Override + void sound() { + System.out.println("Elephant: Trumpet!"); + } +} + +class Monkey extends Animal { + @Override + void sound() { + System.out.println("Monkey: Ooh-ooh!"); + } +} + +public class Zoo { + public static void main(String[] args) { + List animals = new ArrayList<>(); + animals.add(new Lion()); + animals.add(new Elephant()); + animals.add(new Monkey()); + + System.out.println("Zoo Animals Sound:"); + for (Animal animal : animals) { + animal.sound(); + } + } +} +``` + +**Output**: +``` +Zoo Animals Sound: +Lion: Roar! +Elephant: Trumpet! +Monkey: Ooh-ooh! +``` + +--- + +### Exercise 3: “Recipe Book” – Abstract Class Template +**Description**: Implement a recipe management system with an abstract class to define different recipes, showcasing abstract methods. + +**Requirements**: +- Define an abstract class `Recipe` with methods `prepareIngredients()`, `cook()`, and `serve()`. +- Create `PastaRecipe` and `SaladRecipe` classes that extend `Recipe` and implement these methods. + +**Code**: +```java +abstract class Recipe { + abstract void prepareIngredients(); + abstract void cook(); + abstract void serve(); + + public final void makeRecipe() { + prepareIngredients(); + cook(); + serve(); + } +} + +class PastaRecipe extends Recipe { + @Override + void prepareIngredients() { + System.out.println("Preparing pasta, tomatoes, and cheese."); + } + + @Override + void cook() { + System.out.println("Boiling pasta and cooking sauce."); + } + + @Override + void serve() { + System.out.println("Serving pasta on a plate."); + } +} + +class SaladRecipe extends Recipe { + @Override + void prepareIngredients() { + System.out.println("Chopping lettuce, tomatoes, and cucumbers."); + } + + @Override + void cook() { + System.out.println("Mixing all ingredients."); + } + + @Override + void serve() { + System.out.println("Serving salad in a bowl."); + } +} + +public class RecipeBook { + public static void main(String[] args) { + Recipe pasta = new PastaRecipe(); + Recipe salad = new SaladRecipe(); + + System.out.println("Making Pasta:"); + pasta.makeRecipe(); + System.out.println("\nMaking Salad:"); + salad.makeRecipe(); + } +} +``` + +**Output**: +``` +Making Pasta: +Preparing pasta, tomatoes, and cheese. +Boiling pasta and cooking sauce. +Serving pasta on a plate. + +Making Salad: +Chopping lettuce, tomatoes, and cucumbers. +Mixing all ingredients. +Serving salad in a bowl. +``` + +--- + +### Exercise 4: “Guess the Animal” Game – Using Interface and Polymorphism +**Description**: Build a guessing game where the user is given hints to guess the animal. This will utilize interfaces and reinforce object-oriented design. + +**Requirements**: +- Create an interface `AnimalHint` with a method `hint()`. +- Implement classes for different animals (`LionHint`, `ElephantHint`, etc.), each providing unique hints. +- Allow the user to guess based on the hints provided. + +**Code**: +```java +import java.util.Scanner; + +interface AnimalHint { + void hint(); + String getAnswer(); +} + +class LionHint implements AnimalHint { + public void hint() { + System.out.println("I am the king of the jungle. Who am I?"); + } + + public String getAnswer() { + return "Lion"; + } +} + +class ElephantHint implements AnimalHint { + public void hint() { + System.out.println("I have a long trunk. Who am I?"); + } + + public String getAnswer() { + return "Elephant"; + } +} + +public class GuessTheAnimalGame { + public static void main(String[] args) { + AnimalHint[] animals = { new LionHint(), new ElephantHint() }; + Scanner scanner = new Scanner(System.in); + + for (AnimalHint animal : animals) { + animal.hint(); + System.out.print("Your Guess: "); + String guess = scanner.nextLine(); + + if (guess.equalsIgnoreCase(animal.getAnswer())) { + System.out.println("Correct!"); + } else { + System.out.println("Wrong! The answer was " + animal.getAnswer()); + } + } + + scanner.close(); + } +} +``` + +**Output**: +``` +I am the king of the jungle. Who am I? +Your Guess: Tiger +Wrong! The answer was Lion +I have a long trunk. Who am I? +Your Guess: Elephant +Correct! +``` + +--- + +### **Exercise 5: “Battle Game” – Using Polymorphism and Inheritance** +**Description**: Create a battle game where players have different characters, each with unique abilities. This exercise reinforces polymorphism, method overriding, and class inheritance. + +**Requirements**: +- Create a superclass `Character` with `name` and `attack()` method. +- Define subclasses `Warrior`, `Mage`, and `Archer`, each overriding the `attack()` method with unique behaviors. +- Simulate a battle by allowing characters to attack each other. + +**Code**: +```java +abstract class Character { + protected String name; + + public Character(String name) { + this.name = name; + } + + public abstract void attack(); +} + +class Warrior extends Character { + public Warrior(String name) { + super(name); + } + + @Override + public void attack() { + System.out.println(name + " attacks with a sword!"); + } +} + +class Mage extends Character { + public Mage(String name) { + super(name); + } + + @Override + public void attack() { + System.out.println(name + " casts a fireball!"); + } +} + +class Archer extends Character { + public Archer(String name) { + super(name); + } + + @Override + public void attack() { + System.out.println(name + " shoots an arrow!"); + } +} + +public class BattleGame { + public static void main(String[] args) { + Character warrior = new Warrior("Thor"); + Character mage = new Mage("Merlin"); + Character archer = new Archer("Robin"); + + System.out.println("Battle Begins!"); + warrior.attack(); + mage.attack(); + archer.attack(); + } +} +``` + +**Output**: +``` +Battle Begins! +Thor attacks with a sword! +Merlin casts a fireball! +Robin shoots an arrow! +``` + +--- + +### **Exercise 6: “Quiz Master” Game – Interface with Question Types** +**Description**: Create a quiz game where each question has a different type, like multiple choice and true/false. This exercise reinforces interface design and polymorphism. + +**Requirements**: +- Create an interface `Question` with a `displayQuestion()` and `checkAnswer()` methods. +- Implement `MultipleChoiceQuestion` and `TrueFalseQuestion` classes. +- Test the quiz by presenting questions and validating answers. + +**Code**: +```java +import java.util.Scanner; + +interface Question { + void displayQuestion(); + boolean checkAnswer(String answer); +} + +class MultipleChoiceQuestion implements Question { + private String question; + private String[] options; + private String correctAnswer; + + public MultipleChoiceQuestion(String question, String[] options, String correctAnswer) { + this.question = question; + this.options = options; + this.correctAnswer = correctAnswer; + } + + @Override + public void displayQuestion() { + System.out.println(question); + for (int i = 0; i < options.length; i++) { + System.out.println((i + 1) + ": " + options[i]); + } + } + + @Override + public boolean checkAnswer(String answer) { + return options[Integer.parseInt(answer) - 1].equals(correctAnswer); + } +} + +class TrueFalseQuestion implements Question { + private String question; + private boolean correctAnswer; + + public TrueFalseQuestion(String question, boolean correctAnswer) { + this.question = question; + this.correctAnswer = correctAnswer; + } + + @Override + public void displayQuestion() { + System.out.println(question + " (true/false)"); + } + + @Override + public boolean checkAnswer(String answer) { + return Boolean.parseBoolean(answer) == correctAnswer; + } +} + +public class QuizMasterGame { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + Question[] quiz = { + new MultipleChoiceQuestion("What is the capital of France?", new String[]{"Berlin", "Paris", "Rome", "Madrid"}, "Paris"), + new TrueFalseQuestion("The earth is flat.", false) + }; + + for (Question question : quiz) { + question.displayQuestion(); + System.out.print("Your Answer: "); + String answer = scanner.nextLine(); + if (question.checkAnswer(answer)) { + System.out.println("Correct!"); + } else { + System.out.println("Incorrect."); + } + System.out.println(); + } + + scanner.close(); + } +} +``` + +**Output**: +``` +What is the capital of France? +1: Berlin +2: Paris +3: Rome +4: Madrid +Your Answer: 2 +Correct! + +The earth is flat. (true/false) +Your Answer: false +Correct! +``` + +--- + +### **Exercise 7: “Racing Game” – Abstract Class with Interfaces** +**Description**: Create a racing game where players can choose vehicles with different speeds and fuel capacities. This exercise uses an abstract class and interfaces to demonstrate polymorphism and encapsulation. + +**Requirements**: +- Create an abstract class `Vehicle` with a `drive()` method and attributes like `speed` and `fuel`. +- Implement an interface `Refuelable` to add fuel to vehicles. +- Define `Car` and `Bike` classes extending `Vehicle` and implementing `Refuelable`. + +**Code**: +```java +interface Refuelable { + void refuel(int fuelAmount); +} + +abstract class Vehicle implements Refuelable { + protected String name; + protected int speed; + protected int fuel; + + public Vehicle(String name, int speed, int fuel) { + this.name = name; + this.speed = speed; + this.fuel = fuel; + } + + public void drive() { + if (fuel > 0) { + fuel--; + System.out.println(name + " is driving at " + speed + " km/h. Fuel left: " + fuel); + } else { + System.out.println(name + " is out of fuel!"); + } + } + + @Override + public abstract void refuel(int fuelAmount); +} + +class Car extends Vehicle { + public Car(String name, int speed, int fuel) { + super(name, speed, fuel); + } + + @Override + public void refuel(int fuelAmount) { + fuel += fuelAmount; + System.out.println(name + " refueled with " + fuelAmount + " liters. Total fuel: " + fuel); + } +} + +class Bike extends Vehicle { + public Bike(String name, int speed, int fuel) { + super(name, speed, fuel); + } + + @Override + public void refuel(int fuelAmount) { + fuel += fuelAmount; + System.out.println(name + " refueled with " + fuelAmount + " liters. Total fuel: " + fuel); + } +} + +public class RacingGame { + public static void main(String[] args) { + Vehicle car = new Car("Ferrari", 150, 5); + Vehicle bike = new Bike("Ducati", 100, 3); + + System.out.println("Race Start!"); + car.drive(); + car.drive(); + car.refuel(2); + car.drive(); + + bike.drive(); + bike.refuel(1); + bike.drive(); + } +} +``` + +**Output**: +``` +Race Start! +Ferrari is driving at 150 km/h. Fuel left: 4 +Ferrari is driving at 150 km/h. Fuel left: 3 +Ferrari refueled with 2 liters. Total fuel: 5 +Ferrari is driving at 150 km/h. Fuel left: 4 + +Ducati is driving at 100 km/h. Fuel left: 2 +Ducati refueled with 1 liters. Total fuel: 3 +Ducati is driving at 100 km/h. Fuel left: 2 +``` + +--- + +## Section 22: Collections in Java Programming + +#### **Group 1: Steps 1–6 – Basics of Collections and List Interface** + +- **Step 01**: Java Collections - Section Overview with Need for Collections +- **Step 02**: List Interface - Introduction - Position is King +- **Step 03**: List Interface - Immutability and Introduction of Implementations - ArrayList +- **Step 04**: List Interface Implementations - ArrayList vs LinkedList +- **Step 05**: List Interface Implementations - ArrayList vs Vector +- **Step 06**: List Interface - Methods to add, remove, and change elements and lists + +**Why Grouped:** This group covers the basics of the Collections framework, introduces the `List` interface, and explores its different implementations, such as `ArrayList`, `LinkedList`, and `Vector`. Basic operations on lists like adding, removing, and modifying elements are also discussed. + +#### **Puzzles** + +1. **Puzzle: Working with ArrayList Basics** + - **Problem**: Create an ArrayList of integers, add integers from 1 to 10, replace the element at index 5 with 50, and remove the element at index 3. + ```java + import java.util.ArrayList; + + public class ArrayListPuzzle { + public static void main(String[] args) { + ArrayList numbers = new ArrayList<>(); + for (int i = 1; i <= 10; i++) { + numbers.add(i); + } + numbers.set(5, 50); // Replaces element at index 5 + numbers.remove(3); // Removes element at index 3 + System.out.println(numbers); + } + } + ``` + **Output**: `[1, 2, 3, 5, 50, 7, 8, 9, 10]` + +2. **Puzzle: Using LinkedList** + - **Problem**: Create a LinkedList of strings representing tasks for a day. Add "Breakfast" and "Exercise" at the beginning, "Work" and "Lunch" in the middle, and remove "Exercise." + ```java + import java.util.LinkedList; + + public class LinkedListPuzzle { + public static void main(String[] args) { + LinkedList tasks = new LinkedList<>(); + tasks.add("Breakfast"); + tasks.add("Exercise"); + tasks.add("Work"); + tasks.add(2, "Lunch"); // Insert in the middle + tasks.remove("Exercise"); + System.out.println(tasks); + } + } + ``` + **Output**: `[Breakfast, Lunch, Work]` + +### **Existing Quiz Questions** + +1. What is List Interface used for? + + - A) To implement an ordered collection in Java programs. (Answer: A) + - B) o implement an unordered collection in Java programs. + - C) To implement a stack data structure in Java programs. + +### **New Quiz Questions** + +1. **Which of the following interfaces allows duplicate elements in Java?** + - A) `Set` + - B) `Map` + - C) `List` **(Answer: C)** + +2. **Which class in Java is synchronized by default?** + - A) `ArrayList` + - B) `LinkedList` + - C) `Vector` **(Answer: C)** + +3. **What is the primary difference between `ArrayList` and `LinkedList`?** + - A) `ArrayList` is slower for insertions at the beginning **(Answer: A)** + - B) `LinkedList` does not allow null elements + - C) `ArrayList` does not allow duplicate elements + +### **Fun Fact** +- **Did you know?** The Collections Framework was first introduced in Java 1.2, standardizing data structures like `List`, `Set`, and `Map`. + +--- + +#### **Group 2: Steps 7–12 – List Operations and Iteration Techniques** + +- **Step 07**: List and ArrayList - Iterating around elements +- **Step 08**: List and ArrayList - Choosing iteration approach for printing and deleting +- **Step 09**: List and ArrayList - Puzzles - Type Safety and Removing Integers +- **Step 10**: List and ArrayList - Sorting - Introduction to Collections sort static +- **Step 11**: List and ArrayList - Sorting - Implementing Comparable Interface in Students +- **Step 12**: List and ArrayList - Sorting - Providing Flexibility by implementing Comparator + +**Why Grouped:** This group delves into various list operations, including iteration techniques, removing elements, sorting, and understanding type safety. It includes both `Comparable` and `Comparator` interfaces for customized sorting. + +--- + +#### **Puzzles** + +1. **Puzzle: Removing Even Numbers** + - **Problem**: Create an ArrayList of numbers from 1 to 20 and remove all even numbers using an iterator. + ```java + import java.util.ArrayList; + import java.util.Iterator; + + public class RemoveEvenNumbers { + public static void main(String[] args) { + ArrayList numbers = new ArrayList<>(); + for (int i = 1; i <= 20; i++) { + numbers.add(i); + } + Iterator iterator = numbers.iterator(); + while (iterator.hasNext()) { + if (iterator.next() % 2 == 0) { + iterator.remove(); + } + } + System.out.println(numbers); + } + } + ``` + **Output**: `[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]` + + +### **New Quiz Questions** + +1. **Which method removes elements safely while iterating in Java?** + - A) `ArrayList.remove()` + - B) `Iterator.remove()` **(Answer: B)** + - C) `List.removeAll()` + +2. **What’s the primary use of the `Comparable` interface?** + - A) To allow custom comparison in sorting **(Answer: A)** + - B) To provide default comparison + - C) To iterate over elements in reverse + +### **Fun Fact** +- **Fun Fact:** Java allows both `Comparable` and `Comparator` for sorting. `Comparable` is for natural ordering, while `Comparator` enables custom sorting! + +--- + +#### **Group 3: Steps 13–17 – Sets and Uniqueness** + +- **Step 13**: List and ArrayList - A Summary +- **Step 14**: Set Interface - Introduction - No Duplication +- **Step 15**: Understanding Data Structures - Array, LinkedList and Hashing +- **Step 16**: Understanding Data Structures - Tree - Sorted Order +- **Step 17**: Set Interface - Hands on - HashSet, LinkedHashSet, and TreeSet + +**Why Grouped:** This group introduces `Set` interfaces and implementations like `HashSet`, `LinkedHashSet`, and `TreeSet`, emphasizing the uniqueness constraint and different types of ordering. + +#### **Puzzles** + +1. **Puzzle: Unique Student IDs** + - **Problem**: Create a `HashSet` of integers representing student IDs. Add duplicates and see if they’re automatically removed. + ```java + import java.util.HashSet; + + public class StudentIDs { + public static void main(String[] args) { + HashSet ids = new HashSet<>(); + ids.add(101); + ids.add(102); + ids.add(103); + ids.add(101); // Duplicate + System.out.println(ids); + } + } + ``` + **Output**: `[101, 102, 103]` + +--- + +### **Existing Quiz Questions** + +1. How does Java Set handle duplicate elements? + + - A) Stores all duplicate elements. + - B) Stores the first occurrence of an element. (Answer: B) + - C) Throws an exception when duplicates are added. + +2. What does the ‘equals’ method need to return for two objects to be considered equal and treated as duplicates? + + - A) true (Answer: A) + - B) false + +### **New Quiz Questions** + +1. **Which implementation of `Set` maintains insertion order?** + - A) `HashSet` + - B) `LinkedHashSet` **(Answer: B)** + - C) `TreeSet` + +2. **What property does `HashSet` ensure?** + - A) Elements are sorted + - B) Elements are unique **(Answer: B)** + - C) Elements are duplicated + +### **Fun Fact** +- **Fun Fact:** Hashing is a unique process used in `HashSet` to organize data for efficient retrieval, even with large sets! + +--- + +#### **Group 4: Steps 18–22 – Advanced Set Operations and Introduction to Queues** + +- **Step 18**: Set Interface - Exercise - Find Unique Characters in a List +- **Step 19**: TreeSet - Methods from NavigableSet - floor, lower, upper, subSet, headSet +- **Step 20**: Queue Interface - Process Elements in Order +- **Step 21**: Introduction to PriorityQueue - Basic Methods and Customized Priority +- **Step 22**: Map Interface - An Introduction - Key and Value + +**Why Grouped:** This group extends the `Set` operations and dives into `Queue` concepts, including priority and order in processing. It introduces `PriorityQueue` and basic `Map` functionalities. + +#### **Puzzles** + +1. **Puzzle: Task Prioritization with PriorityQueue** + - **Problem**: Create a `PriorityQueue` for tasks with different priorities and display them in order of priority. + ```java + import java.util.PriorityQueue; + + public class TaskPriority { + public static void main(String[] args) { + PriorityQueue tasks = new PriorityQueue<>(); + tasks.add("Complete project"); + tasks.add("Buy groceries"); + tasks.add("Go for a run"); + tasks.add("Read a book"); + while (!tasks.isEmpty()) { + System.out.println(tasks.poll()); + } + } + } + ``` + **Output**: + ``` + Buy groceries + Complete project + Go for a run + Read a book + ``` + +### **New Quiz Questions** + +1. **What is the primary benefit of a PriorityQueue?** + - A) It maintains insertion order + - B) It processes elements by priority **(Answer: B)** + - C) It duplicates elements + +2. **Which method retrieves the first element in a PriorityQueue without removing it?** + - A) `poll()` + - B) `peek()` **(Answer: B)** + - C) `pop()` + +--- + +### **Fun Fact** +- **Fun Fact:** Java’s `PriorityQueue` is used in scheduling systems to manage tasks in order of importance or urgency! + +--- + +#### **Group 5: Steps 23–27 – Map Implementations and Advanced Operations** + +- **Step 23**: Map Interface - Implementations - `HashMap`, `HashTable`, `LinkedHashMap`, and `TreeMap` +- **Step 24**: Map Interface - Basic Operations +- **Step 25**: Map Interface - Comparison - `HashMap` vs `LinkedHashMap` vs `TreeMap` +- **Step 26**: Map Interface - Exercise - Count occurrences of characters and words +- **Step 27**: `TreeMap` - Methods from `NavigableMap` - `floorKey`, `higherKey`, `firstEntry`, `lastEntry` + +**Why Grouped:** This group dives into different implementations of the `Map` interface (`HashMap`, `LinkedHashMap`, `TreeMap`, `Hashtable`) and their basic operations, as well as specific methods from `NavigableMap` to access elements by key. Exercises explore counting occurrences and performing advanced operations with `TreeMap`. + +#### **Puzzles** + +1. **Puzzle: Count Character Frequency in a String** + - **Problem**: Use a `HashMap` to count the occurrences of each character in the string "Programming". + ```java + import java.util.HashMap; + + public class CharFrequency { + public static void main(String[] args) { + String text = "Programming"; + HashMap frequencyMap = new HashMap<>(); + + for (char c : text.toCharArray()) { + frequencyMap.put(c, frequencyMap.getOrDefault(c, 0) + 1); + } + System.out.println(frequencyMap); + } + } + ``` + **Output**: `{P=1, r=2, o=1, g=2, a=1, m=2, i=1, n=1}` + +2. **Puzzle: Find Word Frequency in a Sentence** + - **Problem**: Using a `HashMap`, count the number of occurrences of each word in the sentence "Java is great and Java is versatile". + ```java + import java.util.HashMap; + + public class WordFrequency { + public static void main(String[] args) { + String text = "Java is great and Java is versatile"; + String[] words = text.split(" "); + HashMap wordMap = new HashMap<>(); + + for (String word : words) { + wordMap.put(word, wordMap.getOrDefault(word, 0) + 1); + } + System.out.println(wordMap); + } + } + ``` + **Output**: `{Java=2, is=2, great=1, and=1, versatile=1}` + +3. **Puzzle: Working with TreeMap - NavigableMap Methods** + - **Problem**: Using a `TreeMap`, add a few country-population pairs and use `floorKey`, `higherKey`, `firstEntry`, and `lastEntry` methods to query the data. + ```java + import java.util.TreeMap; + + public class CountryPopulation { + public static void main(String[] args) { + TreeMap countries = new TreeMap<>(); + countries.put("USA", 331000000); + countries.put("India", 1380000000); + countries.put("China", 1440000000); + countries.put("Brazil", 213000000); + + System.out.println("Countries in TreeMap: " + countries); + System.out.println("Country with population <= India: " + countries.floorKey("India")); + System.out.println("Country with population > India: " + countries.higherKey("India")); + System.out.println("First entry: " + countries.firstEntry()); + System.out.println("Last entry: " + countries.lastEntry()); + } + } + ``` + **Output**: + ``` + Countries in TreeMap: {Brazil=213000000, China=1440000000, India=1380000000, USA=331000000} + Country with population <= India: India + Country with population > India: USA + First entry: Brazil=213000000 + Last entry: USA=331000000 + ``` + +### **Existing Quiz Questions** + +1. What is the size of this ‘map’? + +```java +Map map = Map.of("A", 3, "B", 5, "Z", 10); +``` + +- A) 3 (Answer: A) +- B) 4 +- C) 6 + +2. What is the value associated with the key “Z” in ‘map’? + +```java +Map map = Map.of("A", 3, "B", 5, "Z", 10); +``` + +- A) 3 +- B) null +- C) 10 (Answer: C) + +3. What is the output of ‘map.containsValue(4)’? + +```java +Map map = Map.of("A", 3, "B", 5, "Z", 10); +``` + +- A) true +- B) false (Answer: B) + +4. Which of the following map implementations maintains natural sorted order of the keys? + +- A) HashMap +- B) LinkedHashMap +- C) TreeMap (Answer: C) + +5. Which of the following map implementations does not guarantee the order of stored elements? + +- A) HashMap (Answer: A) +- B) LinkedHashMap + +6. Which of the following map implementations maintains insertion order of elements? + +- A) HashMap +- B) LinkedHashMap (Answer: B) +- C) TreeMap + +7. What is the output of the following code? + +```java +Map map = Map.of("A", 1, "B", 2, "C", 3); +map.put("D", 4); +System.out.println(map.size()); +``` + +- A) 3 +- B) 4 +- C) Compilation error (Answer: C) + +8. What is the output of the following code? + +```java +Map map = Map.of("A", 1, "B", 2, "C", 3); +System.out.println(map.keySet()); +``` + +- A) ["A", "B", "C"] (Answer: A) +- B) [1, 2, 3] +- C) ["A"], ['"B"], ["C"] + +9. Which interface provides a contract to implement collections of elements in the form of (key, value) pairs? + +- A) List +- B) Set +- C) Map (Answer: C) + +10. What is the main difference between a HashMap and a TreeMap? + +- A) HashMap stores elements in natural sorted order while TreeMap is unordered. +- B) HashMap maintains insertion order while TreeMap is unsorted. +- C) HashMap and TreeMap are both unordered and unsorted. +- D) HashMap is based on a hash table while TreeMap is stored in a tree data structure and maintains natural sorted order. (Answer: D) + +### **New Quiz Questions** + +1. **What is a primary difference between `HashMap` and `TreeMap`?** + - A) `TreeMap` allows duplicate keys + - B) `HashMap` is sorted by keys + - C) `TreeMap` is sorted by keys **(Answer: C)** + +2. **Which of the following guarantees insertion order?** + - A) `HashMap` + - B) `LinkedHashMap` **(Answer: B)** + - C) `TreeMap` + +3. **What does the `getOrDefault` method do in a `Map`?** + - A) Inserts a default value in the map + - B) Returns the value for a key or a default value if key isn’t present **(Answer: B)** + - C) Returns the key’s default hash code + +4. **What does the `floorKey` method in `TreeMap` do?** + - A) Finds the largest key less than or equal to the given key **(Answer: A)** + - B) Finds the smallest key greater than or equal to the given key + - C) Finds the first key in the map + +### **Fun Fact** +- **Fun Fact:** `TreeMap` is implemented as a Red-Black Tree, which is a balanced binary tree structure, allowing efficient data retrieval and ordering by key. + +--- + +#### **Group 6: Step 28 – Java Collections Conclusion and Tips** + +- **Step 28**: Java Collections - Conclusion with Three Tips + +**Why Grouped:** This step wraps up the Java Collections section, summarizing key takeaways and offering tips for effective usage of collections in Java. + +### **New Quiz Questions** + +1. **Which collection type would you choose for fast retrieval by key?** + - A) `Set` + - B) `Map` **(Answer: B)** + - C) `List` + +2. **What should you consider when choosing between `ArrayList` and `LinkedList`?** + - A) Sorting requirements + - B) Frequency of additions and deletions **(Answer: B)** + - C) Duplicate handling + +3. **Which data structure is typically used for implementing priority queues?** + - A) Linked List + - B) Array + - C) Heap **(Answer: C)** + +### **Fun Fact** +- **Fun Fact:** Java Collections Framework has been optimized over many versions of Java, with each collection having a unique purpose based on efficiency, order, and flexibility. + +--- + +### Additional Coding Exercises + +### Exercise 1: Word Frequency Counter +**Description:** Count the frequency of each word in a given paragraph. + +```java +import java.util.HashMap; +import java.util.Map; + +public class WordFrequencyCounter { + public static void main(String[] args) { + String paragraph = "Java is fun. Java is powerful. Java is also popular!"; + String[] words = paragraph.toLowerCase().replaceAll("[^a-z ]", "").split(" "); + + Map wordCount = new HashMap<>(); + + for (String word : words) { + if (word.length() >= 3) { + wordCount.put(word, wordCount.getOrDefault(word, 0) + 1); + } + } + + System.out.println("Word Frequencies: " + wordCount); + } +} +``` + +**Output:** +``` +Word Frequencies: {java=3, fun=1, powerful=1, also=1, popular=1} +``` + +--- + +### Exercise 2: Grade Book with LinkedList +**Description:** Implement a simple grade book using a `LinkedList`. + +```java +import java.util.LinkedList; + +public class GradeBook { + public static void main(String[] args) { + LinkedList grades = new LinkedList<>(); + + grades.add(85); + grades.add(92); + grades.add(76); + grades.add(88); + + System.out.println("Grades: " + grades); + + grades.removeFirstOccurrence(76); + System.out.println("Grades after removal: " + grades); + + System.out.println("Contains 92? " + grades.contains(92)); + } +} +``` + +**Output:** +``` +Grades: [85, 92, 76, 88] +Grades after removal: [85, 92, 88] +Contains 92? true +``` + +--- + +### Exercise 3: High Scores Tracker with TreeMap +**Description:** Use a `TreeMap` to maintain high scores sorted by score in descending order. + +```java +import java.util.TreeMap; + +public class HighScoresTracker { + public static void main(String[] args) { + TreeMap highScores = new TreeMap<>((a, b) -> b - a); + + highScores.put(95, "Alice"); + highScores.put(85, "Bob"); + highScores.put(100, "Cindy"); + + System.out.println("High Scores: " + highScores); + + System.out.println("Top Score: " + highScores.firstEntry()); + } +} +``` + +**Output:** +``` +High Scores: {100=Cindy, 95=Alice, 85=Bob} +Top Score: 100=Cindy +``` + +--- + +### Exercise 4: Fruit Market Inventory Game (ArrayList & Set) +**Description:** Simulate a market inventory system, showing unique fruit items. + +```java +import java.util.ArrayList; +import java.util.HashSet; + +public class FruitMarketInventory { + public static void main(String[] args) { + ArrayList fruits = new ArrayList<>(); + + fruits.add("Apple"); + fruits.add("Banana"); + fruits.add("Apple"); + fruits.add("Orange"); + System.out.println("Fruit Inventory: " + fruits); + + HashSet uniqueFruits = new HashSet<>(fruits); + System.out.println("Unique Fruits: " + uniqueFruits); + } +} +``` + +**Output:** +``` +Fruit Inventory: [Apple, Banana, Apple, Orange] +Unique Fruits: [Apple, Banana, Orange] +``` + +--- + +### **Exercise 5: “Student Attendance Tracker”** +**Description:** Create a program that tracks student attendance using a `HashMap`. Each student has a name and a count of attended classes. + +**Requirements:** +- The program should allow adding students and incrementing their attendance. +- The attendance should be displayed at the end in descending order of attendance. + +**Code:** +```java +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; +import java.util.TreeMap; +import java.util.Comparator; + +public class AttendanceTracker { + public static void main(String[] args) { + Map attendanceMap = new HashMap<>(); + Scanner scanner = new Scanner(System.in); + + System.out.println("Student Attendance Tracker:"); + System.out.println("Commands: add [name], present [name], display, exit"); + + while (true) { + System.out.print("Enter command: "); + String input = scanner.nextLine(); + String[] command = input.split(" "); + + if (command[0].equalsIgnoreCase("add")) { + String name = command[1]; + attendanceMap.put(name, 0); + System.out.println("Added student: " + name); + + } else if (command[0].equalsIgnoreCase("present")) { + String name = command[1]; + attendanceMap.put(name, attendanceMap.getOrDefault(name, 0) + 1); + System.out.println("Marked present: " + name); + + } else if (command[0].equalsIgnoreCase("display")) { + System.out.println("Attendance Summary:"); + attendanceMap.entrySet() + .stream() + .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) + .forEach(entry -> System.out.println(entry.getKey() + ": " + entry.getValue())); + } else if (command[0].equalsIgnoreCase("exit")) { + break; + } + } + scanner.close(); + } +} +``` + +**Output:** +``` +Commands: add [name], present [name], display, exit +Enter command: add Alice +Added student: Alice +Enter command: present Alice +Marked present: Alice +Enter command: display +Attendance Summary: +Alice: 1 +``` + +--- + +### **Exercise 6: “Classroom Game - Guess the Word”** +**Description:** Create a game where students guess words. Each word guessed correctly is removed from a list, and the player’s score is tracked. + +**Requirements:** +- A predefined list of words. +- A score counter for correct guesses. +- The game ends when all words are guessed or a user types “exit.” + +**Code:** +```java +import java.util.ArrayList; +import java.util.Scanner; + +public class GuessTheWordGame { + public static void main(String[] args) { + ArrayList words = new ArrayList<>(); + words.add("Java"); + words.add("Collections"); + words.add("HashMap"); + words.add("ArrayList"); + + int score = 0; + Scanner scanner = new Scanner(System.in); + + System.out.println("Welcome to Guess the Word Game!"); + System.out.println("Type 'exit' to quit."); + + while (!words.isEmpty()) { + System.out.print("Guess a word: "); + String guess = scanner.nextLine(); + + if (guess.equalsIgnoreCase("exit")) break; + + if (words.contains(guess)) { + words.remove(guess); + score++; + System.out.println("Correct! Your score: " + score); + } else { + System.out.println("Incorrect! Try again."); + } + } + + System.out.println("Game Over! Final Score: " + score); + scanner.close(); + } +} +``` + +**Output:** +``` +Welcome to Guess the Word Game! +Guess a word: Java +Correct! Your score: 1 +Guess a word: HashMap +Correct! Your score: 2 +Game Over! Final Score: 2 +``` + +--- + +### **Exercise 7: “Zoo Animal Counter” - Using Sets and Maps** +**Description:** Simulate a zoo animal tracker. This program will keep track of unique animals and their counts as they enter or leave the zoo. + +**Requirements:** +- Use a `HashSet` to track unique animal species. +- Use a `HashMap` to count the number of animals of each species. +- Display all animals in the zoo with their counts. + +**Code:** +```java +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Scanner; + +public class ZooAnimalTracker { + public static void main(String[] args) { + HashSet animalSpecies = new HashSet<>(); + Map animalCount = new HashMap<>(); + Scanner scanner = new Scanner(System.in); + + System.out.println("Zoo Animal Tracker:"); + System.out.println("Commands: add [species], remove [species], display, exit"); + + while (true) { + System.out.print("Enter command: "); + String[] command = scanner.nextLine().split(" "); + + if (command[0].equalsIgnoreCase("add")) { + String species = command[1]; + animalSpecies.add(species); + animalCount.put(species, animalCount.getOrDefault(species, 0) + 1); + System.out.println("Added " + species); + + } else if (command[0].equalsIgnoreCase("remove")) { + String species = command[1]; + if (animalCount.getOrDefault(species, 0) > 0) { + animalCount.put(species, animalCount.get(species) - 1); + if (animalCount.get(species) == 0) { + animalSpecies.remove(species); + } + System.out.println("Removed one " + species); + } else { + System.out.println("No such species in the zoo."); + } + + } else if (command[0].equalsIgnoreCase("display")) { + System.out.println("Animals in the zoo:"); + animalCount.forEach((species, count) -> System.out.println(species + ": " + count)); + } else if (command[0].equalsIgnoreCase("exit")) { + break; + } + } + scanner.close(); + } +} +``` + +**Output:** +``` +Commands: add [species], remove [species], display, exit +Enter command: add Lion +Added Lion +Enter command: add Elephant +Added Elephant +Enter command: display +Animals in the zoo: +Lion: 1 +Elephant: 1 +``` + +--- + +### **Exercise 8: “Library Book Borrowing System” - Using Map and Queue** +**Description:** Build a library system that allows users to borrow books. Each book is represented by a title and the borrower’s name. + +**Requirements:** +- Use a `HashMap` to store book titles and borrowers. +- Allow checking out and returning books. +- Track a queue of borrowers for each book. + +**Code:** +```java +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.Scanner; + +public class LibrarySystem { + public static void main(String[] args) { + Map> bookBorrowers = new HashMap<>(); + Scanner scanner = new Scanner(System.in); + + System.out.println("Library Book Borrowing System:"); + System.out.println("Commands: borrow [book] [name], return [book], queue [book], exit"); + + while (true) { + System.out.print("Enter command: "); + String[] command = scanner.nextLine().split(" "); + + if (command[0].equalsIgnoreCase("borrow")) { + String book = command[1]; + String name = command[2]; + bookBorrowers.putIfAbsent(book, new LinkedList<>()); + Queue queue = bookBorrowers.get(book); + + if (queue.isEmpty()) { + System.out.println(name + " borrowed " + book); + } else { + queue.offer(name); + System.out.println(name + " added to the waiting list for " + book); + } + } else if (command[0].equalsIgnoreCase("return")) { + String book = command[1]; + Queue queue = bookBorrowers.get(book); + + if (!queue.isEmpty()) { + String nextBorrower = queue.poll(); + System.out.println(nextBorrower + " can now borrow " + book); + } else { + System.out.println("No one is in line for " + book); + } + } else if (command[0].equalsIgnoreCase("queue")) { + String book = command[1]; + System.out.println("Waiting list for " + book + ": " + bookBorrowers.getOrDefault(book, new + + LinkedList<>())); + } else if (command[0].equalsIgnoreCase("exit")) { + break; + } + } + scanner.close(); + } +} +``` + +**Output:** +``` +Commands: borrow [book] [name], return [book], queue [book], exit +Enter command: borrow Java101 Alice +Alice borrowed Java101 +Enter command: borrow Java101 Bob +Bob added to the waiting list for Java101 +Enter command: queue Java101 +Waiting list for Java101: [Bob] +``` + +--- + +## Section 24: Generics in Java Programming + +#### **Group 1: Steps 1–2 – Introduction and Implementing Generics** + +- **Step 01**: Introduction to Generics - Why do we need Generics? +- **Step 02**: Implementing Generics for the Custom List + +**Why Grouped:** These steps introduce the concept of generics and why they’re essential in Java. Step 2 transitions to practical implementation, applying generics to a custom list class, allowing it to work with any data type. + +#### **Puzzles** + +1. **Puzzle: Create a Custom List with Generics** + - **Problem:** Modify a `MyCustomList` class to store elements of any type and add a `get(int index)` method to retrieve an element by its index. + + **Code:** + ```java + import java.util.ArrayList; + + class MyCustomList { + private ArrayList list = new ArrayList<>(); + + public void addElement(T element) { + list.add(element); + } + + public T getElement(int index) { + return list.get(index); + } + + @Override + public String toString() { + return list.toString(); + } + } + + public class GenericsPuzzle { + public static void main(String[] args) { + MyCustomList stringList = new MyCustomList<>(); + stringList.addElement("Hello"); + stringList.addElement("Generics"); + System.out.println("String List: " + stringList); + + MyCustomList intList = new MyCustomList<>(); + intList.addElement(10); + intList.addElement(20); + System.out.println("Integer List: " + intList); + } + } + ``` + **Output:** + ``` + String List: [Hello, Generics] + Integer List: [10, 20] + ``` + +2. **Puzzle: Implement a Generic `addElement` and `removeElement` Method** + - **Problem:** Extend `MyCustomList` with methods to add and remove elements dynamically. + + **Code:** + ```java + class MyCustomList { + private ArrayList list = new ArrayList<>(); + + public void addElement(T element) { + list.add(element); + } + + public void removeElement(T element) { + list.remove(element); + } + + @Override + public String toString() { + return list.toString(); + } + } + + public class GenericsTest { + public static void main(String[] args) { + MyCustomList doubleList = new MyCustomList<>(); + doubleList.addElement(3.14); + doubleList.addElement(2.71); + System.out.println("Before removal: " + doubleList); + + doubleList.removeElement(2.71); + System.out.println("After removal: " + doubleList); + } + } + ``` + **Output:** + ``` + Before removal: [3.14, 2.71] + After removal: [3.14] + ``` + +#### **New Quiz Questions** + +1. **What is the purpose of generics in Java?** + - A) To restrict classes to specific data types + - B) To allow classes to work with different data types **(Answer: B)** + - C) To enhance security + +2. **What symbol is used to denote a generic type?** + - A) `` **(Answer: A)** + - B) `[G]` + - C) `{T}` + +### **Fun Fact** +- **Fun Fact:** The concept of generics was introduced in Java 5 to add more type safety and reduce casting errors. + +--- + +#### **Group 2: Step 3 – Extending Custom List with Generic Return Method** + +- **Step 03**: Extending Custom List with a Generic Return Method + +**Why Grouped:** This step builds on the previous custom list by adding a generic return method, showcasing the flexibility of generics in method return types. + +#### **Puzzle** + +1. **Puzzle: Adding a Generic `getElement` Method** + - **Problem:** Create a generic `getElement(int index)` method to return the element at a specific index. + + **Code:** + ```java + class MyCustomList { + private ArrayList list = new ArrayList<>(); + + public void addElement(T element) { + list.add(element); + } + + public T getElement(int index) { + return list.get(index); + } + + @Override + public String toString() { + return list.toString(); + } + } + + public class GenericsReturnPuzzle { + public static void main(String[] args) { + MyCustomList words = new MyCustomList<>(); + words.addElement("Java"); + words.addElement("Programming"); + + System.out.println("First word: " + words.getElement(0)); + } + } + ``` + **Output:** + ``` + First word: Java + ``` + +### **New Quiz Question** + +1. **How can a generic return type be defined in a method?** + - A) By adding `` before the return type **(Answer: A)** + - B) By using the `Object` class as the return type + - C) By returning an `ArrayList` + +### **Fun Fact** +- **Fun Fact:** Generics add type safety without impacting runtime performance, as they are implemented through "type erasure." + +--- + +#### **Group 3: Step 4 – Restrictions with Extends and Generic Methods** + +- **Step 04**: Generics Puzzles - Restrictions with extends and Generic Methods + +**Why Grouped:** This step explores restrictions in generics using `extends`, limiting types to subclasses of a specific class, which helps enforce consistency and prevent runtime errors. + +#### **Puzzle** + +1. **Puzzle: Restricting Types in a Generic List** + - **Problem:** Create a `NumericList` that accepts only numbers (Integer, Double, etc.) and can return the average of all numbers. + + **Code:** + ```java + import java.util.ArrayList; + + class NumericList { + private ArrayList list = new ArrayList<>(); + + public void addNumber(T number) { + list.add(number); + } + + public double getAverage() { + double sum = 0.0; + for (T number : list) { + sum += number.doubleValue(); + } + return sum / list.size(); + } + } + + public class GenericsRestriction { + public static void main(String[] args) { + NumericList numbers = new NumericList<>(); + numbers.addNumber(10); + numbers.addNumber(20); + numbers.addNumber(30); + + System.out.println("Average: " + numbers.getAverage()); + } + } + ``` + **Output:** + ``` + Average: 20.0 + ``` + +### **New Quiz Question** + +1. **Which of the following restricts a generic type to subtypes of `Number`?** + - A) `` + - B) `` **(Answer: B)** + - C) `` + +### **Fun Fact** +- **Fun Fact:** `extends` in generics can apply to both classes and interfaces, allowing flexible restrictions. + +--- + +#### **Group 4: Step 5 – WildCards with Upper and Lower Bound** + +- **Step 05**: Generics and WildCards - Upper Bound and Lower Bound + +**Why Grouped:** This step introduces wildcards with `extends` (upper bound) and `super` (lower bound), showcasing flexible boundaries in method arguments. + +--- + +#### **Puzzle** + +1. **Puzzle: Summing Numbers with Upper Bounded Wildcard** + - **Problem:** Create a method that sums any list of numbers using an upper bounded wildcard (`? extends Number`). + + **Code:** + ```java + import java.util.List; + + public class SumNumbers { + public static double sumOfNumbers(List numbers) { + double sum = 0.0; + for (Number number : numbers) { + sum += number.doubleValue(); + } + return sum; + } + + public static void main(String[] args) { + List intList = List.of(1, 2, 3, 4); + List doubleList = List.of(1.5, 2.5, 3.5); + + System.out.println("Sum of integers: " + sumOfNumbers(intList)); + System.out.println("Sum of doubles: " + sumOfNumbers(doubleList)); + } + } + ``` + **Output:** + ``` + Sum of integers: 10.0 + Sum of doubles: 7.5 + ``` + +### **New Quiz Question** + +1. **Which wildcard allows accepting a list of any subtype of `Number`?** + - A) `` + - B) `` **(Answer: B)** + - C) `` + +### **Fun Fact** +- **Fun Fact:** Wildcards make generics more flexible, allowing methods to work with various subclasses or superclasses without modifying the class itself. + +--- + +### Additional Coidng Exercises + +### **Exercise 1: Custom Stack with Generics** + +**Description:** Create a custom `Stack` class using generics. This class should allow pushing elements to the top, popping elements from the top, and viewing the top element. + +**Code:** +```java +import java.util.ArrayList; + +class CustomStack { + private ArrayList stack = new ArrayList<>(); + + public void push(T element) { + stack.add(element); + } + + public T pop() { + if (!stack.isEmpty()) { + return stack.remove(stack.size() - 1); + } + return null; // Or throw an exception + } + + public T peek() { + if (!stack.isEmpty()) { + return stack.get(stack.size() - 1); + } + return null; + } + + @Override + public String toString() { + return stack.toString(); + } +} + +public class StackGenericsTest { + public static void main(String[] args) { + CustomStack stringStack = new CustomStack<>(); + stringStack.push("Java"); + stringStack.push("Generics"); + System.out.println("Stack after pushes: " + stringStack); + + System.out.println("Peek: " + stringStack.peek()); + System.out.println("Pop: " + stringStack.pop()); + System.out.println("Stack after pop: " + stringStack); + } +} +``` + +**Output:** +``` +Stack after pushes: [Java, Generics] +Peek: Generics +Pop: Generics +Stack after pop: [Java] +``` + +--- + +### **Exercise 2: Pair Finder with Upper Bounds** + +**Description:** Create a generic method to find and display all pairs from a list of numbers (e.g., `Integer`, `Double`) that sum up to a given target value. + +**Code:** +```java +import java.util.ArrayList; +import java.util.List; + +public class PairFinder { + public static void findPairs(List list, double targetSum) { + for (int i = 0; i < list.size(); i++) { + for (int j = i + 1; j < list.size(); j++) { + if (list.get(i).doubleValue() + list.get(j).doubleValue() == targetSum) { + System.out.println("Pair found: " + list.get(i) + ", " + list.get(j)); + } + } + } + } + + public static void main(String[] args) { + List intList = List.of(2, 4, 6, 8, 10); + System.out.println("Finding pairs that sum to 10:"); + findPairs(intList, 10); + + List doubleList = List.of(1.5, 3.5, 5.0, 6.5); + System.out.println("Finding pairs that sum to 7.0:"); + findPairs(doubleList, 7.0); + } +} +``` + +**Output:** +``` +Finding pairs that sum to 10: +Pair found: 2, 8 +Pair found: 4, 6 +Finding pairs that sum to 7.0: +Pair found: 1.5, 5.5 +``` + +--- + +### **Exercise 3: “Flashcard Quiz” Game using Generics** + +**Description:** Create a flashcard quiz game where each flashcard has a question (String) and an answer (generic). This will allow different types of answers, such as `Integer`, `Double`, or `String`. + +**Code:** +```java +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; + +class Flashcard { + private String question; + private T answer; + + public Flashcard(String question, T answer) { + this.question = question; + this.answer = answer; + } + + public String getQuestion() { + return question; + } + + public T getAnswer() { + return answer; + } +} + +public class FlashcardQuiz { + public static void main(String[] args) { + Map, String> flashcards = new HashMap<>(); + flashcards.put(new Flashcard<>("What is 5 + 5?", 10), "Integer"); + flashcards.put(new Flashcard<>("Name of this programming language?", "Java"), "String"); + flashcards.put(new Flashcard<>("Square root of 49?", 7.0), "Double"); + + Scanner scanner = new Scanner(System.in); + int score = 0; + + for (Map.Entry, String> entry : flashcards.entrySet()) { + Flashcard card = entry.getKey(); + System.out.println(card.getQuestion()); + System.out.print("Answer: "); + String userAnswer = scanner.nextLine(); + + if (String.valueOf(card.getAnswer()).equalsIgnoreCase(userAnswer)) { + System.out.println("Correct!"); + score++; + } else { + System.out.println("Incorrect. Correct answer: " + card.getAnswer()); + } + } + + System.out.println("Quiz over! Your score: " + score + "/" + flashcards.size()); + } +} +``` + +**Output:** +``` +What is 5 + 5? +Answer: 10 +Correct! +Name of this programming language? +Answer: Java +Correct! +Quiz over! Your score: 2/2 +``` + +--- + +### **Exercise 4: Generic Max Finder Game with Bounds** + +**Description:** Create a game that finds the maximum number from a list. The list should support `Integer`, `Double`, or `Float` types using upper bounds. + +**Code:** +```java +import java.util.List; + +public class MaxFinderGame { + public static > T findMax(List list) { + if (list.isEmpty()) { + return null; + } + + T max = list.get(0); + for (T element : list) { + if (element.compareTo(max) > 0) { + max = element; + } + } + return max; + } + + public static void main(String[] args) { + List intList = List.of(10, 30, 20, 50); + System.out.println("Max in Integer list: " + findMax(intList)); + + List doubleList = List.of(1.5, 3.5, 2.5, 6.5); + System.out.println("Max in Double list: " + findMax(doubleList)); + } +} +``` + +**Output:** +``` +Max in Integer list: 50 +Max in Double list: 6.5 +``` + +--- + +## Section 25: Introduction to Functional Programming in Java + +#### **Group 1: Steps 1–3 - Introduction and Basic Functions as Parameters** + +- **Step 01**: Introduction to Functional Programming - Functions are First-Class Citizens +- **Step 02**: Functional Programming - First Example with Function as Parameter +- **Step 03**: Functional Programming - Exercise - Loop a List of Numbers + +**Why Grouped:** This group covers fundamental concepts, introducing functions as first-class citizens and demonstrating how functions can be passed as parameters in Java. + +#### **Puzzles** + +1. **Puzzle:** Create a function that accepts a list of integers and returns a list with each element incremented by 2. + - **Solution Code:** + ```java + import java.util.List; + import java.util.stream.Collectors; + + public class IncrementByTwo { + public static List increment(List numbers) { + return numbers.stream().map(n -> n + 2).collect(Collectors.toList()); + } + + public static void main(String[] args) { + List numbers = List.of(1, 2, 3); + System.out.println(increment(numbers)); // Output: [3, 4, 5] + } + } + ``` + - **Output:** `[3, 4, 5]` + +2. **Puzzle:** Create a function that takes a list and applies a lambda to double each number. + - **Solution Code:** + ```java + import java.util.List; + import java.util.stream.Collectors; + + public class DoubleNumbers { + public static List doubleElements(List numbers) { + return numbers.stream().map(n -> n * 2).collect(Collectors.toList()); + } + + public static void main(String[] args) { + List numbers = List.of(4, 5, 6); + System.out.println(doubleElements(numbers)); // Output: [8, 10, 12] + } + } + ``` + - **Output:** `[8, 10, 12]` + +### **Existing Quiz Questions** + +1. What is a functional interface in Java? + + - A) An interface that contains only one abstract method. + - B) An interface that can be implemented using a lambda expression. + - C) An interface that can be used to represent a function. + - D) All of the above. (Answer: D) + +2. How is a lambda expression different from a regular method? + + - A) Lambda expressions are anonymous, while regular methods have names. + - B) Lambda expressions are concise, while regular methods can be multiple lines of code. + - C) Lambda expressions are type-inferred, while regular methods must explicitly specify their types. + - D) All of the above. (Answer: D) + +### **New Quiz Questions** + +1. **What does it mean for functions to be "first-class citizens" in functional programming?** + - A) Functions can be passed as arguments, returned as values, and assigned to variables **(Answer: A)** + - B) Functions can only be called in classes + - C) Functions cannot return values + +2. **How would you loop through a list of numbers in functional programming?** + - A) Using a traditional `for` loop + - B) Using `forEach` with a lambda expression **(Answer: B)** + - C) Using only recursive functions + +### **Fun Fact** +Java introduced lambda expressions and functional programming concepts in Java 8 to make code more readable and concise. + +--- + +#### **Group 2: Steps 4–6 - Filtering and Summing Lists** + +- **Step 04**: Functional Programming - Filtering - Exercises to print odd and even numbers +- **Step 05**: Functional Programming - Collect - Sum of Numbers in a List +- **Step 06**: Functional Programming vs Structural Programming - A Quick Comparison + +**Why Grouped:** These steps cover filtering operations, collecting data into lists, and comparing functional programming with traditional structural programming. + +#### **Puzzles** + +1. **Puzzle:** Write a function to filter out even numbers and return only odd numbers from a list. + - **Solution Code:** + ```java + import java.util.List; + import java.util.stream.Collectors; + + public class OddNumbersOnly { + public static List filterOdds(List numbers) { + return numbers.stream().filter(n -> n % 2 != 0).collect(Collectors.toList()); + } + + public static void main(String[] args) { + List numbers = List.of(1, 2, 3, 4, 5); + System.out.println(filterOdds(numbers)); // Output: [1, 3, 5] + } + } + ``` + - **Output:** `[1, 3, 5]` + +2. **Puzzle:** Implement a function that sums all the even numbers in a list. + - **Solution Code:** + ```java + import java.util.List; + + public class SumEvenNumbers { + public static int sumEven(List numbers) { + return numbers.stream().filter(n -> n % 2 == 0).mapToInt(Integer::intValue).sum(); + } + + public static void main(String[] args) { + List numbers = List.of(1, 2, 3, 4, 5); + System.out.println(sumEven(numbers)); // Output: 6 + } + } + ``` + - **Output:** `6` + +### **Existing Quiz Questions** + +1. What is the purpose of the filter method? + + - A) To filter the elements of a stream based on a predicate. (Answer: A) + - B) To sort the elements of a stream. + - C) To map the elements of a stream to a new type. + - D) To reduce the elements of a stream to a single value. + +2. How would you filter the list of numbers to contain only even numbers? + +```java +List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); +``` + +- A) numbers.stream().filter(num -> num%2 == 0) (Answer: A) +- B) numbers.stream().filter(num -> num%2 ==1) +- C) numbers.stream().filter(num -> num%2 == 2) + +### **New Quiz Questions** + +1. **What is the purpose of the `filter` method in streams?** + - A) To filter out elements based on a condition **(Answer: A)** + - B) To loop through a list + - C) To sort elements + +2. **How would you sum elements in a list using streams?** + - A) `list.stream().reduce(Integer::sum)` + - B) `list.stream().mapToInt(Integer::intValue).sum()` **(Answer: B)** + - C) `list.stream().average()` + +### **Fun Fact** +Functional programming encourages immutability and avoids side effects, making programs easier to reason about and debug. + +--- + +#### **Group 3: Steps 7–10 - Intermediate Stream Operations and Lambda Expressions** + +- **Step 07**: Functional Programming Terminology - Lambda Expression, Stream and Operators +- **Step 08**: Stream Intermediate Operations - Sort, Distinct, Filter and Map +- **Step 09**: Stream Intermediate Operations - Exercises - Squares of First 10, Map +- **Step 10**: Stream Terminal Operations - `max` operation with Comparator + +**Why Grouped:** These steps introduce various stream operations, including sorting, distinct elements, filtering, and working with lambda expressions for more complex stream manipulations. + +#### **Puzzles** + +1. **Puzzle:** Implement a function to return distinct squares of numbers from a list. + - **Solution Code:** + ```java + import java.util.List; + import java.util.stream.Collectors; + + public class DistinctSquares { + public static List squareDistinct(List numbers) { + return numbers.stream().map(n -> n * n).distinct().collect(Collectors.toList()); + } + + public static void main(String[] args) { + List numbers = List.of(2, 3, 2, 4); + System.out.println(squareDistinct(numbers)); // Output: [4, 9, 16] + } + } + ``` + - **Output:** `[4, 9, 16]` + +2. **Puzzle:** Write a function to find the maximum element in a list using streams. + - **Solution Code:** + ```java + import java.util.List; + import java.util.Comparator; + + public class MaxElement { + public static int findMax(List numbers) { + return numbers.stream().max(Comparator.naturalOrder()).orElseThrow(); + } + + public static void main(String[] args) { + List numbers = List.of(3, 7, 2, 9, 5); + System.out.println(findMax(numbers)); // Output: 9 + } + } + ``` + - **Output:** `9` + +### **Existing Quiz Questions** + +1. What is the purpose of the distinct method in stream operations? + + - A) To remove duplicate elements from a stream. (Answer: A) + - B) To sort the elements of a stream. + - C) To map the elements of a stream to a new type. + - D) To reduce the elements of a stream to a single value. + +2. What is the purpose of the map() operation in stream operations? + + - A) To apply a function to each element in a stream and produce a new stream with the results. (Answer: A) + - B) To filter the elements of a stream based on a predicate. + - C) To sort the elements of a stream. + - D) To reduce the elements of a stream to a single value. + +3. What are intermediate operations and terminal operations in streams? + + - A) Intermediate operations return a new stream, while terminal operations produce a result or side-effect. + - B) Intermediate operations can be chained together, while terminal operations cannot be chained together. + - C) Both are true (Answer: C) + +### **New Quiz Questions** + +1. **What does the `map` method do in a stream?** + - A) Loops over elements + - B) Transforms each element **(Answer: B)** + - C) Filters elements + +2. **Which stream operation is terminal?** + - A) map + - B) filter + - C) collect **(Answer: C)** + +#### **Fun Fact** +Streams provide a high-level abstraction for processing collections, allowing developers to work with data in a more functional style. + +--- + +#### **Group 4: Steps 11–18 - Optional Class, Functional Interfaces, and Method References** + +- **Step 11**: Stream Terminal Operations - `min`, collect to List +- **Step 12**: Optional class in Java - An Introduction +- **Step 13**: Functional Interfaces - Implement Predicate Interface +- **Step 14**: Functional Interfaces - Implement Consumer Interface +- **Step 15**: Functional Interfaces - Implement Function Interface +- **Step 16**: Simplify Functional Programming with Method References +- **Step 17**: Functions are First-Class Citizens +- **Step 18**: Introduction to Functional Programming - Conclusion + +**Why Grouped:** This group dives deeper into advanced functional programming concepts, such as functional interfaces, optional values, and method references, providing a well-rounded conclusion to the section. + +#### **Puzzles** + +1. **Puzzle:** Implement a function that returns the minimum of a list using streams. + - **Solution Code:** + ```java + import java.util.List; + import java.util.Comparator; + + public class MinElement { + public static int findMin(List numbers) { + return numbers.stream().min(Comparator.naturalOrder()).orElseThrow(); + } + + public static void main(String[] args) { + List numbers = List.of(5, 3, 9, 2); + System.out.println(findMin(numbers)); // Output: 2 + } + } + + + ``` + - **Output:** `2` + +2. **Puzzle:** Create a function that uses the `Predicate` functional interface to filter words with length greater than 4. + - **Solution Code:** + ```java + import java.util.List; + import java.util.function.Predicate; + import java.util.stream.Collectors; + + public class FilterWords { + public static List filterByLength(List words, Predicate condition) { + return words.stream().filter(condition).collect(Collectors.toList()); + } + + public static void main(String[] args) { + List words = List.of("Java", "Stream", "API", "Functional", "Programming"); + System.out.println(filterByLength(words, word -> word.length() > 4)); // Output: [Stream, Functional, Programming] + } + } + ``` + - **Output:** `[Stream, Functional, Programming]` + +### **Existing Quiz Questions** + +1. What does the Optional < T > class represent in stream operations? + +- A) A container object that may or may not contain a value. +- B) A way to represent null values in stream operations. +- C) A way to avoid NullPointerExceptions in stream operations. +- D) All of the above. (Answer: D) + +2. What is the purpose of the reduce method in functional programming? + +- A) To filter the elements of a stream based on a predicate. +- B) To sort the elements of a stream. +- C) To map the elements of a stream to a new type. +- D) To reduce the elements of a stream to a single value. (Answer: D) + +3. What is the output of the following code? + +```java +List list = List.of(1, 4, 7, 9); +list.stream().filter(num -> num%2 == 1).forEach(elem -> System.out.println(elem)); +``` + +- A) 1, 7,9 (Annswer: A) +- B) 4 +- C) 1, 4, 7, 9 + +4. What is the output of the following code? + +```java +List numbers = List.of(4, 6, 8, 13, 3, 15); +int sum = numbers.stream() + .reduce(0, (num1, num2) -> num1 + num2); +System.out.println(sum); +``` + +- A) 49 (Answer: A) +- B) 31 +- C) 34 + +### **New Quiz Questions** + +1. **What does `Optional` represent in Java?** + - A) A mandatory value + - B) A container for nullable values **(Answer: B)** + - C) A required integer + +2. **What does `Predicate` interface represent?** + - A) A function that returns a boolean **(Answer: A)** + - B) A void method + - C) A mathematical formula + +--- + +### Additional Coding Exercises + +### Exercise 1: **Inventory Management System** + +**Description**: In this exercise, you will create a small inventory management system that uses functional programming to manage a list of products. Implement filtering, mapping, and reducing operations to manage inventory and calculate the total value of in-stock items. + +1. **Instructions**: + - Define a `Product` class with properties `String name`, `double price`, and `boolean inStock`. + - Create a list of `Product` instances, with varying prices and stock status. + - Use functional programming to: + - Filter products that are in stock. + - Calculate and display the total value of the inventory for in-stock items. + - Map and print product names in uppercase. + +2. **Code**: + ```java + import java.util.*; + import java.util.stream.*; + + class Product { + String name; + double price; + boolean inStock; + + public Product(String name, double price, boolean inStock) { + this.name = name; + this.price = price; + this.inStock = inStock; + } + + public String getName() { + return name; + } + + public double getPrice() { + return price; + } + + public boolean isInStock() { + return inStock; + } + } + + public class InventoryManager { + public static void main(String[] args) { + List products = List.of( + new Product("Laptop", 1200.50, true), + new Product("Mouse", 25.75, false), + new Product("Keyboard", 75.25, true), + new Product("Monitor", 300.00, true) + ); + + // Filter in-stock products and calculate total value + double totalValue = products.stream() + .filter(Product::isInStock) + .mapToDouble(Product::getPrice) + .sum(); + + System.out.println("Total value of in-stock items: $" + totalValue); + + // Map product names to uppercase + System.out.println("Product names in uppercase:"); + products.stream() + .map(product -> product.getName().toUpperCase()) + .forEach(System.out::println); + } + } + ``` +3. **Output**: + ``` + Total value of in-stock items: $1575.75 + Product names in uppercase: + LAPTOP + MOUSE + KEYBOARD + MONITOR + ``` + +--- + +### Exercise 2: **Student Grades Analyzer** + +**Description**: Create a program that analyzes a list of students’ grades. Using functional programming, find students with grades above a certain threshold, calculate the average grade, and display the highest grade in the class. + +1. **Instructions**: + - Define a `Student` class with properties `String name` and `double grade`. + - Generate a list of students with random grades. + - Use streams to: + - Filter and print students with grades above 70. + - Calculate the class average. + - Find the student with the highest grade. + +2. **Code**: + ```java + import java.util.*; + import java.util.stream.*; + + class Student { + String name; + double grade; + + public Student(String name, double grade) { + this.name = name; + this.grade = grade; + } + + public String getName() { + return name; + } + + public double getGrade() { + return grade; + } + } + + public class StudentAnalyzer { + public static void main(String[] args) { + List students = List.of( + new Student("Alice", 85.5), + new Student("Bob", 62.0), + new Student("Charlie", 91.5), + new Student("Diana", 76.5) + ); + + System.out.println("Students with grades above 70:"); + students.stream() + .filter(s -> s.getGrade() > 70) + .forEach(s -> System.out.println(s.getName())); + + double averageGrade = students.stream() + .mapToDouble(Student::getGrade) + .average() + .orElse(0.0); + System.out.println("Class average: " + averageGrade); + + Student topStudent = students.stream() + .max(Comparator.comparingDouble(Student::getGrade)) + .orElse(null); + if (topStudent != null) { + System.out.println("Top student: " + topStudent.getName() + " with grade " + topStudent.getGrade()); + } + } + } + ``` +3. **Output**: + ``` + Students with grades above 70: + Alice + Charlie + Diana + Class average: 78.875 + Top student: Charlie with grade 91.5 + ``` + +--- + +### Exercise 3: **“Guess the Number” Game with Hints** + +**Description**: Create a functional programming-based guessing game where the computer randomly picks a number between 1 and 100, and the player must guess it. The program should give hints like "too high" or "too low." + +1. **Instructions**: + - Generate a random number. + - Allow the player to input guesses and provide hints until they guess correctly. + - Count attempts and print the final score. + +2. **Code**: + ```java + import java.util.*; + import java.util.stream.*; + + public class GuessTheNumberGame { + public static void main(String[] args) { + int numberToGuess = new Random().nextInt(100) + 1; + Scanner scanner = new Scanner(System.in); + System.out.println("Welcome to the 'Guess the Number' Game!"); + System.out.println("I'm thinking of a number between 1 and 100. Try to guess it!"); + + Stream.generate(() -> scanner.nextInt()) + .map(guess -> { + if (guess < numberToGuess) return "Too low!"; + else if (guess > numberToGuess) return "Too high!"; + else return "Correct!"; + }) + .peek(System.out::println) + .anyMatch(response -> response.equals("Correct!")); + + System.out.println("You guessed the correct number! Congratulations!"); + } + } + ``` +3. **Output**: + ``` + Welcome to the 'Guess the Number' Game! + I'm thinking of a number between 1 and 100. Try to guess it! + (Player input: 50) + Too low! + (Player input: 75) + Too high! + ... + Correct! + ``` + +--- + +### Exercise 4: **Word Frequency Counter** + +**Description**: Implement a program that calculates the frequency of each word in a given sentence. This exercise will use functional programming to process a sentence into words, map word counts, and print the results. + +1. **Instructions**: + - Take a sentence input from the user. + - Split the sentence into words. + - Count occurrences of each word using streams. + +2. **Code**: + ```java + import java.util.*; + import java.util.stream.*; + + public class WordFrequencyCounter { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + System.out.println("Enter a sentence:"); + String sentence = scanner.nextLine().toLowerCase(); + + Map wordFrequency = Arrays.stream(sentence.split(" ")) + .collect(Collectors.groupingBy(word -> word, Collectors.counting())); + + System.out.println("Word Frequency:"); + wordFrequency.forEach((word, count) -> System.out.println(word + ": " + count)); + } + } + ``` +3. **Output**: + ``` + Enter a sentence: + (User input: "Java is fun and Java is powerful") + Word Frequency: + java: 2 + is: 2 + fun: 1 + and: 1 + powerful: 1 + ``` + +--- + +### **Exercise 5: Vocabulary Builder** + +**Description**: Create a vocabulary builder program that takes a list of words and counts occurrences of each word length. This is useful for building vocabulary by focusing on different word lengths. + +1. **Instructions**: + - Accept a list of words. + - Count and display the frequency of each word length (e.g., 3-letter words, 4-letter words, etc.). + - Use streams to group by word length and count occurrences. + +2. **Code**: + ```java + import java.util.*; + import java.util.stream.*; + + public class VocabularyBuilder { + public static void main(String[] args) { + List words = List.of("apple", "orange", "cat", "elephant", "dog", "pear", "zebra", "owl"); + + Map lengthFrequency = words.stream() + .collect(Collectors.groupingBy(String::length, Collectors.counting())); + + System.out.println("Word Length Frequency:"); + lengthFrequency.forEach((length, count) -> System.out.println(length + "-letter words: " + count)); + } + } + ``` +3. **Output**: + ``` + Word Length Frequency: + 5-letter words: 2 + 6-letter words: 1 + 3-letter words: 3 + 7-letter words: 1 + 8-letter words: 1 + ``` + +--- + +### **Exercise 6: Movie Rating Aggregator** + +**Description**: Implement a movie rating aggregator that takes a list of movies with ratings and calculates the average rating for each genre. This will help reinforce the use of streams to group and aggregate data. + +1. **Instructions**: + - Define a `Movie` class with `String title`, `String genre`, and `double rating`. + - Create a list of `Movie` instances. + - Use functional programming to: + - Group movies by genre. + - Calculate and display the average rating for each genre. + +2. **Code**: + ```java + import java.util.*; + import java.util.stream.*; + + class Movie { + String title; + String genre; + double rating; + + public Movie(String title, String genre, double rating) { + this.title = title; + this.genre = genre; + this.rating = rating; + } + + public String getGenre() { + return genre; + } + + public double getRating() { + return rating; + } + } + + public class MovieRatingAggregator { + public static void main(String[] args) { + List movies = List.of( + new Movie("Inception", "Sci-Fi", 9.0), + new Movie("Interstellar", "Sci-Fi", 8.5), + new Movie("The Matrix", "Sci-Fi", 8.7), + new Movie("The Godfather", "Crime", 9.2), + new Movie("Goodfellas", "Crime", 8.7), + new Movie("Pulp Fiction", "Drama", 8.9) + ); + + Map averageRatings = movies.stream() + .collect(Collectors.groupingBy(Movie::getGenre, Collectors.averagingDouble(Movie::getRating))); + + System.out.println("Average Ratings by Genre:"); + averageRatings.forEach((genre, avgRating) -> System.out.println(genre + ": " + avgRating)); + } + } + ``` +3. **Output**: + ``` + Average Ratings by Genre: + Sci-Fi: 8.733333333333333 + Crime: 8.95 + Drama: 8.9 + ``` + +--- + +### **Exercise 7: Language Translation Quiz Game** + +**Description**: Create a language translation quiz game where users must translate words from English to another language. This exercise uses functional programming to shuffle words and verify answers. + +1. **Instructions**: + - Create a `Map` of English words and their corresponding translations. + - Randomly select words for the quiz. + - Check if the player’s translation matches the correct answer. + +2. **Code**: + ```java + import java.util.*; + import java.util.stream.*; + + public class LanguageTranslationQuiz { + public static void main(String[] args) { + Map translations = Map.of( + "hello", "hola", + "world", "mundo", + "apple", "manzana", + "car", "coche", + "book", "libro" + ); + + List words = new ArrayList<>(translations.keySet()); + Collections.shuffle(words); + Scanner scanner = new Scanner(System.in); + int score = 0; + + System.out.println("Translate the following words into Spanish:"); + + for (String word : words.stream().limit(3).collect(Collectors.toList())) { + System.out.print("Translate '" + word + "': "); + String answer = scanner.nextLine(); + if (translations.get(word).equalsIgnoreCase(answer)) { + System.out.println("Correct!"); + score++; + } else { + System.out.println("Incorrect! The correct answer is: " + translations.get(word)); + } + } + + System.out.println("Your score: " + score + "/" + 3); + } + } + ``` +3. **Output**: + ``` + Translate the following words into Spanish: + Translate 'hello': hola + Correct! + Translate 'car': coche + Correct! + Translate 'apple': fruta + Incorrect! The correct answer is: manzana + Your score: 2/3 + ``` + +--- + +## Section 27: Introduction to Threads And Concurrency in Java + +#### **Group 1: Steps 01-03 - Introduction and Basic Thread Creation** + + - **Why Grouped**: These steps introduce the need for threads, creating a thread by extending the `Thread` class, and implementing `Runnable`. + +#### **Puzzles** + +**Puzzle 1**: Create a `Task` class that extends `Thread` and prints numbers from 1 to 50. + + **Code**: + ```java + class Task extends Thread { + @Override + public void run() { + for (int i = 1; i <= 50; i++) { + System.out.println("Task printing: " + i); + } + } + } + + public class TaskExample { + public static void main(String[] args) { + Task task = new Task(); + task.start(); + } + } + ``` + **Output**: + ``` + Task printing: 1 + Task printing: 2 + ... + Task printing: 50 + ``` + +**Puzzle 2**: Implement a `Runnable` that counts down from 100 to 1 with a delay. + + **Code**: + ```java + class Countdown implements Runnable { + @Override + public void run() { + for (int i = 100; i >= 1; i--) { + System.out.println("Countdown: " + i); + try { + Thread.sleep(100); // Pauses for 0.1 seconds + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + public class CountdownExample { + public static void main(String[] args) { + Thread countdownThread = new Thread(new Countdown()); + countdownThread.start(); + } + } + ``` + **Output**: + ``` + Countdown: 100 + Countdown: 99 + ... + Countdown: 1 + ``` + +### **Existing Quiz Questions** + +1. **What is the purpose of implementing the `Runnable` interface in Java?** + +- A) To create a class that can be executed by a thread. (Answer: A) +- B) To create a class that can throw checked exceptions. +- C) To create a class that can be used in a try-catch block. + +2. **What is a drawback of using the `Thread` class or `Runnable` interface for managing threads?** + +- A) No fine-grained control over thread execution. +- B) Difficult to maintain when managing multiple threads. +- C) No way to get the result from a sub-task. +- D) All of the above. (Answer: D) + +### **New Quiz Questions** + +1. **What are the two main ways to create a thread in Java?** + - A) Using `Thread` and `Runnable` **(Answer)** + - B) Using `Callable` and `Runnable` + - C) Using `Runnable` and `Executor` + +2. **What is the purpose of the `start()` method in a thread?** + - A) To begin executing the thread **(Answer)** + - B) To initialize thread variables + - C) To set thread priority + +### **Fun Fact** + +- **Did you know?** Threads allow Java applications to handle multiple tasks simultaneously, introduced as early as Java’s initial release in 1995. + +--- + +#### **Group 2: Steps 04-06 - Thread States, Priorities, and Communication with join()** + + - **Why Grouped**: These steps discuss thread states, setting thread priorities, and using the `join()` method for communication. + +#### **Puzzles** + +**Puzzle 1**: Run two threads (`Task1` and `Task2`) in sequence using `join()`. + + **Code**: + ```java + class Task1 extends Thread { + public void run() { + System.out.println("Task1 started."); + try { Thread.sleep(500); } catch (InterruptedException e) {} + System.out.println("Task1 completed."); + } + } + + class Task2 extends Thread { + public void run() { + System.out.println("Task2 started."); + try { Thread.sleep(500); } catch (InterruptedException e) {} + System.out.println("Task2 completed."); + } + } + + public class SequentialThreads { + public static void main(String[] args) throws InterruptedException { + Task1 task1 = new Task1(); + Task2 task2 = new Task2(); + task1.start(); + task1.join(); // Ensure Task2 starts only after Task1 completes + task2.start(); + } + } + ``` + **Output**: + ``` + Task1 started. + Task1 completed. + Task2 started. + Task2 completed. + ``` + +**Puzzle 2**: Assign `MAX_PRIORITY` to `Task1` and `MIN_PRIORITY` to `Task2`. + + **Code**: + ```java + class TaskPriorityExample extends Thread { + private String name; + + public TaskPriorityExample(String name) { + this.name = name; + } + + public void run() { + System.out.println(name + " started with priority " + getPriority()); + try { Thread.sleep(100); } catch (InterruptedException e) {} + System.out.println(name + " completed."); + } + } + + public class PriorityExample { + public static void main(String[] args) { + TaskPriorityExample task1 = new TaskPriorityExample("Task1"); + TaskPriorityExample task2 = new TaskPriorityExample("Task2"); + task1.setPriority(Thread.MAX_PRIORITY); + task2.setPriority(Thread.MIN_PRIORITY); + task1.start(); + task2.start(); + } + } + ``` + **Output**: + ``` + Task1 started with priority 10 + Task1 completed. + Task2 started with priority 1 + Task2 completed. + ``` + +### **Existing Quiz Questions** + +1. **Which of the following states is a thread in when it is ready to be executed but not currently running?** + +- A) RUNNING +- B) RUNNABLE (Answer: B) +- C) BLOCKED/WAITING + +2. **What is the range of thread priorities in Java?** + +- A) 1 to 100 +- B) 1 to 1000 +- C) 1 to 10 (Answer: C) + +3. **What is the default priority assigned to a thread in Java?** + +- A) 1 +- B) 5 (Answer: B) +- C) 10 +- D) 0 + +4. **What is the purpose of the `join()` method in Java?** + +- A) It pauses the execution of a thread until it is explicitly resumed. +- B) It sets the priority of a thread to the highest level. +- C) It allows one thread to wait for the completion of another thread. (Answer: C) +- D) It terminates a thread and frees up system resources. + +### **New Quiz Questions** + +1. **What does `join()` do in a thread?** + - A) Pauses the thread until another completes **(Answer)** + - B) Combines two threads into one + - C) Duplicates the thread + +2. **What are the five thread states in Java?** + - A) New, Runnable, Running, Blocked, Terminated **(Answer)** + - B) Waiting, Active, Suspended, Terminated, Runnable + - C) Initialized, Running, Blocked, Suspended, Terminated + +### **Fun Fact** + +- **Did you know?** Thread priority is only a “hint” to the Java scheduler and doesn’t guarantee priority order. + +--- + +#### **Group 3: Steps 07-08 - Thread Control with sleep, yield, and synchronized** + + - **Why Grouped**: These steps introduce methods like `sleep` and `yield`, as well as synchronization to control thread execution. + +#### **Puzzles** + +**Puzzle 1**: Create two threads that increment a shared counter variable. Use `synchronized` to avoid data inconsistencies. + + **Code**: + ```java + class Counter { + private int count = 0; + + public synchronized void increment() { + count++; + } + + public int getCount() { + return count; + } + } + + class IncrementTask extends Thread { + private Counter counter; + + public IncrementTask(Counter counter) { + this.counter = counter; + } + + public void run() { + for (int i = 0; i < 100; i++) { + counter.increment(); + } + } + } + + public class SynchronizedCounterExample { + public static void main(String[] args) throws InterruptedException { + Counter counter = new Counter(); + IncrementTask task1 = new IncrementTask(counter); + IncrementTask task2 = new IncrementTask(counter); + task1.start(); + task2.start(); + task1.join(); + task2.join(); + System.out.println("Final counter value: " + counter.getCount()); + } + } + ``` + **Output**: + ``` + Final counter value: 200 + ``` + +**Puzzle 2**: Use `Thread.sleep(500)` to add a delay. + + **Code**: + ```java + class SleepTask extends Thread { + public void run() { + System.out.println("Processing..."); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("Processing continued..."); + } + } + + public class SleepExample { + public static void main(String[] args) { + SleepTask task = new SleepTask(); + task.start(); + } + } + ``` + **Output**: + ``` + Processing... + [Pauses for 0.5 seconds] + Processing continued... + ``` + +### **New Quiz Questions** + +1. **What does the `synchronized` keyword do?** + - A) Ensures only one thread accesses a block of code at a time **(Answer)** + - B) Pauses the thread + - C) Sets thread priority + +2. **What is the purpose of `Thread.sleep()`?** + - A) To permanently stop the thread + - B) To pause the thread **(Answer)** + - C) To synchronize the thread + +### **Fun Fact** + +- **Did you know?** The `synchronized` keyword prevents race conditions by allowing only one thread to execute a synchronized method at a time. + +--- + +#### **Group 4: Steps 09-14 - Advanced Thread Control with ExecutorService** + + - **Why Grouped**: These steps cover the `ExecutorService`, including `invokeAll` and `invokeAny` methods. + +#### **Puzzles** + +**Puzzle 1**: Use `invokeAll` to execute multiple tasks and retrieve their results. + + **Code**: + ```java + import java.util.*; + import java.util.concurrent.*; + + class SimpleTask implements Callable { + private String name; + + public SimpleTask(String name) { + this.name = name; + } + + public String call() { + return name + " completed"; + } + } + + public class InvokeAllExample { + public static void main(String[] args) throws InterruptedException, ExecutionException { + ExecutorService executor = Executors.newFixedThreadPool(3); + List> tasks = List.of( + new + + SimpleTask("Task 1"), + new SimpleTask("Task 2"), + new SimpleTask("Task 3") + ); + + List> results = executor.invokeAll(tasks); + for (Future result : results) { + System.out.println(result.get()); + } + executor.shutdown(); + } + } + ``` + **Output**: + ``` + Task 1 completed + Task 2 completed + Task 3 completed + ``` + +**Puzzle 2**: Use `invokeAny` to execute multiple tasks and get the result of the fastest. + + **Code**: + ```java + import java.util.*; + import java.util.concurrent.*; + + public class InvokeAnyExample { + public static void main(String[] args) throws ExecutionException, InterruptedException { + ExecutorService executor = Executors.newFixedThreadPool(3); + List> tasks = List.of( + () -> { Thread.sleep(200); return "Task 1 completed"; }, + () -> { Thread.sleep(100); return "Task 2 completed"; }, + () -> { Thread.sleep(300); return "Task 3 completed"; } + ); + + String result = executor.invokeAny(tasks); + System.out.println("Fastest task result: " + result); + executor.shutdown(); + } + } + ``` + **Output**: + ``` + Fastest task result: Task 2 completed + ``` + +### **Existing Quiz Questions** + +1. **Which method is used to create an `ExecutorService` with just one thread?** + +- A) ExecutorService.newSingleThreadExecutor() (Answer: A) +- B) ExecutorService.newFixedThreadPool() +- C) ExecutorService.newCachedThreadPool() +- D) ExecutorService.newScheduledThreadPool() + +2. **Which method is used to create a thread pool with a specified number of threads?** + +- A) ExecutorService.newSingleThreadExecutor() +- B) ExecutorService.newFixedThreadPool() (Answer: B) +- C) ExecutorService.newCachedThreadPool() +- D) ExecutorService.newScheduledThreadPool() + +3. **What happens if more tasks are submitted to an `ExecutorService` than the number of threads in the pool?** + +- A) The additional tasks are queued and executed when a thread becomes available. (Answer: A) +- B) The additional tasks are discarded and not executed. +- C) The Executor Service automatically adds more threads to the thread pool to accommodate the tasks. + +4. **Which interface is used to create sub-tasks that return a result?** + +- A) Thread +- B) Runnable +- C) Callable < T > (Answer: C) +- D) ExecutorService + +5. **What method of `ExecutorService` can be used to wait for the result of the fastest completed task from a group of tasks?** + +- A) execute() +- B) submit() +- C) invokeAll() +- D) invokeAny() (Answer: D) + +### **New Quiz Questions** + +1. **What is the purpose of the `Future` object in `ExecutorService`?** + - A) Holds a promise of a result for an asynchronous task **(Answer)** + - B) Pauses a task + - C) Sets task priority + +2. **How does `invokeAny()` differ from `invokeAll()` in an `ExecutorService`?** + - A) `invokeAny()` returns the first completed task result, `invokeAll()` waits for all tasks to complete **(Answer)** + - B) Both wait for all tasks to complete + - C) Both return a list of results + +### **Fun Fact** + +- **Did you know?** Java’s `Future` class allows you to cancel tasks and check their completion status, adding a layer of control to concurrency handling. + +--- + +### Additional Coding Exercises + +### **Exercise 1: Task Scheduler Game** +**Description**: Create a simple game using threads to schedule and execute tasks in sequence and parallel. In this game, each task simulates a game level, and players must complete each level (task) to progress to the next level. + +**Code**: +```java +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +class GameLevel implements Runnable { + private final String levelName; + + public GameLevel(String levelName) { + this.levelName = levelName; + } + + @Override + public void run() { + System.out.println(levelName + " has started."); + try { + Thread.sleep(1000); // Simulate level execution time + } catch (InterruptedException e) { + System.out.println("Interrupted: " + levelName); + } + System.out.println(levelName + " has finished."); + } +} + +public class TaskSchedulerGame { + public static void main(String[] args) { + ExecutorService executor = Executors.newFixedThreadPool(3); + System.out.println("Game has started!"); + + // Add levels + executor.execute(new GameLevel("Level 1")); + executor.execute(new GameLevel("Level 2")); + executor.execute(new GameLevel("Level 3")); + + executor.shutdown(); + } +} +``` + +**Output**: +``` +Game has started! +Level 1 has started. +Level 1 has finished. +Level 2 has started. +Level 2 has finished. +Level 3 has started. +Level 3 has finished. +``` + +--- + +### **Exercise 2: Multi-Task File Downloader** +**Description**: Simulate downloading files using multiple threads. Each thread represents a file download task, and `ExecutorService` manages simultaneous downloads. + +**Code**: +```java +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +class FileDownload implements Runnable { + private final String fileName; + + public FileDownload(String fileName) { + this.fileName = fileName; + } + + @Override + public void run() { + System.out.println("Starting download of " + fileName); + try { + Thread.sleep(2000); // Simulating download time + } catch (InterruptedException e) { + System.out.println("Download interrupted for: " + fileName); + } + System.out.println("Completed download of " + fileName); + } +} + +public class FileDownloader { + public static void main(String[] args) { + ExecutorService executor = Executors.newFixedThreadPool(3); + + executor.execute(new FileDownload("File1.zip")); + executor.execute(new FileDownload("File2.zip")); + executor.execute(new FileDownload("File3.zip")); + executor.execute(new FileDownload("File4.zip")); + executor.execute(new FileDownload("File5.zip")); + + executor.shutdown(); + try { + executor.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} +``` + +**Output**: +``` +Starting download of File1.zip +Starting download of File2.zip +Starting download of File3.zip +Completed download of File1.zip +Starting download of File4.zip +Completed download of File2.zip +Starting download of File5.zip +... +``` + +--- + +### **Exercise 3: Quiz Timer Challenge** +**Description**: Develop a timer-based quiz game where each question has a time limit. If the user doesn’t answer within the time, the thread will automatically terminate and move to the next question. + +**Code**: +```java +import java.util.Scanner; +import java.util.concurrent.*; + +class QuizQuestion implements Callable { + private final String question; + + public QuizQuestion(String question) { + this.question = question; + } + + @Override + public String call() throws Exception { + System.out.println(question); + Scanner scanner = new Scanner(System.in); + return scanner.nextLine(); + } +} + +public class QuizTimerChallenge { + public static void main(String[] args) { + ExecutorService executor = Executors.newSingleThreadExecutor(); + String[] questions = {"What is the capital of France?", "2 + 2?", "What is Java?"}; + int score = 0; + + for (String question : questions) { + Future future = executor.submit(new QuizQuestion(question)); + + try { + String answer = future.get(5, TimeUnit.SECONDS); // 5-second timer for each question + System.out.println("Answer: " + answer); + score++; + } catch (TimeoutException e) { + System.out.println("Time's up!"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + executor.shutdown(); + System.out.println("Final score: " + score + "/" + questions.length); + } +} +``` + +**Output**: +``` +What is the capital of France? +[User input or "Time's up!" if exceeded] +2 + 2? +[User input or "Time's up!" if exceeded] +Final score: X/3 +``` + +--- + +### **Exercise 4: “Fastest Response” Task Game** +**Description**: Using `invokeAny`, create a game where multiple threads perform a simulated task, and the first to complete is the “winner.” This demonstrates competitive parallel execution. + +**Code**: +```java +import java.util.concurrent.*; + +class TaskChallenge implements Callable { + private final String taskName; + + public TaskChallenge(String taskName) { + this.taskName = taskName; + } + + @Override + public String call() throws InterruptedException { + int time = (int) (Math.random() * 3000); + Thread.sleep(time); + return taskName + " finished in " + time + " ms"; + } +} + +public class FastestTaskGame { + public static void main(String[] args) throws InterruptedException, ExecutionException { + ExecutorService executor = Executors.newFixedThreadPool(3); + + System.out.println("Starting the Fastest Task Game..."); + String result = executor.invokeAny( + List.of(new TaskChallenge("Task A"), new TaskChallenge("Task B"), new TaskChallenge("Task C")) + ); + + System.out.println("Fastest task: " + result); + executor.shutdown(); + } +} +``` + +**Output**: +``` +Starting the Fastest Task Game... +Fastest task: Task B finished in 912 ms +``` + +--- + +### **Exercise 5: Multiplayer Chat Simulation** + +**Description**: Create a multiplayer chat simulation where each player represents a `Runnable` task. Messages are sent at random intervals, and the program displays each message in real-time. + +1. **Instructions**: + - Define a `Player` class implementing `Runnable`, simulating random message sends. + - Use `ExecutorService` to handle multiple players (threads). + - Randomly delay messages to simulate real-time chat. + +2. **Code**: + ```java + import java.util.Random; + import java.util.concurrent.ExecutorService; + import java.util.concurrent.Executors; + import java.util.concurrent.TimeUnit; + + class Player implements Runnable { + private final String name; + + public Player(String name) { + this.name = name; + } + + @Override + public void run() { + String[] messages = { + "Hello!", "How’s it going?", "Anyone here?", + "I’m ready to play!", "Good game!", "Let’s win!" + }; + Random random = new Random(); + + for (int i = 0; i < 5; i++) { + try { + Thread.sleep(random.nextInt(2000)); // Random delay for message + System.out.println(name + ": " + messages[random.nextInt(messages.length)]); + } catch (InterruptedException e) { + System.out.println(name + " left the chat."); + } + } + } + } + + public class MultiplayerChatSimulation { + public static void main(String[] args) { + ExecutorService chatService = Executors.newFixedThreadPool(3); + + System.out.println("Chat simulation started..."); + + chatService.execute(new Player("Player1")); + chatService.execute(new Player("Player2")); + chatService.execute(new Player("Player3")); + + chatService.shutdown(); + try { + chatService.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + System.out.println("Chat simulation ended."); + } + } + ``` + +3. **Output**: + ``` + Chat simulation started... + Player1: Hello! + Player2: I’m ready to play! + Player3: How’s it going? + Player1: Good game! + ... + Chat simulation ended. + ``` + +--- + +### **Exercise 6: Airport Runway Simulation** + +**Description**: Simulate an airport runway with multiple planes requesting permission to take off. Only one plane can use the runway at a time, and planes must wait for their turn. + +1. **Instructions**: + - Define a `Plane` class implementing `Runnable`, representing a plane waiting to take off. + - Use a `synchronized` method to control runway access. + - Implement a `takeOff()` method where each plane attempts to use the runway sequentially. + +2. **Code**: + ```java + class Runway { + public synchronized void takeOff(String planeName) { + System.out.println(planeName + " is taking off..."); + try { + Thread.sleep(2000); // Simulate take-off time + } catch (InterruptedException e) { + System.out.println(planeName + " take-off interrupted."); + } + System.out.println(planeName + " has successfully taken off."); + } + } + + class Plane implements Runnable { + private final String planeName; + private final Runway runway; + + public Plane(String planeName, Runway runway) { + this.planeName = planeName; + this.runway = runway; + } + + @Override + public void run() { + System.out.println(planeName + " is ready to take off."); + runway.takeOff(planeName); + } + } + + public class AirportSimulation { + public static void main(String[] args) { + Runway runway = new Runway(); + Thread plane1 = new Thread(new Plane("Plane A", runway)); + Thread plane2 = new Thread(new Plane("Plane B", runway)); + Thread plane3 = new Thread(new Plane("Plane C", runway)); + + plane1.start(); + plane2.start(); + plane3.start(); + } + } + ``` + +3. **Output**: + ``` + Plane A is ready to take off. + Plane A is taking off... + Plane B is ready to take off. + Plane C is ready to take off. + Plane A has successfully taken off. + Plane B is taking off... + ... + ``` + +--- + +### **Exercise 7: Race Simulation with Threads** + +**Description**: Create a race simulation where multiple runners (threads) compete to finish first. Each runner moves forward in random increments, and the race ends when one runner reaches the finish line. + +1. **Instructions**: + - Define a `Runner` class implementing `Runnable`, with each runner advancing at a random speed. + - Use a `volatile` flag to signal when the race ends. + - Track each runner’s position, and declare a winner when the first runner crosses the finish line. + +2. **Code**: + ```java + import java.util.Random; + import java.util.concurrent.ExecutorService; + import java.util.concurrent.Executors; + import java.util.concurrent.TimeUnit; + + class Runner implements Runnable { + private static volatile boolean raceOver = false; + private final String name; + private static final int FINISH_LINE = 100; + + public Runner(String name) { + this.name = name; + } + + @Override + public void run() { + Random random = new Random(); + int position = 0; + + while (!raceOver && position < FINISH_LINE) { + position += random.nextInt(10) + 1; // Move forward by 1-10 units + System.out.println(name + " ran to position: " + position); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + if (!raceOver && position >= FINISH_LINE) { + raceOver = true; + System.out.println(name + " wins the race!"); + } + } + } + + public class RaceSimulation { + public static void main(String[] args) { + ExecutorService race = Executors.newFixedThreadPool(3); + System.out.println("Race has started!"); + + race.execute(new Runner("Runner 1")); + race.execute(new Runner("Runner 2")); + race.execute(new Runner("Runner 3")); + + race.shutdown(); + try { + race.awaitTermination(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + ``` + +3. **Output**: + ``` + Race has started! + Runner 1 ran to position: 5 + Runner 2 ran to position: 7 + Runner 3 ran to position: 3 + Runner 1 ran to position: 15 + ... + Runner 2 wins the race! + ``` + +--- + +## Section 28: Introduction to Exception Handling in Java + +#### **Group 1: Basics of Exception Handling and Thought Process (Steps 1-3)** + - **Why Grouped**: These steps introduce core concepts of exception handling, including understanding the stack trace, and basic error handling using `try` and `catch`. + +#### **Puzzles** + +**Puzzle 1**: **Simulating a NullPointerException** + - **Problem**: Create a program that intentionally causes a `NullPointerException` by accessing a method on a `null` object. Use a `try-catch` block to handle the exception. + - **Code**: + ```java + public class NullPointerExample { + public static void main(String[] args) { + try { + String str = null; + System.out.println(str.length()); + } catch (NullPointerException e) { + System.out.println("Caught a NullPointerException: " + e.getMessage()); + } + } + } + ``` + - **Output**: + ``` + Caught a NullPointerException: null + ``` + +**Puzzle 2**: **Exception Flow Up the Call Stack** + - **Problem**: Write methods `methodA`, `methodB`, and `methodC`, where `methodC` throws an exception, and `methodA` catches it. Observe the flow of the exception up the call stack. + - **Code**: + ```java + public class ExceptionFlow { + public static void main(String[] args) { + try { + methodA(); + } catch (Exception e) { + System.out.println("Exception caught in main: " + e.getMessage()); + } + } + + static void methodA() throws Exception { + methodB(); + } + + static void methodB() throws Exception { + methodC(); + } + + static void methodC() throws Exception { + throw new Exception("Exception from methodC"); + } + } + ``` + - **Output**: + ``` + Exception caught in main: Exception from methodC + ``` + +### **Existing Quiz Questions** + +1. **What is an exception in Java?** + +- A) A condition that indicates the successful completion of a program +- B) A statement that is used to handle errors in a program +- C) An event that occurs during the execution of a program and disrupts the normal flow of instructions (Answer: C) + +2. **Which of the following is an example of an exception?** + +- A) A program running out of memory. +- B) A division by zero error. +- C) Both A and B. ( Answer: C) + +3. **What happens if an exception is not handled in a program?** + +- A) The program continues running normally. +- B) The program terminates abruptly. (Answer: B) +- C) The program enters a loop until the exception is resolved. + +4. **How can you handle an exception in Java?** + +- A) By using the try-catch block. (Answer: A) +- B) By using the if-else statement. +- C) By using the throw keyword. + +5. **What is the purpose of the `catch` block in a try-catch block?** + +- A) To define the code that may throw an exception. +- B) To write code to handle the exception. (Answer: B) + +6. **What happens if an exception is caught in a catch block?** + +- A) The program continues running normally after the catch block. (Answer: A) +- B) The program terminates abruptly and an error message is displayed. +- C) The program enters a loop until the exception is resolved. + +### **New Quiz Questions** + +1. **What is the purpose of the `try` and `catch` blocks in Java?** + - A) To store multiple variables + - B) To handle exceptions and prevent program crashes **(Answer)** + - C) To declare variables as final + +2. **Which method is used to print a detailed stack trace of an exception in Java?** + - A) `e.printStackTrace()` **(Answer)** + - B) `System.out.println(e)` + - C) `e.toString()` + +### **Fun Fact** +- **Did you know?** Java’s exception handling system was inspired by Ada, a language used in real-time, high-stakes applications like aviation software, emphasizing safety and reliability. + +--- + +#### **Group 2: Exception Hierarchy, Matching, and Catching (Steps 4-6)** + - **Why Grouped**: This set explains the structure of exception types in Java, discusses the exception hierarchy, and covers the significance of `finally` blocks. + +#### **Puzzles** + +**Puzzle 1**: **Multiple Catch Blocks** + - **Problem**: Write a program using multiple `catch` blocks for `NullPointerException` and `ArrayIndexOutOfBoundsException`. Test by triggering each exception and observe the handling mechanism. + - **Code**: + ```java + public class MultipleCatchExample { + public static void main(String[] args) { + try { + String[] arr = null; + System.out.println(arr[1]); + } catch (NullPointerException e) { + System.out.println("Caught NullPointerException"); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println("Caught ArrayIndexOutOfBoundsException"); + } + } + } + ``` + - **Output**: + ``` + Caught NullPointerException + ``` + +**Puzzle 2**: **Using finally for Resource Cleanup** + - **Problem**: Demonstrate the use of `finally` to close a resource, regardless of whether an exception is thrown or not. + - **Code**: + ```java + import java.io.FileReader; + import java.io.IOException; + + public class FinallyExample { + public static void main(String[] args) { + FileReader reader = null; + try { + reader = new FileReader("test.txt"); + System.out.println("File opened successfully."); + } catch (IOException e) { + System.out.println("File not found."); + } finally { + try { + if (reader != null) reader.close(); + System.out.println("File closed."); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + ``` + - **Output**: + ``` + File not found. + File closed. + ``` + +### **Existing Quiz Questions** + +1. **What is the root class of the Java exception hierarchy?** + +- A) RuntimeException +- B) Exception +- C) Throwable (Answer: C) + +2. **Which of the following is true about the exception hierarchy in Java?** + +- A) All exceptions in Java are subclasses of Exception. +- B) NullPointerException is a subclass of RuntimeException. +- C) Both A and B. (Answer: C) + +3. **How can you ensure that a resource is always released, even if an exception occurs?** + +- A) By using the try-catch block. +- B) By using the finally block. (Answer: B) +- C) By using the throw keyword. + +4. **When is the code inside the `finally` block executed?** + +- A) Only when an exception occurs. +- B) Only when there is no exception. +- C) Whether an exception occurs or not. (Answer: C) + +### **New Quiz Questions** + +1. **What is the purpose of the `finally` block?** + - A) To execute code regardless of an exception occurrence **(Answer)** + - B) To handle checked exceptions only + - C) To ignore runtime exceptions + +2. **When should you use multiple catch blocks?** + - A) When catching different types of exceptions **(Answer)** + - B) When trying to avoid all exceptions + - C) To always catch unchecked exceptions + +### **Fun Fact** +- **Did you know?** The `finally` block always executes after the `try-catch` sequence, making it an ideal spot for resource cleanup tasks. + +--- + +#### **Group 3: Checked vs. Unchecked Exceptions (Steps 7-8)** + - **Why Grouped**: This group explores checked and unchecked exceptions, clarifying their differences and the specific handling requirements in Java. + +#### **Puzzles** + +**Puzzle 1**: **Checked Exception Simulation with Thread.sleep()** + - **Problem**: Use `Thread.sleep()` to trigger a checked `InterruptedException` and handle it properly. + - **Code**: + ```java + public class CheckedExceptionExample { + public static void main(String[] args) { + try { + riskyMethod(); + } catch (InterruptedException e) { + System.out.println("Caught InterruptedException: " + e.getMessage()); + } + } + + static void riskyMethod() throws InterruptedException { + Thread.sleep(1000); + } + } + ``` + - **Output**: + ``` + (After 1 second delay) + Caught InterruptedException: sleep interrupted + ``` + +**Puzzle 2**: **Unchecked Exception Simulation** + - **Problem**: Trigger a `RuntimeException` in the same program, and observe that it doesn’t need to be explicitly caught. + - **Code**: + ```java + public class UncheckedExceptionExample { + public static void main(String[] args) { + throw new RuntimeException("Unchecked exception example"); + } + } + ``` + - **Output**: + ``` + Exception in thread "main" java.lang.RuntimeException: Unchecked exception example + ``` + +### **Existing Quiz Questions** + +1. **Which category of exceptions are unchecked exceptions?** + +- A) RuntimeException and its sub-classes (Answer: A) +- B) All sub-classes of Exception excluding RuntimeException +- C) InterruptedException and its sub-classes + +2. **Which category of exceptions are checked exceptions?** + +- A) RuntimeException and its sub-classes +- B) All sub-classes of Exception excluding RuntimeException and subclasses of RuntimeException (Answer: B) +- C) InterruptedException and its sub-classes + +### **New Quiz Questions** + +1. **Which of these exceptions must be handled by the programmer?** + - A) `NullPointerException` + - B) `IOException` **(Answer)** + - C) `ArithmeticException` + +2. **What keyword is used to propagate a checked exception up the call chain?** + - A) `catch` + - B) `throws` **(Answer)** + - C) `return` + +### **Fun Fact** +- **Did you know?** In Java, checked exceptions must be either caught or declared in the method signature, whereas unchecked exceptions are optional to catch. + +--- + +#### **Group 4: Throwing Exceptions and Custom Exceptions (Steps 9-11)** + - **Why Grouped**: This group covers throwing standard exceptions, creating custom exceptions, and their usage. + +#### **Puzzles** + +**Puzzle 1**: **Throwing a Custom Exception** + - **Problem**: Create a custom `InvalidCurrencyException` and throw it when currencies don’t match in a currency conversion method. + - **Code**: + ```java + class InvalidCurrencyException extends Exception { + public InvalidCurrencyException(String message) { + super(message); + } + } + + public class CustomExceptionDemo { + public static void main(String[] args) { + try { + checkCurrency("USD", "EUR"); + } catch (InvalidCurrencyException e) { + System.out.println("Caught custom exception: " + e.getMessage()); + } + } + + static void checkCurrency(String currency1, String currency2) throws InvalidCurrencyException { + if (!currency1.equals(currency2)) { + throw new InvalidCurrencyException("Currencies do not match!"); + } + } + } + ``` + - **Output**: + ``` + Caught custom exception: Currencies do not match! + ``` + +### **Existing Quiz Questions** + +1. **What is the purpose of the `throws` keyword in Java?** + +- A) To handle an exception within a method using a try-catch block. +- B) To declare that a method may throw a specific type of exception. (Answer: B) +- C) To indicate that an exception has occurred in a method. + +2. **What is the benefit of throwing a custom exception in Java?** + +- A) It allows you to provide more specific information about the error that occurred. +- B) It allows you to create your own exception hierarchy. +- C) It allows you to catch and handle the exception in a more specific way. +- D) All of the above. (Answer: D) + +### **New Quiz Questions** + +1. **When should you throw a custom exception?** + - A) To indicate a specific error not covered by standard exceptions **(Answer)** + - B) To print error messages to the console + - C) To declare variables as constant + +### **Fun Fact** +- **Did you know?** Custom exceptions can make your code easier to understand and debug, as they communicate specific issues more clearly than generic exceptions. + +--- + +#### **Group 5: Best Practices in Exception Handling (Steps 12-14)** + - **Why Grouped**: This final group emphasizes best practices, including using try-with-resources and avoiding unnecessary exception handling. + +#### **Puzzles** + +**Puzzle 1**: **Try-with-Resources Example** + - **Problem**: Use a try-with-resources + + statement to automatically close a file reader resource. + - **Code**: + ```java + import java.io.BufferedReader; + import java.io.FileReader; + import java.io.IOException; + + public class TryWithResourcesExample { + public static void main(String[] args) { + try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) { + System.out.println("File content: " + reader.readLine()); + } catch (IOException e) { + System.out.println("Exception while reading file: " + e.getMessage()); + } + } + } + ``` + - **Output**: + ``` + Exception while reading file: example.txt (No such file or directory) + ``` + +### **Existing Quiz Questions** + +1. **Which interface must a resource implement to be compatible with try-with-resources?** + +- A) Closeable +- B) AutoCloseable (Answer: B) +- C) Resource +- D) Disposable + +2. **What is the purpose of the try-with-resources statement in Java?** + +- A) To handle exceptions in a try-catch-finally block. +- B) To automatically manage resources that implement the AutoCloseable interface. (Answer: B) +- C) To terminate the program abruptly. + +### **New Quiz Questions** + +1. **What is the purpose of try-with-resources?** + - A) Automatically closes resources **(Answer)** + - B) Reduces memory allocation + - C) Optimizes CPU usage + +2. **What will happen if an exception is not caught in Java?** + - A) The program terminates **(Answer)** + - B) The exception is ignored + - C) The JVM handles it automatically + +### **Fun Fact** +- **Did you know?** The `try-with-resources` statement, introduced in Java 7, simplifies resource management and reduces potential memory leaks by auto-closing resources. + +--- + +### Additional Coding Exercises + +### **Exercise 1: Bank Account Simulation with Custom Exception Handling** + +**Description**: Create a `BankAccount` class where users can withdraw funds. Implement a custom exception `InsufficientFundsException` to handle scenarios where a withdrawal amount exceeds the account balance. + +**Code**: + +```java +class InsufficientFundsException extends Exception { + public InsufficientFundsException(String message) { + super(message); + } +} + +class BankAccount { + private double balance; + + public BankAccount(double balance) { + this.balance = balance; + } + + public void withdraw(double amount) throws InsufficientFundsException { + if (amount > balance) { + throw new InsufficientFundsException("Insufficient funds. Balance: " + balance); + } + balance -= amount; + System.out.println("Withdrawal successful! Remaining Balance: " + balance); + } + + public double getBalance() { + return balance; + } +} + +public class Main { + public static void main(String[] args) { + BankAccount account = new BankAccount(500); + try { + account.withdraw(100); // Should succeed + account.withdraw(600); // Should throw InsufficientFundsException + } catch (InsufficientFundsException e) { + System.out.println("Exception: " + e.getMessage()); + } + } +} +``` + +**Explanation**: +- `InsufficientFundsException` is a custom exception that inherits from `Exception`. +- If the withdrawal amount exceeds the balance, `InsufficientFundsException` is thrown with a message. +- The `catch` block handles the custom exception and outputs the error message. + +**Output**: +```plaintext +Withdrawal successful! Remaining Balance: 400.0 +Exception: Insufficient funds. Balance: 400.0 +``` + +--- + +### **Exercise 2: Online Shopping Cart with Checked Exceptions** + +**Description**: Implement an online shopping cart system where each `Product` has a limited stock. Create a custom `OutOfStockException` to manage inventory. + +**Code**: + +```java +class OutOfStockException extends Exception { + public OutOfStockException(String message) { + super(message); + } +} + +class Product { + private String name; + private int stock; + + public Product(String name, int stock) { + this.name = name; + this.stock = stock; + } + + public void purchase(int quantity) throws OutOfStockException { + if (quantity > stock) { + throw new OutOfStockException("Insufficient stock for product: " + name); + } + stock -= quantity; + System.out.println("Purchased " + quantity + " of " + name + ". Stock left: " + stock); + } + + public int getStock() { + return stock; + } +} + +public class Main { + public static void main(String[] args) { + Product product = new Product("Laptop", 5); + try { + product.purchase(2); // Successful purchase + product.purchase(4); // Will throw OutOfStockException + } catch (OutOfStockException e) { + System.out.println("Exception: " + e.getMessage()); + } + } +} +``` + +**Explanation**: +- `OutOfStockException` is thrown if the quantity requested is greater than the stock. +- The `catch` block outputs the exception message. + +**Output**: +```plaintext +Purchased 2 of Laptop. Stock left: 3 +Exception: Insufficient stock for product: Laptop +``` + +--- + +### **Exercise 3: File Handling with `try-with-resources`** + +**Description**: Implement a file reading operation using `try-with-resources`. The program should handle exceptions gracefully and ensure the file is closed automatically. + +**Code**: + +```java +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +public class FileReadExample { + public static void main(String[] args) { + String filePath = "sample.txt"; + + try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { + String line; + while ((line = reader.readLine()) != null) { + System.out.println(line); + } + } catch (IOException e) { + System.out.println("Error reading file: " + e.getMessage()); + } + } +} +``` + +**Explanation**: +- `try-with-resources` ensures that the file is automatically closed after the operation. +- The `catch` block handles `IOException`, displaying an error message if file reading fails. + +**Output** (If `sample.txt` contains "Hello World!"): +```plaintext +Hello World! +``` + +--- + +### **Exercise 4: Guess the Number Game with Exception Handling** + +**Description**: Create a number-guessing game where players try to guess a randomly generated number. Handle invalid inputs (e.g., non-integer inputs) using exception handling. + +**Code**: + +```java +import java.util.InputMismatchException; +import java.util.Random; +import java.util.Scanner; + +public class GuessTheNumber { + public static void main(String[] args) { + Random random = new Random(); + int targetNumber = random.nextInt(100) + 1; + Scanner scanner = new Scanner(System.in); + int attempts = 0; + boolean guessedCorrectly = false; + + System.out.println("Guess the number between 1 and 100!"); + + while (!guessedCorrectly) { + System.out.print("Enter your guess: "); + try { + int guess = scanner.nextInt(); + attempts++; + if (guess == targetNumber) { + System.out.println("Congratulations! You've guessed the number in " + attempts + " attempts."); + guessedCorrectly = true; + } else if (guess < targetNumber) { + System.out.println("Too low! Try again."); + } else { + System.out.println("Too high! Try again."); + } + } catch (InputMismatchException e) { + System.out.println("Invalid input! Please enter a valid number."); + scanner.next(); // Clear invalid input + } + } + scanner.close(); + } +} +``` + +**Explanation**: +- `InputMismatchException` is handled to manage non-integer inputs. +- If the guess is too high or low, feedback is provided, allowing the player to continue guessing until they succeed. + +**Output** (example): +```plaintext +Guess the number between 1 and 100! +Enter your guess: abc +Invalid input! Please enter a valid number. +Enter your guess: 50 +Too high! Try again. +Enter your guess: 25 +Congratulations! You've guessed the number in 2 attempts. +``` + +--- + +### **Exercise 5: Library Management System with Book Reservation** + +**Description**: Design a Library Management System where users can reserve books. If a book is already reserved, throw a custom `BookNotAvailableException`. Implement exception handling to manage book reservation and return. + +**Code**: + +```java +class BookNotAvailableException extends Exception { + public BookNotAvailableException(String message) { + super(message); + } +} + +class Book { + private String title; + private boolean isReserved; + + public Book(String title) { + this.title = title; + this.isReserved = false; + } + + public void reserve() throws BookNotAvailableException { + if (isReserved) { + throw new BookNotAvailableException("Book '" + title + "' is already reserved."); + } + isReserved = true; + System.out.println("Book '" + title + "' reserved successfully."); + } + + public void returnBook() { + isReserved = false; + System.out.println("Book '" + title + "' returned."); + } +} + +public class LibrarySystem { + public static void main(String[] args) { + Book book = new Book("Java Programming"); + + try { + book.reserve(); + book.reserve(); // Attempt to reserve again, should throw exception + } catch (BookNotAvailableException e) { + System.out.println("Exception: " + e.getMessage()); + } finally { + book.returnBook(); // Ensure the book is returned + } + } +} +``` + +**Explanation**: +- `BookNotAvailableException` is a custom exception triggered when a reserved book is attempted to be reserved again. +- The `finally` block ensures the book is returned after the reservation process, releasing the reservation regardless of the exception. + +**Output**: +```plaintext +Book 'Java Programming' reserved successfully. +Exception: Book 'Java Programming' is already reserved. +Book 'Java Programming' returned. +``` + +--- + +### **Exercise 6: Quiz Competition with Time-Limited Questions** + +**Description**: Create a quiz application where each question has a time limit. If the user fails to answer within the specified time, throw a `TimeLimitExceededException`. + +**Code**: + +```java +import java.util.Scanner; +import java.util.concurrent.*; + +class TimeLimitExceededException extends Exception { + public TimeLimitExceededException(String message) { + super(message); + } +} + +class QuizGame { + private final ExecutorService executor = Executors.newSingleThreadExecutor(); + + public String askQuestion(String question, int timeLimit) throws TimeLimitExceededException { + Callable task = () -> { + Scanner scanner = new Scanner(System.in); + System.out.println(question); + return scanner.nextLine(); + }; + + try { + Future future = executor.submit(task); + return future.get(timeLimit, TimeUnit.SECONDS); + } catch (TimeoutException e) { + throw new TimeLimitExceededException("Time limit exceeded for this question!"); + } catch (Exception e) { + return "An error occurred."; + } + } + + public void endQuiz() { + executor.shutdown(); + } +} + +public class QuizCompetition { + public static void main(String[] args) { + QuizGame quizGame = new QuizGame(); + + try { + String answer = quizGame.askQuestion("What is the capital of France?", 5); + System.out.println("Your answer: " + answer); + } catch (TimeLimitExceededException e) { + System.out.println("Exception: " + e.getMessage()); + } finally { + quizGame.endQuiz(); + } + } +} +``` + +**Explanation**: +- `TimeLimitExceededException` is thrown if the user fails to respond within the allowed time. +- The `ExecutorService` manages the task, allowing a time-bound input mechanism. + +**Output** (if the user exceeds the time limit): +```plaintext +What is the capital of France? +Exception: Time limit exceeded for this question! +``` + +--- + +### **Exercise 7: Online Banking System with Multi-Level Exception Handling** + +**Description**: Build an online banking simulation with funds transfer and balance check operations. If a user tries to transfer an amount greater than their balance, throw an `InsufficientFundsException`. If a negative amount is entered for transfer, throw an `InvalidAmountException`. + +**Code**: + +```java +class InsufficientFundsException extends Exception { + public InsufficientFundsException(String message) { + super(message); + } +} + +class InvalidAmountException extends Exception { + public InvalidAmountException(String message) { + super(message); + } +} + +class Account { + private String accountHolder; + private double balance; + + public Account(String accountHolder, double balance) { + this.accountHolder = accountHolder; + this.balance = balance; + } + + public void transferFunds(double amount) throws InsufficientFundsException, InvalidAmountException { + if (amount <= 0) { + throw new InvalidAmountException("Transfer amount must be positive."); + } + if (amount > balance) { + throw new InsufficientFundsException("Insufficient funds. Available balance: " + balance); + } + balance -= amount; + System.out.println("Transferred " + amount + ". Remaining balance: " + balance); + } + + public double getBalance() { + return balance; + } +} + +public class BankingSystem { + public static void main(String[] args) { + Account account = new Account("Alice", 500); + + try { + account.transferFunds(200); // Successful transfer + account.transferFunds(-50); // Will throw InvalidAmountException + account.transferFunds(400); // Will throw InsufficientFundsException + } catch (InsufficientFundsException | InvalidAmountException e) { + System.out.println("Exception: " + e.getMessage()); + } + } +} +``` + +**Explanation**: +- `InvalidAmountException` is thrown if the transfer amount is non-positive. +- `InsufficientFundsException` is thrown if the transfer amount exceeds the balance. +- The `catch` block manages both exceptions using a multi-catch statement. + +**Output**: +```plaintext +Transferred 200.0. Remaining balance: 300.0 +Exception: Transfer amount must be positive. +Exception: Insufficient funds. Available balance: 300.0 +``` + +--- + +## Section 29: Files and Directories in Java + +#### **Group 1: Listing Files and Directories (Steps 1-2)** + - **Why Grouped**: This group introduces methods for listing and filtering files in a directory. It covers both single-level file listing with `Files.list()` and recursive listing with `Files.walk()`. + +#### **Puzzles** + +**Puzzle 1**: **List All Files in a Directory** + - **Problem**: Write a program that lists all files and folders in a specified directory. + - **Code**: + ```java + import java.nio.file.Files; + import java.nio.file.Path; + import java.nio.file.Paths; + import java.io.IOException; + + public class ListFiles { + public static void main(String[] args) { + try { + Files.list(Paths.get(".")) + .forEach(System.out::println); + } catch (IOException e) { + System.out.println("Error listing files: " + e.getMessage()); + } + } + } + ``` + - **Output**: + ``` + ./.classpath + ./.project + ./src + ./bin + ./resources + ``` + +**Puzzle 2**: **Recursive Directory Listing with Filtering** + - **Problem**: List all `.java` files within a directory recursively. + - **Code**: + ```java + import java.nio.file.*; + import java.io.IOException; + + public class ListJavaFiles { + public static void main(String[] args) { + try { + Files.walk(Paths.get(".")) + .filter(path -> path.toString().endsWith(".java")) + .forEach(System.out::println); + } catch (IOException e) { + System.out.println("Error: " + e.getMessage()); + } + } + } + ``` + - **Output**: + ``` + ./src/Main.java + ./src/Utils.java + ./tests/TestMain.java + ``` + +### **New Quiz Questions** + +1. **Which method is used to list files in a directory in Java?** + - A) `Files.readAllLines()` + - B) `Files.list()` **(Answer)** + - C) `Files.lines()` + +2. **What method allows recursive listing of files in Java?** + - A) `Files.walk()` **(Answer)** + - B) `Files.find()` + - C) `Files.lines()` + +### **Fun Fact** + +- **Did you know?** The `Files.walk()` method allows for depth-first traversal of a file tree, providing developers an efficient way to navigate large directory structures. + +--- + +#### **Group 2: Reading and Writing Files (Steps 3-4)** + - **Why Grouped**: This group focuses on file content operations, covering reading and writing methods with `Files.readAllLines()`, `Files.lines()`, and `Files.write()`. + +#### **Puzzles** + +**Puzzle 1**: **Read from a File and Print Each Line** + - **Problem**: Write a program to read all lines from a file and print each line to the console. + - **Code**: + ```java + import java.nio.file.*; + import java.io.IOException; + import java.util.List; + + public class ReadFileExample { + public static void main(String[] args) { + Path path = Paths.get("resources/data.txt"); + try { + List lines = Files.readAllLines(path); + lines.forEach(System.out::println); + } catch (IOException e) { + System.out.println("Error reading file: " + e.getMessage()); + } + } + } + ``` + - **Output** (assuming `data.txt` contains "Hello World!" and "Java is great!"): + ``` + Hello, World! + Java is great! + ``` + +**Puzzle 2**: **Write Content to a File** + - **Problem**: Create a list of strings and write each string to a file. + - **Code**: + ```java + import java.nio.file.*; + import java.io.IOException; + import java.util.List; + + public class WriteToFile { + public static void main(String[] args) { + Path path = Paths.get("resources/output.txt"); + List content = List.of("Java", "Python", "C++"); + try { + Files.write(path, content); + System.out.println("Content written to file."); + } catch (IOException e) { + System.out.println("Error writing to file: " + e.getMessage()); + } + } + } + ``` + - **Output**: + ``` + Content written to file. + ``` + +### **New Quiz Questions** + +1. **Which method reads all lines of a file at once?** + - A) `Files.lines()` + - B) `Files.readAllLines()` **(Answer)** + - C) `Files.walk()` + +2. **Which method is best for reading large files line-by-line in Java?** + - A) `Files.readAllLines()` + - B) `Files.write()` + - C) `Files.lines()` **(Answer)** + +3. **What does the `Files.write()` method do?** + - A) Reads content from a file + - B) Writes content to a file **(Answer)** + - C) Lists files in a directory + +### **Fun Fact** + +- **Did you know?** The `Files.lines()` method allows reading large files line-by-line, making it highly efficient for big data applications and minimizing memory use. + +--- + +#### **Group 3: Conclusion and Best Practices (Step 5)** + - **Why Grouped**: This group summarizes the best practices for handling files, especially when managing large files, using functional programming concepts like `map` and `filter` with file streams. + +#### **Puzzles** + +**Puzzle 1**: **Use Stream API to Count Lines in a File** + - **Problem**: Count the number of lines in a file using `Files.lines()` and display the result. + - **Code**: + ```java + import java.nio.file.*; + import java.io.IOException; + + public class CountLinesInFile { + public static void main(String[] args) { + Path path = Paths.get("resources/sample.txt"); + try { + long lineCount = Files.lines(path).count(); + System.out.println("Total lines: " + lineCount); + } catch (IOException e) { + System.out.println("Error reading file: " + e.getMessage()); + } + } + } + ``` + - **Output** (if `sample.txt` contains 3 lines): + ``` + Total lines: 3 + ``` + +**Puzzle 2**: **File Copy with Best Practices** + - **Problem**: Copy content from one file to another, demonstrating best practices. + - **Code**: + ```java + import java.nio.file.*; + import java.io.IOException; + + public class FileCopyExample { + public static void main(String[] args) { + Path source = Paths.get("resources/source.txt"); + Path destination = Paths.get("resources/destination.txt"); + + try { + Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING); + System.out.println("File copied successfully."); + } catch (IOException e) { + System.out.println("Error copying file: " + e.getMessage()); + } + } + } + ``` + - **Output**: + ``` + File copied successfully. + ``` + +### **New Quiz Questions** + +1. **Which class is used to handle file paths in Java’s NIO package?** + - A) `Paths` **(Answer)** + - B) `FileReader` + - C) `FileInputStream` + +2. **What is a recommended best practice when handling large files in Java?** + - A) Load the entire file into memory + - B) Use `Files.lines()` to read line-by-line **(Answer)** + - C) Avoid using streams for large files + +3. **How does `Files.copy()` behave if the destination file already exists and `REPLACE_EXISTING` is not specified?** + - A) It will overwrite the file + - B) It will throw an `IOException` **(Answer)** + - C) It will append content to the file + +### **Fun Fact** + +- **Did you know?** The `StandardCopyOption.REPLACE_EXISTING` option allows developers to specify whether they want to overwrite an existing file, providing control over file copy operations and reducing potential errors. + +--- + +### Additional Coding Exercises + +### **Exercise 1: File Directory Explorer with Filtering and Sorting** + +**Description**: Create a program that explores a directory, lists all `.txt` files in a specified directory, and sorts them by their last modified date in descending order. + +**Code**: + +```java +import java.nio.file.*; +import java.io.IOException; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Comparator; +import java.util.stream.Stream; + +public class DirectoryExplorer { + public static void main(String[] args) { + Path path = Paths.get("resources"); // specify the directory path + + try (Stream stream = Files.list(path)) { + stream.filter(p -> p.toString().endsWith(".txt")) + .sorted((p1, p2) -> { + try { + BasicFileAttributes attr1 = Files.readAttributes(p1, BasicFileAttributes.class); + BasicFileAttributes attr2 = Files.readAttributes(p2, BasicFileAttributes.class); + return attr2.lastModifiedTime().compareTo(attr1.lastModifiedTime()); + } catch (IOException e) { + return 0; + } + }) + .forEach(System.out::println); + } catch (IOException e) { + System.out.println("Error accessing directory: " + e.getMessage()); + } + } +} +``` + +**Explanation**: +- Filters files with `.txt` extension. +- Sorts the files by last modified date in descending order. +- Outputs the sorted list of `.txt` files to the console. + +**Output**: +```plaintext +resources/report.txt +resources/log.txt +resources/notes.txt +``` + +--- + +### **Exercise 2: File Word Counter** + +**Description**: Develop a program that reads a file and counts the occurrences of each word, ignoring case sensitivity. + +**Code**: + +```java +import java.nio.file.*; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +public class WordCounter { + public static void main(String[] args) { + Path path = Paths.get("resources/sample.txt"); // specify the file path + + Map wordCount = new HashMap<>(); + + try (Stream lines = Files.lines(path)) { + lines.forEach(line -> { + String[] words = line.toLowerCase().split("\\W+"); + for (String word : words) { + if (word.isEmpty()) continue; + wordCount.put(word, wordCount.getOrDefault(word, 0) + 1); + } + }); + + wordCount.forEach((word, count) -> System.out.println(word + ": " + count)); + } catch (IOException e) { + System.out.println("Error reading file: " + e.getMessage()); + } + } +} +``` + +**Explanation**: +- Reads a text file and splits each line into words, converting them to lowercase. +- Counts occurrences of each word and stores them in a `Map`. +- Displays each word and its frequency in the console. + +**Output**: +```plaintext +java: 3 +programming: 2 +language: 1 +``` + +--- + +### **Exercise 3: File Search Game** + +**Description**: Create a file search game where users try to guess the name of a file that exists in a directory. The program hints if their guesses are close by showing the files alphabetically near the guessed name. + +**Code**: + +```java +import java.nio.file.*; +import java.io.IOException; +import java.util.List; +import java.util.Scanner; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class FileGuessGame { + public static void main(String[] args) { + Path path = Paths.get("resources"); + Scanner scanner = new Scanner(System.in); + + try (Stream stream = Files.list(path)) { + List fileNames = stream.map(p -> p.getFileName().toString()) + .sorted() + .collect(Collectors.toList()); + + System.out.println("Guess the name of a file in the directory (hint: type 'list' to see all files)."); + String guess; + + while (true) { + System.out.print("Enter your guess: "); + guess = scanner.nextLine().trim(); + + if (guess.equalsIgnoreCase("list")) { + fileNames.forEach(System.out::println); + continue; + } + + if (fileNames.contains(guess)) { + System.out.println("Correct! The file exists in the directory."); + break; + } else { + System.out.println("Incorrect. Here are some close matches:"); + fileNames.stream() + .filter(name -> name.compareTo(guess) > 0) + .limit(3) + .forEach(System.out::println); + } + } + } catch (IOException e) { + System.out.println("Error accessing directory: " + e.getMessage()); + } + + scanner.close(); + } +} +``` + +**Explanation**: +- Lists files in a directory and allows the user to guess file names. +- Provides hints by displaying a few file names alphabetically near the incorrect guess. + +**Output**: +```plaintext +Guess the name of a file in the directory (hint: type 'list' to see all files). +Enter your guess: sample.txt +Incorrect. Here are some close matches: +summary.txt +test.txt +``` + +--- + +### **Exercise 4: Directory Size Calculator with Progress Display** + +**Description**: Write a program that calculates the total size of all files in a directory. Display progress by printing each file’s size as it is calculated. + +**Code**: + +```java +import java.nio.file.*; +import java.io.IOException; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.stream.Stream; + +public class DirectorySizeCalculator { + public static void main(String[] args) { + Path path = Paths.get("resources"); // specify directory + + try (Stream stream = Files.walk(path)) { + long totalSize = stream.filter(Files::isRegularFile) + .mapToLong(p -> { + try { + long size = Files.size(p); + System.out.println("File: " + p + " Size: " + size + " bytes"); + return size; + } catch (IOException e) { + System.out.println("Error reading file: " + p); + return 0L; + } + }) + .sum(); + + System.out.println("Total Directory Size: " + totalSize + " bytes"); + } catch (IOException e) { + System.out.println("Error accessing directory: " + e.getMessage()); + } + } +} +``` + +**Explanation**: +- Recursively traverses a directory and calculates the size of each file. +- Outputs each file’s size as it’s processed, then displays the total directory size. + +**Output**: +```plaintext +File: resources/sample1.txt Size: 256 bytes +File: resources/sample2.txt Size: 512 bytes +File: resources/sample3.txt Size: 128 bytes +Total Directory Size: 896 bytes +``` + +--- + +## Section 30: More Concurrency with Concurrent Collections and Atomic Operations + +#### **Group 1: Basics of Synchronization and Locks (Steps 1-3)** + - **Why Grouped**: This group introduces the essentials of synchronization with `synchronized` and its limitations, and progresses to using `ReentrantLock` for more efficient thread management. + +#### **Puzzles** + +**Puzzle 1**: **Synchronized Counter Example** + - **Problem**: Implement a thread-safe counter using the `synchronized` keyword. + - **Code**: + ```java + class Counter { + private int count = 0; + + public synchronized void increment() { + count++; + } + + public synchronized int getCount() { + return count; + } + } + + public class SynchronizedCounter { + public static void main(String[] args) throws InterruptedException { + Counter counter = new Counter(); + + Runnable task = () -> { + for (int i = 0; i < 1000; i++) { + counter.increment(); + } + }; + + Thread thread1 = new Thread(task); + Thread thread2 = new Thread(task); + + thread1.start(); + thread2.start(); + + thread1.join(); + thread2.join(); + + System.out.println("Final Count: " + counter.getCount()); + } + } + ``` + - **Output**: + ```plaintext + Final Count: 2000 + ``` + +**Puzzle 2**: **ReentrantLock with Two Counters** + - **Problem**: Use `ReentrantLock` to manage synchronization with two separate counters. + - **Code**: + ```java + import java.util.concurrent.locks.ReentrantLock; + + class DualCounter { + private int counter1 = 0; + private int counter2 = 0; + private final ReentrantLock lock1 = new ReentrantLock(); + private final ReentrantLock lock2 = new ReentrantLock(); + + public void incrementCounter1() { + lock1.lock(); + try { + counter1++; + } finally { + lock1.unlock(); + } + } + + public void incrementCounter2() { + lock2.lock(); + try { + counter2++; + } finally { + lock2.unlock(); + } + } + + public int getCounter1() { + return counter1; + } + + public int getCounter2() { + return counter2; + } + } + + public class ReentrantLockExample { + public static void main(String[] args) throws InterruptedException { + DualCounter dualCounter = new DualCounter(); + Runnable task1 = dualCounter::incrementCounter1; + Runnable task2 = dualCounter::incrementCounter2; + + Thread t1 = new Thread(task1); + Thread t2 = new Thread(task2); + t1.start(); + t2.start(); + + t1.join(); + t2.join(); + + System.out.println("Counter1: " + dualCounter.getCounter1()); + System.out.println("Counter2: " + dualCounter.getCounter2()); + } + } + ``` + - **Output**: + ```plaintext + Counter1: 1 + Counter2: 1 + ``` + +#### **New Quiz Questions** + +1. **Which of the following ensures thread safety for a single method?** + - A) `volatile` + - B) `synchronized` **(Answer)** + - C) `final` + +2. **What is a primary limitation of `synchronized` for concurrent methods?** + - A) Too much concurrency + - B) Only one thread can execute at a time per object instance **(Answer)** + - C) Locks only local variables + +#### **Fun Fact** + +- **Did you know?** Reentrant locks allow the same thread to acquire a lock multiple times without getting stuck. This ability to re-enter is especially useful in recursive calls and complex threading operations. + +--- + +#### **Group 2: Atomic Classes and Concurrent Collections (Steps 4-7)** + + - **Why Grouped**: This group introduces atomic classes like `AtomicInteger` for atomic operations, and `ConcurrentHashMap` for concurrent access to collections with built-in thread safety and regional locking for optimized performance. + +#### **Puzzles** + +**Puzzle 1**: **Atomic Integer Counter** + - **Problem**: Implement a thread-safe counter using `AtomicInteger`. + - **Code**: + ```java + import java.util.concurrent.atomic.AtomicInteger; + + class AtomicCounter { + private AtomicInteger count = new AtomicInteger(0); + + public void increment() { + count.incrementAndGet(); + } + + public int getCount() { + return count.get(); + } + } + + public class AtomicCounterExample { + public static void main(String[] args) throws InterruptedException { + AtomicCounter counter = new AtomicCounter(); + Runnable task = counter::increment; + + Thread thread1 = new Thread(task); + Thread thread2 = new Thread(task); + thread1.start(); + thread2.start(); + + thread1.join(); + thread2.join(); + + System.out.println("Final Count: " + counter.getCount()); + } + } + ``` + - **Output**: + ```plaintext + Final Count: 2 + ``` + +**Puzzle 2**: **ConcurrentHashMap Character Counter** + - **Problem**: Use `ConcurrentHashMap` to count occurrences of each character in a string. + - **Code**: + ```java + import java.util.concurrent.ConcurrentHashMap; + + public class ConcurrentCharacterCounter { + public static void main(String[] args) { + ConcurrentHashMap counter = new ConcurrentHashMap<>(); + String text = "Hello World"; + + for (char c : text.toCharArray()) { + counter.merge(c, 1, Integer::sum); + } + + counter.forEach((key, value) -> System.out.println(key + ": " + value)); + } + } + ``` + - **Output**: + ```plaintext + H: 1 + e: 1 + l: 3 + o: 2 + W: 1 + r: 1 + d: 1 + ``` + +#### **New uiz Questions** + +1. **What class is used to handle atomic integer operations?** + - A) `Integer` + - B) `AtomicInteger` **(Answer)** + - C) `ConcurrentInteger` + +2. **Which class provides a thread-safe alternative to `HashMap`?** + - A) `Hashtable` + - B) `ConcurrentHashMap` **(Answer)** + - C) `HashMap` + +#### **Fun Fact** + +- **Did you know?** `ConcurrentHashMap` employs a segmented locking mechanism, allowing different threads to access distinct regions of the map simultaneously, significantly boosting performance in concurrent environments. + +--- + +#### **Group 3: CopyOnWrite Collections (Step 8)** + - **Why Grouped**: This group discusses `CopyOnWriteArrayList` and `CopyOnWriteArraySet`, optimized for situations where reads heavily outweigh writes. These collections copy data on each write operation. + +#### **Puzzles** + +**Puzzle 1**: **CopyOnWriteArrayList Example** + - **Problem**: Demonstrate how `CopyOnWriteArrayList` allows concurrent reads and occasional writes without affecting other threads. + - **Code**: + ```java + import java.util.List; + import java.util.concurrent.CopyOnWriteArrayList; + + public class CopyOnWriteExample { + public static void main(String[] args) { + List list = new CopyOnWriteArrayList<>(List.of("A", "B", "C")); + + // Reading elements + for (String s : list) { + System.out.println("Reading: " + s); + } + + // Adding a new element + list.add("D"); + + // Reading elements again + for (String s : list) { + System.out.println("Reading after adding: " + s); + } + } + } + ``` + - **Output**: + ```plaintext + Reading: A + Reading: B + Reading: C + Reading after adding: A + Reading after adding: B + Reading after adding: C + Reading after adding: D + ``` + +#### **New Quiz Questions** + +1. **Which class is optimized for high reads and low writes?** + - A) `ArrayList` + - B) `CopyOnWriteArrayList` **(Answer)** + - C) `LinkedList` + +2. **What happens in a `CopyOnWriteArrayList` when an element is modified?** + - A) The list is replaced with a new copy **(Answer)** + - B) The modification is ignored + - C) It throws an exception + +#### **Fun Fact** + +- **Did you know?** `CopyOnWriteArrayList` is particularly useful in read-heavy scenarios like cache implementations or applications where data is infrequently updated but frequently read by multiple threads. + +--- + +#### **Group 4: Conclusion and Best Practices (Step 9)** + - **Why Grouped**: This step provides a wrap-up of best practices for using concurrent collections and atomic operations effectively, emphasizing scenarios and recommendations for choosing the right data structure for optimal performance. + +#### **Puzzles** + +**Puzzle 1**: **AtomicBoolean for Task Management** + - **Problem**: Use `AtomicBoolean` to manage a shared resource between threads. + - **Code**: + ```java + import java.util.concurrent.atomic.AtomicBoolean; + + class SharedTask { + private AtomicBoolean isRunning = new Atomic + +Boolean(false); + + public void startTask() { + if (isRunning.compareAndSet(false, true)) { + System.out.println("Task started by " + Thread.currentThread().getName()); + } else { + System.out.println("Task already running!"); + } + } + } + + public class AtomicBooleanExample { + public static void main(String[] args) { + SharedTask task = new SharedTask(); + + Runnable taskRunner = task::startTask; + + Thread t1 = new Thread(taskRunner, "Thread-1"); + Thread t2 = new Thread(taskRunner, "Thread-2"); + + t1.start(); + t2.start(); + } + } + ``` + - **Output**: + ```plaintext + Task started by Thread-1 + Task already running! + ``` + +#### **New Quiz Questions** + +1. **What class provides atomic operations for a boolean value?** + - A) `AtomicBoolean` **(Answer)** + - B) `AtomicBooleanValue` + - C) `AtomicFlag` + +2. **Which of these is recommended when many threads perform frequent reads but few writes?** + - A) `ConcurrentHashMap` + - B) `CopyOnWriteArrayList` **(Answer)** + - C) `ArrayList` + +#### **Fun Fact** + +- **Did you know?** Atomic classes, like `AtomicBoolean`, allow multiple threads to safely manage shared flags, making them ideal for controlling tasks and managing shared resources. + +--- + +### Additional Coding Exercises + +### **Exercise 1: Concurrent Auction System Simulation** + +**Description**: +Create a simulation of an online auction system where multiple bidders place bids on items simultaneously. Use `ConcurrentHashMap` to store the items and their current highest bids and simulate concurrency by using multiple threads to represent bidders. + +**Code**: +```java +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ThreadLocalRandom; + +class Auction { + private final ConcurrentHashMap itemBids = new ConcurrentHashMap<>(); + + public Auction(String... items) { + for (String item : items) { + itemBids.put(item, 0); + } + } + + public void placeBid(String item, int bidAmount) { + itemBids.merge(item, bidAmount, Math::max); // Only keeps highest bid + } + + public void displayResults() { + itemBids.forEach((item, highestBid) -> System.out.println(item + " highest bid: " + highestBid)); + } +} + +public class AuctionSimulation { + public static void main(String[] args) throws InterruptedException { + Auction auction = new Auction("Laptop", "Smartphone", "Tablet"); + + Runnable bidder = () -> { + for (int i = 0; i < 10; i++) { + String item = switch (ThreadLocalRandom.current().nextInt(3)) { + case 0 -> "Laptop"; + case 1 -> "Smartphone"; + default -> "Tablet"; + }; + int bidAmount = ThreadLocalRandom.current().nextInt(100, 1000); + auction.placeBid(item, bidAmount); + System.out.println(Thread.currentThread().getName() + " placed a bid of " + bidAmount + " on " + item); + } + }; + + Thread bidder1 = new Thread(bidder); + Thread bidder2 = new Thread(bidder); + Thread bidder3 = new Thread(bidder); + + bidder1.start(); + bidder2.start(); + bidder3.start(); + + bidder1.join(); + bidder2.join(); + bidder3.join(); + + System.out.println("\nAuction Results:"); + auction.displayResults(); + } +} +``` + +**Output**: +```plaintext +Thread-0 placed a bid of 450 on Smartphone +Thread-0 placed a bid of 320 on Laptop +Thread-1 placed a bid of 650 on Tablet +Thread-2 placed a bid of 750 on Laptop +... +Auction Results: +Laptop highest bid: 750 +Smartphone highest bid: 450 +Tablet highest bid: 650 +``` + +--- + +### **Exercise 2: Atomic Integer Game - Hit Counter** + +**Description**: +Implement a game where players hit a target, and the total hits are counted using `AtomicInteger`. This ensures thread-safe counting, even if multiple players hit the target simultaneously. Each thread represents a player attempting to hit the target. + +**Code**: +```java +import java.util.concurrent.atomic.AtomicInteger; + +class TargetGame { + private final AtomicInteger hitCount = new AtomicInteger(0); + + public void hit() { + hitCount.incrementAndGet(); + } + + public int getHits() { + return hitCount.get(); + } +} + +public class HitCounterGame { + public static void main(String[] args) throws InterruptedException { + TargetGame game = new TargetGame(); + + Runnable player = () -> { + for (int i = 0; i < 100; i++) { + game.hit(); + System.out.println(Thread.currentThread().getName() + " hit the target."); + } + }; + + Thread player1 = new Thread(player); + Thread player2 = new Thread(player); + Thread player3 = new Thread(player); + + player1.start(); + player2.start(); + player3.start(); + + player1.join(); + player2.join(); + player3.join(); + + System.out.println("\nTotal Hits: " + game.getHits()); + } +} +``` + +**Output**: +```plaintext +Thread-0 hit the target. +Thread-1 hit the target. +Thread-2 hit the target. +... +Total Hits: 300 +``` + +--- + +### **Exercise 3: Thread-Safe Chat Room with CopyOnWriteArrayList** + +**Description**: +Simulate a chat room where users can join and send messages concurrently. Use `CopyOnWriteArrayList` to store messages and allow multiple threads to simulate concurrent messaging. + +**Code**: +```java +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +class ChatRoom { + private final List messages = new CopyOnWriteArrayList<>(); + + public void postMessage(String message) { + messages.add(message); + } + + public void displayMessages() { + messages.forEach(System.out::println); + } +} + +public class ChatRoomSimulation { + public static void main(String[] args) throws InterruptedException { + ChatRoom chatRoom = new ChatRoom(); + + Runnable user = () -> { + for (int i = 0; i < 5; i++) { + String message = Thread.currentThread().getName() + " says hello " + i; + chatRoom.postMessage(message); + System.out.println(Thread.currentThread().getName() + " posted: " + message); + } + }; + + Thread user1 = new Thread(user); + Thread user2 = new Thread(user); + Thread user3 = new Thread(user); + + user1.start(); + user2.start(); + user3.start(); + + user1.join(); + user2.join(); + user3.join(); + + System.out.println("\nChat Room Messages:"); + chatRoom.displayMessages(); + } +} +``` + +**Output**: +```plaintext +Thread-0 posted: Thread-0 says hello 0 +Thread-1 posted: Thread-1 says hello 0 +Thread-2 posted: Thread-2 says hello 0 +... +Chat Room Messages: +Thread-0 says hello 0 +Thread-0 says hello 1 +Thread-1 says hello 0 +Thread-2 says hello 0 +Thread-1 says hello 1 +Thread-2 says hello 1 +``` + +--- + +### **Exercise 4: Multi-threaded Bank Account System Using Locks** + +**Description**: +Simulate a bank account system where multiple users try to deposit and withdraw money concurrently. Use `ReentrantLock` to ensure transactions are safely handled without overlapping. + +**Code**: +```java +import java.util.concurrent.locks.ReentrantLock; + +class BankAccount { + private double balance; + private final ReentrantLock lock = new ReentrantLock(); + + public BankAccount(double initialBalance) { + this.balance = initialBalance; + } + + public void deposit(double amount) { + lock.lock(); + try { + balance += amount; + System.out.println(Thread.currentThread().getName() + " deposited " + amount + ". New Balance: " + balance); + } finally { + lock.unlock(); + } + } + + public void withdraw(double amount) { + lock.lock(); + try { + if (balance >= amount) { + balance -= amount; + System.out.println(Thread.currentThread().getName() + " withdrew " + amount + ". New Balance: " + balance); + } else { + System.out.println(Thread.currentThread().getName() + " tried to withdraw " + amount + " but insufficient funds."); + } + } finally { + lock.unlock(); + } + } + + public double getBalance() { + return balance; + } +} + +public class BankAccountSimulation { + public static void main(String[] args) throws InterruptedException { + BankAccount account = new BankAccount(500); + + Runnable depositTask = () -> { + for (int i = 0; i < 3; i++) { + account.deposit(100); + } + }; + + Runnable withdrawTask = () -> { + for (int i = 0; i < 3; i++) { + account.withdraw(50); + } + }; + + Thread thread1 = new Thread(depositTask); + Thread thread2 = new Thread(withdrawTask); + Thread thread3 = new Thread(depositTask); + + thread1.start(); + thread2.start(); + thread3.start(); + + thread1.join(); + thread2.join(); + thread3.join(); + + System.out.println("\nFinal Balance: " + account.getBalance()); + } +} +``` + +**Output**: +```plaintext +Thread-0 deposited 100. New Balance: 600.0 +Thread-1 withdrew 50. New Balance: 550.0 +Thread-2 deposited 100. New Balance: 650.0 +... +Final Balance: 800.0 +``` + +--- + +> End of this document - Last updated 18:46 10/26 \ No newline at end of file