diff --git a/data/Java/data/01-beginner/02-java-basics.md b/data/Java/data/01-beginner/02-java-basics.md index 40c4444d..ac3b1f42 100644 --- a/data/Java/data/01-beginner/02-java-basics.md +++ b/data/Java/data/01-beginner/02-java-basics.md @@ -2,1163 +2,133 @@ **Module 01 · Beginner · Lesson 02 of 10** +## Learning Objectives -## Learning objectives - -- Understand **java basics and syntax** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Understand the structure of a Java program +- Know the difference between compiled and interpreted languages +- Write and read basic Java syntax correctly ## Overview -Java Basics and Syntax is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. - -## Key concepts - -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes - -## Example - -```java -// Java Basics and Syntax — practice sketch -// add your code here -``` - -## Exercise - -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). - -## Checkpoint - -You are ready for the next lesson when you can solve the exercise without copying the example. - ---- - -**Next:** Continue to lesson 03 in this module. - ---- - -## Additional reference - -# Level 1: Java Fundamentals - Building Strong Foundations - -**Duration:** 4 Weeks | **Difficulty:** Beginner | **Prerequisites:** Level 0 Complete - -## 🎯 Week 3: Control Flow and Decision Making - -### Day 15: If/Else Statements - -#### Understanding Conditional Logic -Conditional statements allow your program to make decisions based on conditions. - -#### Basic If Statement -```java -age = 18 - -if age >= 18: - print("You are an adult!") - print("You can vote!") -``` - -#### If-Else Statement -```java -age = 16 - -if age >= 18: - print("You are an adult!") -else: - print("You are a minor!") -``` - -#### If-Elif-Else Chain -```java -grade = 85 - -if grade >= 90: - letter = "A" -elif grade >= 80: - letter = "B" -elif grade >= 70: - letter = "C" -elif grade >= 60: - letter = "D" -else: - letter = "F" - -print(f"Your grade: {grade} = {letter}") -``` - -#### Nested Conditions -```java -age = 25 -has_license = True - -if age >= 18: - if has_license: - print("You can drive!") - else: - print("You need to get a license first!") -else: - print("You're too young to drive!") -``` - -### Day 16: Logical Operators - -#### AND Operator -Both conditions must be True: -```java -age = 25 -has_license = True - -if age >= 18 and has_license: - print("You can drive!") -else: - print("You cannot drive!") - -# More examples -temperature = 75 -weather = "sunny" - -if temperature > 70 and weather == "sunny": - print("Perfect day for a picnic!") -``` - -#### OR Operator -At least one condition must be True: -```java -day = "Saturday" -is_holiday = True - -if day == "Saturday" or day == "Sunday" or is_holiday: - print("No work today!") -else: - print("Time to work!") - -# Practical example -has_car = False -has_bike = True - -if has_car or has_bike: - print("You can get around!") -else: - print("You need transportation!") -``` - -#### NOT Operator -Reverses the condition: -```java -is_raining = False - -if not is_raining: - print("Let's go outside!") -else: - print("Stay indoors!") - -# Combining with other operators -age = 17 -has_parent_permission = True - -if age >= 18 or (age < 18 and has_parent_permission): - print("You can attend the concert!") -else: - print("Sorry, you cannot attend!") -``` - -#### Complex Conditions -```java -# Student eligibility example -age = 20 -gpa = 3.5 -has_extracurricular = True -citizen = True - -if age >= 18 and age <= 25 and gpa >= 3.0 and has_extracurricular and citizen: - print("Eligible for scholarship!") -else: - print("Not eligible for scholarship.") - - # Provide specific reasons - if age < 18 or age > 25: - print("- Age requirement not met") - if gpa < 3.0: - print("- GPA too low") - if not has_extracurricular: - print("- No extracurricular activities") - if not citizen: - print("- Not a citizen") -``` - -### Day 17: Nested Conditions and Complex Logic +Java is a **compiled, statically-typed, object-oriented** language. Before your code runs, the Java compiler (`javac`) converts it into **bytecode** (`.class` files), which the Java Virtual Machine (JVM) then executes. This is what makes Java "write once, run anywhere." -#### Multi-Level Decision Making -```java -def classify_person(age, student_status, employment_status): - """Classify person based on multiple factors""" - - if age < 18: - return "Minor" - else: - if student_status == "full-time": - return "Full-time Student" - elif student_status == "part-time": - if employment_status == "full-time": - return "Working Part-time Student" - else: - return "Part-time Student" - else: - if employment_status == "full-time": - return "Full-time Employee" - elif employment_status == "part-time": - return "Part-time Employee" - else: - return "Unemployed" - -# Test the function -print(classify_person(16, "none", "none")) # Minor -print(classify_person(20, "full-time", "none")) # Full-time Student -print(classify_person(22, "part-time", "full-time")) # Working Part-time Student -``` +Every Java program starts inside a **class**, and execution begins from a special method called `main`. -#### Practical Example: Loan Approval -```java -def approve_loan(credit_score, income, employment_years, debt_ratio): - """Determine loan approval status""" - - # Basic eligibility - if credit_score < 600: - return "Denied: Credit score too low" - - if income < 20000: - return "Denied: Income too low" - - if employment_years < 1: - return "Denied: Insufficient employment history" - - if debt_ratio > 0.4: - return "Denied: Debt-to-income ratio too high" - - # Determine loan amount and interest rate - if credit_score >= 750 and income >= 50000: - return "Approved: Maximum amount, Prime rate" - elif credit_score >= 700 and income >= 35000: - return "Approved: Standard amount, Good rate" - else: - return "Approved: Limited amount, Standard rate" - -# Test cases -print(approve_loan(780, 75000, 5, 0.2)) # Best case -print(approve_loan(650, 30000, 2, 0.3)) # Average case -print(approve_loan(550, 25000, 3, 0.5)) # Denied -``` +## Key Concepts -### Day 18: Practice Problems +### 1. Program Structure -#### Exercise 1: Grade Calculator -Create a program that calculates letter grades and GPA. +Every Java file must have: +- A **class** whose name matches the filename exactly +- A `main` method as the entry point ```java -def calculate_grade(score): - """Convert numeric score to letter grade""" - if score >= 97: - return "A+", 4.0 - elif score >= 93: - return "A", 4.0 - elif score >= 90: - return "A-", 3.7 - elif score >= 87: - return "B+", 3.3 - elif score >= 83: - return "B", 3.0 - elif score >= 80: - return "B-", 2.7 - elif score >= 77: - return "C+", 2.3 - elif score >= 73: - return "C", 2.0 - elif score >= 70: - return "C-", 1.7 - elif score >= 67: - return "D+", 1.3 - elif score >= 65: - return "D", 1.0 - else: - return "F", 0.0 - -def calculate_gpa(grades_list): - """Calculate GPA from a list of grades""" - total_points = 0 - for grade in grades_list: - letter, points = calculate_grade(grade) - total_points += points - return total_points / len(grades_list) - -# Test the functions -scores = [92, 85, 78, 95, 88] -for score in scores: - letter, points = calculate_grade(score) - print(f"Score {score}: Grade {letter} ({points} points)") - -gpa = calculate_gpa(scores) -print(f"Overall GPA: {gpa:.2f}") -``` - -#### Exercise 2: Ticket Pricing System -Calculate ticket prices based on age and membership. - -```java -def calculate_ticket_price(age, is_member, is_student, day_of_week): - """Calculate ticket price based on multiple factors""" - - base_price = 10.00 - - # Age discounts - if age < 5: - return 0.00 # Free for toddlers - elif age >= 65: - base_price *= 0.7 # 30% senior discount - elif age < 18: - base_price *= 0.8 # 20% child discount - - # Membership discount - if is_member: - base_price *= 0.9 # 10% member discount - - # Student discount (additional) - if is_student and age >= 18: - base_price *= 0.85 # 15% student discount - - # Weekend surcharge - if day_of_week in ["Saturday", "Sunday"]: - base_price *= 1.1 # 10% weekend surcharge - - # Round to 2 decimal places - return round(base_price, 2) - -# Test scenarios -scenarios = [ - (4, False, False, "Monday"), # Toddler - (16, False, True, "Saturday"), # Student on weekend - (25, True, False, "Friday"), # Member - (70, False, False, "Sunday"), # Senior on weekend - (20, True, True, "Wednesday") # Student member -] - -for age, member, student, day in scenarios: - price = calculate_ticket_price(age, member, student, day) - print(f"Age {age}, Member: {member}, Student: {student}, {day}: ${price}") -``` - -### Day 19: Switch-like Patterns - -#### Java's Match Statement (Java 3.10+) -```java -def get_day_type(day): - """Categorize day of week""" - match day: - case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday": - return "Weekday" - case "Saturday" | "Sunday": - return "Weekend" - case _: - return "Invalid day" - -# Alternative for older Java versions -def get_day_type_old(day): - """Categorize day of week (compatible with older Java)""" - weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"] - weekends = ["Saturday", "Sunday"] - - if day in weekdays: - return "Weekday" - elif day in weekends: - return "Weekend" - else: - return "Invalid day" -``` - -#### Dictionary-based Switch -```java -def get_operation(operator): - """Get operation function based on operator""" - operations = { - "+": lambda a, b: a + b, - "-": lambda a, b: a - b, - "*": lambda a, b: a * b, - "/": lambda a, b: a / b, - "^": lambda a, b: a ** b, - "%": lambda a, b: a % b +// File: MyProgram.java +public class MyProgram { + public static void main(String[] args) { + System.out.println("Hello from Java!"); } - - return operations.get(operator, lambda a, b: "Invalid operator") - -# Test -op_func = get_operation("+") -result = op_func(5, 3) # 8 -print(f"5 + 3 = {result}") -``` - -### Day 20: Project - Number Guessing Game - -#### Complete Number Guessing Game -```java -import random - -def play_number_guessing_game(): - """Interactive number guessing game""" - - print("=" * 50) - print(" NUMBER GUESSING GAME") - print("=" * 50) - print("I'm thinking of a number between 1 and 100!") - print("Can you guess what it is?") - print() - - # Generate random number - secret_number = random.randint(1, 100) - attempts = 0 - max_attempts = 10 - - while attempts < max_attempts: - attempts += 1 - remaining = max_attempts - attempts - - # Get user guess - try: - guess = int(input(f"Attempt {attempts}/{max_attempts}. Enter your guess: ")) - except ValueError: - print("Please enter a valid number!") - attempts -= 1 # Don't count invalid attempts - continue - - # Validate guess range - if guess < 1 or guess > 100: - print("Please enter a number between 1 and 100!") - attempts -= 1 # Don't count invalid attempts - continue - - # Check guess - if guess == secret_number: - print(f"\n🎉 CONGRATULATIONS! You guessed it in {attempts} attempts!") - print(f"The number was {secret_number}.") - - # Performance feedback - if attempts <= 3: - print("Amazing! You're a guessing master!") - elif attempts <= 6: - print("Great job! You did well!") - else: - print("Good job! You got it!") - return - - elif guess < secret_number: - print(f"Too low! Try a higher number.") - if remaining == 1: - print(f"You have {remaining} attempt left!") - else: - print(f"You have {remaining} attempts left!") - else: - print(f"Too high! Try a lower number.") - if remaining == 1: - print(f"You have {remaining} attempt left!") - else: - print(f"You have {remaining} attempts left!") - - print() # Add spacing - - # Game over - ran out of attempts - print(f"\n😔 GAME OVER! You ran out of attempts!") - print(f"The number was {secret_number}.") - print("Better luck next time!") - -def main(): - """Main game loop""" - while True: - play_number_guessing_game() - - # Ask to play again - while True: - play_again = input("\nDo you want to play again? (y/n): ").lower() - if play_again in ["y", "n"]: - break - print("Please enter 'y' or 'n'!") - - if play_again == "n": - print("\nThanks for playing Number Guessing Game!") - print("Goodbye!") - break - - print("\n" + "=" * 50) - print(" NEW GAME") - print("=" * 50) - -if __name__ == "__main__": - main() -``` - -### Day 21: Review and Refinement - -#### Level 1 Week 3 Summary -```java -# Week 3 Review - Control Flow and Decision Making - -def review_concepts(): - """Review all concepts from Week 3""" - - print("WEEK 3 REVIEW: CONTROL FLOW") - print("=" * 40) - - # 1. Basic if statement - age = 20 - if age >= 18: - print("✓ Basic if statement works") - - # 2. If-else statement - score = 75 - if score >= 60: - result = "Pass" - else: - result = "Fail" - print(f"✓ If-else: {result}") - - # 3. If-elif-else chain - grade = 85 - if grade >= 90: - letter = "A" - elif grade >= 80: - letter = "B" - elif grade >= 70: - letter = "C" - else: - letter = "F" - print(f"✓ If-elif-else: Grade {grade} = {letter}") - - # 4. Logical operators - has_ticket = True - has_id = True - can_enter = has_ticket and has_id - print(f"✓ Logical AND: Can enter = {can_enter}") - - # 5. Nested conditions - weather = "sunny" - temperature = 75 - if weather == "sunny": - if temperature > 70: - activity = "Beach" - else: - activity = "Park" - else: - activity = "Museum" - print(f"✓ Nested conditions: Activity = {activity}") - - print("=" * 40) - print("All concepts reviewed successfully!") - -# Run the review -review_concepts() -``` - -## 🎯 Week 4: Loops and Iteration - -### Day 22: While Loops - -#### Basic While Loop -```java -# Simple counting -count = 1 -while count <= 5: - print(f"Count: {count}") - count += 1 # Important: increment to avoid infinite loop! - -print("Loop finished!") -``` - -#### While Loop with User Input -```java -def password_checker(): - """Password validation with while loop""" - correct_password = "java123" - attempts = 0 - max_attempts = 3 - - while attempts < max_attempts: - password = input("Enter password: ") - attempts += 1 - - if password == correct_password: - print("Access granted!") - return - else: - remaining = max_attempts - attempts - if remaining > 0: - print(f"Wrong password! {remaining} attempts left.") - else: - print("Too many failed attempts!") - - print("Access denied!") - -# password_checker() # Uncomment to test -``` - -#### While Loop for Input Validation -```java -def get_positive_number(): - """Get a positive number from user""" - while True: - try: - number = float(input("Enter a positive number: ")) - if number > 0: - return number - else: - print("Please enter a number greater than 0!") - except ValueError: - print("Please enter a valid number!") - -# Test -# positive_num = get_positive_number() -# print(f"You entered: {positive_num}") -``` - -#### While Loop with Flags -```java -def simple_calculator(): - """Calculator with while loop and flags""" - running = True - - while running: - print("\nSimple Calculator") - print("1. Add") - print("2. Subtract") - print("3. Multiply") - print("4. Divide") - print("5. Exit") - - choice = input("Choose operation (1-5): ") - - if choice == "5": - running = False - print("Exiting calculator...") - continue - - if choice in ["1", "2", "3", "4"]: - try: - num1 = float(input("Enter first number: ")) - num2 = float(input("Enter second number: ")) - - if choice == "1": - result = num1 + num2 - elif choice == "2": - result = num1 - num2 - elif choice == "3": - result = num1 * num2 - elif choice == "4": - if num2 != 0: - result = num1 / num2 - else: - print("Cannot divide by zero!") - continue - - print(f"Result: {result}") - - except ValueError: - print("Please enter valid numbers!") - else: - print("Invalid choice! Please try again.") - -# simple_calculator() # Uncomment to test -``` - -### Day 23: For Loops - -#### Basic For Loop -```java -# Loop through a range -for i in range(5): - print(f"Iteration {i}") - -print("\nLooping with start and end:") -for i in range(2, 7): - print(f"Number: {i}") - -print("\nLooping with step:") -for i in range(0, 10, 2): - print(f"Even number: {i}") -``` - -#### Loop Through Lists -```java -fruits = ["apple", "banana", "orange", "grape"] - -print("Loop through list:") -for fruit in fruits: - print(f"I like {fruit}") - -print("\nLoop with index:") -for index, fruit in enumerate(fruits): - print(f"{index + 1}. {fruit}") +} ``` -#### Loop Through Strings -```java -word = "Java" +| Part | Meaning | +|------|---------| +| `public` | Accessible from anywhere | +| `class MyProgram` | Defines a class named MyProgram | +| `static` | Belongs to the class, not an object | +| `void` | Returns nothing | +| `String[] args` | Command-line arguments | -print("Loop through string:") -for letter in word: - print(f"Letter: {letter}") +### 2. Statements and Semicolons -print("\nLoop with position:") -for position, letter in enumerate(word): - print(f"Position {position}: {letter}") -``` +Every statement in Java **must end with a semicolon** `;`. Forgetting it is the most common beginner mistake. -#### Loop Through Dictionaries ```java -person = { - "name": "Alice", - "age": 25, - "city": "New York", - "job": "Developer" -} - -print("Loop through dictionary keys:") -for key in person: - print(f"Key: {key}") - -print("\nLoop through dictionary values:") -for value in person.values(): - print(f"Value: {value}") - -print("\nLoop through dictionary items:") -for key, value in person.items(): - print(f"{key}: {value}") +System.out.println("This works"); // ✅ correct +System.out.println("This fails") // ❌ missing semicolon ``` -### Day 24: Loop Control (Break and Continue) +### 3. Comments -#### Break Statement ```java -# Find first even number in a range -for i in range(1, 20): - if i % 2 == 0: - print(f"First even number found: {i}") - break # Exit the loop - -print("Loop ended with break") - -# Search in list -numbers = [3, 7, 2, 9, 5, 8] -target = 9 - -for index, num in enumerate(numbers): - if num == target: - print(f"Found {target} at index {index}") - break -else: - print(f"{target} not found in the list") -``` +// Single-line comment -#### Continue Statement -```java -# Skip odd numbers -print("Even numbers from 1 to 10:") -for i in range(1, 11): - if i % 2 != 0: - continue # Skip odd numbers - print(i) +/* + Multi-line comment + spans multiple lines +*/ -# Filter list -words = ["apple", "", "banana", "orange", "", "grape"] -print("\nNon-empty words:") -for word in words: - if not word: # Empty string is falsy - continue # Skip empty strings - print(word) +/** + * Javadoc comment — used to generate documentation + * @param name the name to greet + */ ``` -#### Break and Continue Together -```java -def find_prime_numbers(limit): - """Find prime numbers up to limit""" - print(f"Prime numbers up to {limit}:") - - for num in range(2, limit + 1): - if num == 2: - print(num) - continue - - # Check if num is divisible by any number other than 1 and itself - is_prime = True - for i in range(2, int(num ** 0.5) + 1): - if num % i == 0: - is_prime = False - break # Not prime, check next number - - if is_prime: - print(num) - -# Test -find_prime_numbers(20) -``` +### 4. Case Sensitivity -### Day 25: Nested Loops +Java is **case-sensitive**. `Main`, `main`, and `MAIN` are three different things. -#### Basic Nested Loops ```java -# Multiplication table -print("Multiplication Table:") -for i in range(1, 6): - for j in range(1, 6): - product = i * j - print(f"{i} × {j} = {product}") - print("-" * 20) - -# Pattern printing -print("\nTriangle Pattern:") -for i in range(1, 6): - for j in range(i): - print("*", end=" ") - print() +String name = "Alice"; // ✅ +String Name = "Bob"; // This is a DIFFERENT variable ``` -#### Nested Loops with Lists -```java -# Find pairs that sum to target -numbers = [2, 4, 6, 8, 10, 12] -target = 14 - -print(f"Pairs that sum to {target}:") -for i in range(len(numbers)): - for j in range(i + 1, len(numbers)): # Start from i+1 to avoid duplicates - if numbers[i] + numbers[j] == target: - print(f"{numbers[i]} + {numbers[j]} = {target}") - -# Matrix operations -matrix = [ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9] -] +### 5. Printing Output -print("\nMatrix elements:") -for row in matrix: - for element in row: - print(element, end=" ") - print() # New line after each row -``` - -#### Practical Example: Shopping Cart ```java -def display_shopping_cart(): - """Display shopping cart with nested loops""" - - products = [ - {"name": "Apple", "price": 0.99, "quantity": 3}, - {"name": "Banana", "price": 0.59, "quantity": 5}, - {"name": "Orange", "price": 1.29, "quantity": 2} - ] - - print("SHOPPING CART") - print("=" * 40) - print(f"{'Item':<15} {'Price':<10} {'Qty':<5} {'Total':<10}") - print("-" * 40) - - grand_total = 0 - - for product in products: - item_total = product["price"] * product["quantity"] - grand_total += item_total - - print(f"{product['name']:<15} ${product['price']:<9.2f} {product['quantity']:<5} ${item_total:<9.2f}") - - print("-" * 40) - print(f"{'GRAND TOTAL':<30} ${grand_total:<9.2f}") - -# display_shopping_cart() # Uncomment to test +System.out.println("Prints with newline at end"); +System.out.print("Prints WITHOUT newline"); +System.out.printf("Formatted: name=%s, age=%d%n", "Alice", 25); ``` -### Day 26: List Comprehensions +## Full Example -#### Basic List Comprehension ```java -# Traditional way -squares = [] -for i in range(1, 6): - squares.append(i ** 2) -print(f"Traditional: {squares}") +public class JavaBasics { + public static void main(String[] args) { + // Print a greeting + System.out.println("=== Java Basics Demo ==="); -# List comprehension way -squares_comp = [i ** 2 for i in range(1, 6)] -print(f"Comprehension: {squares_comp}") + // Variables + int year = 2024; + String language = "Java"; -# With condition -even_squares = [i ** 2 for i in range(1, 11) if i % 2 == 0] -print(f"Even squares: {even_squares}") -``` - -#### Advanced List Comprehensions -```java -# String manipulation -words = ["apple", "banana", "orange", "grape"] -uppercase_words = [word.upper() for word in words] -print(f"Uppercase: {uppercase_words}") - -# Length filtering -long_words = [word for word in words if len(word) > 5] -print(f"Long words: {long_words}") - -# Nested operations -numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -processed = [x ** 2 for x in numbers if x % 2 == 0] -print(f"Processed: {processed}") - -# Dictionary comprehension -word_lengths = {word: len(word) for word in words} -print(f"Word lengths: {word_lengths}") -``` - -#### Practical Examples -```java -# Filter and transform data -students = [ - {"name": "Alice", "score": 85, "grade": "B"}, - {"name": "Bob", "score": 92, "grade": "A"}, - {"name": "Charlie", "score": 78, "grade": "C"}, - {"name": "Diana", "score": 95, "grade": "A"} -] + // Formatted output + System.out.printf("%s was created in 1995. Current year: %d%n", language, year); -# Get A students -a_students = [student["name"] for student in students if student["grade"] == "A"] -print(f"A students: {a_students}") - -# Create summary -student_summary = [ - { - "name": student["name"], - "status": "Excellent" if student["score"] >= 90 else "Good" if student["score"] >= 80 else "Needs Improvement" + // Math + int a = 10, b = 3; + System.out.println("Sum: " + (a + b)); + System.out.println("Division: " + (a / b)); // Integer division = 3 + System.out.println("Remainder: " + (a % b)); // 1 + System.out.println("Float div: " + (a / (double) b)); // 3.333... } - for student in students -] -print(f"Summary: {student_summary}") -``` - -### Day 27: Practice Exercises - -#### Exercise 1: Factorial Calculator -```java -def factorial_with_while(n): - """Calculate factorial using while loop""" - if n < 0: - return "Factorial not defined for negative numbers" - elif n == 0: - return 1 - - result = 1 - i = n - while i > 0: - result *= i - i -= 1 - return result - -def factorial_with_for(n): - """Calculate factorial using for loop""" - if n < 0: - return "Factorial not defined for negative numbers" - elif n == 0: - return 1 - - result = 1 - for i in range(1, n + 1): - result *= i - return result - -# Test -for num in range(0, 6): - print(f"{num}! = {factorial_with_for(num)}") +} ``` -#### Exercise 2: Fibonacci Sequence -```java -def fibonacci_sequence(n): - """Generate Fibonacci sequence""" - if n <= 0: - return [] - elif n == 1: - return [0] - - sequence = [0, 1] - - while len(sequence) < n: - next_num = sequence[-1] + sequence[-2] - sequence.append(next_num) - - return sequence - -def fibonacci_with_comprehension(n): - """Generate Fibonacci using list comprehension (more complex)""" - if n <= 0: - return [] - - fib = [0, 1] - [fib.append(fib[-1] + fib[-2]) for _ in range(2, n)] - return fib[:n] - -# Test -print(fibonacci_sequence(10)) -print(fibonacci_with_comprehension(10)) +**Expected output:** ``` - -### Day 28: Level 1 Project - Pattern Generator - -#### Complete Pattern Generator Project -```java -def pattern_generator(): - """Interactive pattern generator using loops""" - - print("=" * 50) - print(" PATTERN GENERATOR") - print("=" * 50) - print("Create various patterns using loops!") - print() - - while True: - print("Pattern Menu:") - print("1. Right Triangle") - print("2. Inverted Triangle") - print("3. Pyramid") - print("4. Diamond") - print("5. Number Triangle") - print("6. Floyd's Triangle") - print("7. Exit") - - choice = input("Choose pattern (1-7): ") - - if choice == "7": - print("Goodbye!") - break - - if choice not in ["1", "2", "3", "4", "5", "6"]: - print("Invalid choice! Please try again.") - print() - continue - - try: - size = int(input("Enter pattern size (1-20): ")) - if size < 1 or size > 20: - print("Please enter a size between 1 and 20!") - continue - except ValueError: - print("Please enter a valid number!") - continue - - print("\n" + "-" * 30) - - if choice == "1": - right_triangle(size) - elif choice == "2": - inverted_triangle(size) - elif choice == "3": - pyramid(size) - elif choice == "4": - diamond(size) - elif choice == "5": - number_triangle(size) - elif choice == "6": - floyd_triangle(size) - - print("-" * 30) - print() - -def right_triangle(size): - """Generate right triangle pattern""" - print("RIGHT TRIANGLE") - for i in range(1, size + 1): - print("*" * i) - -def inverted_triangle(size): - """Generate inverted triangle pattern""" - print("INVERTED TRIANGLE") - for i in range(size, 0, -1): - print("*" * i) - -def pyramid(size): - """Generate pyramid pattern""" - print("PYRAMID") - for i in range(1, size + 1): - spaces = " " * (size - i) - stars = "*" * (2 * i - 1) - print(spaces + stars) - -def diamond(size): - """Generate diamond pattern""" - print("DIAMOND") - # Upper half - for i in range(1, size + 1): - spaces = " " * (size - i) - stars = "*" * (2 * i - 1) - print(spaces + stars) - - # Lower half - for i in range(size - 1, 0, -1): - spaces = " " * (size - i) - stars = "*" * (2 * i - 1) - print(spaces + stars) - -def number_triangle(size): - """Generate number triangle pattern""" - print("NUMBER TRIANGLE") - for i in range(1, size + 1): - for j in range(1, i + 1): - print(j, end=" ") - print() - -def floyd_triangle(size): - """Generate Floyd's triangle pattern""" - print("FLOYD'S TRIANGLE") - num = 1 - for i in range(1, size + 1): - for j in range(i): - print(num, end=" ") - num += 1 - print() - -if __name__ == "__main__": - pattern_generator() +=== Java Basics Demo === +Java was created in 1995. Current year: 2024 +Sum: 13 +Division: 3 +Remainder: 1 +Float div: 3.3333333333333335 ``` -## 🎉 Level 1 Completion Checklist - -### ✅ What You've Mastered -- [ ] **Control Flow**: If/Else statements, logical operators -- [ ] **Decision Making**: Nested conditions, complex logic -- [ ] **Loops**: While loops, for loops, nested loops -- [ ] **Loop Control**: Break, continue statements -- [ ] **List Comprehensions**: Advanced list operations -- [ ] **Pattern Generation**: Creating visual patterns -- [ ] **Problem Solving**: Number guessing game, pattern generator -- [ ] **Code Organization**: Functions, modular design +## Exercise -### 🚀 Ready for Level 2? -You're ready for Level 2: Intermediate Programming if you can: -- Write complex conditional logic -- Use loops effectively -- Create list comprehensions -- Build interactive applications -- Debug and fix errors independently +1. Create a file `AboutMe.java` with a class named `AboutMe`. +2. In `main`, print your name, age, and favourite programming concept on separate lines. +3. Use `printf` to format at least one line. +4. Add a comment explaining what each `System.out` call does. -### 📝 Level 1 Certificate -You've successfully completed: -- **4 weeks** of intensive Java programming -- **2 complete projects** (Number Guessing Game + Pattern Generator) -- **Core programming concepts** (control flow, loops, functions) -- **Problem-solving skills** (algorithms, patterns, user interaction) +## Checkpoint -**Congratulations! 🎉 You're now an intermediate Java programmer!** +You are ready for the next lesson when you can: +- Explain why the filename must match the class name +- Fix a "missing semicolon" error on sight +- Use both `println` and `printf` correctly --- - -**Next Level:** [Level 2: Intermediate Programming](level2_intermediate_programming.md) - -**Keep practicing:** The more you code, the better you'll become! +**Next:** Lesson 03 — Hello World and Running Your First Program diff --git a/data/Java/data/01-beginner/04-variables-and-types.md b/data/Java/data/01-beginner/04-variables-and-types.md index 6e95d80e..7fd0b06e 100644 --- a/data/Java/data/01-beginner/04-variables-and-types.md +++ b/data/Java/data/01-beginner/04-variables-and-types.md @@ -2,40 +2,142 @@ **Module 01 · Beginner · Lesson 04 of 10** +## Learning Objectives -## Learning objectives - -- Understand **variables and data types** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Declare and initialize variables in Java +- Know all 8 primitive types and when to use each +- Understand the difference between primitives and `String` ## Overview -Variables and Data Types is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. +Java is **statically typed** — every variable must have a declared type, and that type cannot change. The compiler checks types at compile time, catching many bugs before the program even runs. + +## Key Concepts + +### 1. The 8 Primitive Types + +| Type | Size | Range / Use | Example | +|------|------|-------------|---------| +| `byte` | 8-bit | -128 to 127 | `byte b = 100;` | +| `short` | 16-bit | -32,768 to 32,767 | `short s = 1000;` | +| `int` | 32-bit | ~-2 billion to 2 billion | `int age = 25;` | +| `long` | 64-bit | Very large integers | `long pop = 8_000_000_000L;` | +| `float` | 32-bit | Decimal, ~7 digits precision | `float f = 3.14f;` | +| `double` | 64-bit | Decimal, ~15 digits precision | `double pi = 3.14159;` | +| `char` | 16-bit | Single Unicode character | `char grade = 'A';` | +| `boolean` | 1-bit | `true` or `false` | `boolean isJavaFun = true;` | + +> **Rule of thumb:** Use `int` for whole numbers, `double` for decimals, `boolean` for yes/no, `char` for single characters. + +### 2. Declaring and Initialising Variables + +```java +// Declare then assign +int score; +score = 95; + +// Declare and assign in one line (preferred) +int lives = 3; + +// Multiple variables of the same type +int x = 10, y = 20, z = 30; +``` + +### 3. The `long` and `float` Suffixes -## Key concepts +```java +long bigNumber = 9_876_543_210L; // Must add L for long literals +float temperature = 36.6f; // Must add f for float literals +double price = 19.99; // No suffix needed for double +``` -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes +### 4. `String` — Not a Primitive -## Example +`String` is a class, not a primitive. It holds text and has many useful methods. ```java -// Variables and Data Types — practice sketch -// declare and print sample variables +String name = "Alice"; +String greeting = "Hello, " + name + "!"; // Concatenation with + +int length = name.length(); // 5 +String upper = name.toUpperCase(); // "ALICE" +boolean starts = name.startsWith("Al"); // true +``` + +### 5. `var` (Java 10+) — Type Inference + +```java +var count = 42; // compiler infers int +var message = "Hi"; // compiler infers String +var pi = 3.14; // compiler infers double +``` + +Use `var` only when the type is obvious from context. + +### 6. Constants with `final` + +```java +final double TAX_RATE = 0.18; // Cannot be changed after assignment +// TAX_RATE = 0.20; ← compile error! +``` + +## Full Example + +```java +public class VariablesDemo { + public static void main(String[] args) { + // Primitive types + int age = 20; + double gpa = 3.85; + char grade = 'A'; + boolean enrolled = true; + + // String + String name = "Zara"; + + // Constant + final int MAX_CREDITS = 20; + + // Output + System.out.println("Student: " + name); + System.out.println("Age: " + age); + System.out.printf("GPA: %.2f%n", gpa); + System.out.println("Grade: " + grade); + System.out.println("Enrolled: " + enrolled); + System.out.println("Max credits allowed: " + MAX_CREDITS); + + // Type limits + int maxInt = Integer.MAX_VALUE; + System.out.println("Largest int: " + maxInt); + System.out.println("Largest int + 1 overflows: " + (maxInt + 1)); + } +} +``` + +**Expected output:** +``` +Student: Zara +Age: 20 +GPA: 3.85 +Grade: A +Enrolled: true +Max credits allowed: 20 +Largest int: 2147483647 +Largest int + 1 overflows: -2147483648 ``` ## Exercise -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). +1. Declare variables to represent a product: name (String), price (double), quantity (int), inStock (boolean). +2. Calculate the total cost (`price * quantity`) and store it in a `double`. +3. Print a receipt-style summary using `printf`. +4. Make the tax rate (18%) a `final` constant and include tax in the total. ## Checkpoint -You are ready for the next lesson when you can solve the exercise without copying the example. +You are ready for the next lesson when you can: +- Name all 8 primitive types from memory +- Explain why `long` needs `L` and `float` needs `f` +- Describe the difference between `int` and `Integer` --- - -**Next:** Continue to lesson 05 in this module. +**Next:** Lesson 05 — Control Flow and Loops diff --git a/data/Java/data/01-beginner/05-control-flow-and-loops.md b/data/Java/data/01-beginner/05-control-flow-and-loops.md index 047e0b96..31ea11df 100644 --- a/data/Java/data/01-beginner/05-control-flow-and-loops.md +++ b/data/Java/data/01-beginner/05-control-flow-and-loops.md @@ -2,211 +2,186 @@ **Module 01 · Beginner · Lesson 05 of 10** -# Java Conditional Statements +## Learning Objectives -## What are Conditional Statements? -Conditional statements allow your program to **make decisions** — execute different code depending on whether a condition is `True` or `False`. +- Use `if`, `else if`, `else`, and `switch` to make decisions +- Write `for`, `while`, and `do-while` loops +- Use `break` and `continue` correctly ---- +## Overview -## 1. `if` Statement +Programs rarely run top-to-bottom without decisions or repetition. **Control flow** statements let your program choose different paths, and **loops** let it repeat actions without copy-pasting code. -Executes a block of code **only if** the condition is True. +## Key Concepts -```java -if condition: - # code runs only when condition is True -``` +### 1. if / else if / else -### Example ```java -age = 20 -if age >= 18: - print("You are an adult.") +int score = 78; + +if (score >= 90) { + System.out.println("A"); +} else if (score >= 80) { + System.out.println("B"); +} else if (score >= 70) { + System.out.println("C"); +} else { + System.out.println("F"); +} +// Output: C ``` ---- - -## 2. `if-else` Statement - -Executes one block if True, **another block if False**. +### 2. Ternary Operator (short if-else) ```java -if condition: - # runs when True -else: - # runs when False +int age = 20; +String status = (age >= 18) ? "Adult" : "Minor"; +System.out.println(status); // Adult ``` -### Example +### 3. switch Statement + ```java -age = 15 -if age >= 18: - print("Adult") -else: - print("Minor") +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; + default: System.out.println("Other day"); +} +// Output: Wednesday ``` ---- - -## 3. `if-elif-else` (Multiple Conditions) +> Always add `break` at the end of each case — without it, Java falls through to the next case! -Tests multiple conditions in sequence — the **first True** block runs. +### 4. switch Expression (Java 14+) ```java -if condition1: - # runs if condition1 is True -elif condition2: - # runs if condition2 is True -elif condition3: - # runs if condition3 is True -else: - # runs if none are True +String dayName = switch (day) { + case 1 -> "Monday"; + case 2 -> "Tuesday"; + case 3 -> "Wednesday"; + default -> "Other"; +}; ``` -### Example: Grade Classification +### 5. for Loop + ```java -marks = 78 - -if marks >= 90: - grade = "A" -elif marks >= 80: - grade = "B" -elif marks >= 70: - grade = "C" -elif marks >= 60: - grade = "D" -else: - grade = "F" - -print(f"Grade: {grade}") +// Count 1 to 5 +for (int i = 1; i <= 5; i++) { + System.out.print(i + " "); +} +// Output: 1 2 3 4 5 + +// Count down +for (int i = 5; i >= 1; i--) { + System.out.print(i + " "); +} +// Output: 5 4 3 2 1 ``` ---- - -## 4. Nested `if` Statements - -An `if` inside another `if`. +### 6. while Loop ```java -age = 25 -has_id = True - -if age >= 18: - if has_id: - print("Entry allowed") - else: - print("Need ID") -else: - print("Too young") +int n = 1; +while (n <= 5) { + System.out.print(n + " "); + n++; +} +// Output: 1 2 3 4 5 ``` ---- - -## 5. Ternary (One-Line) `if` +### 7. do-while Loop -A compact way to write simple `if-else`. +The body runs **at least once**, then checks the condition. ```java -value = true_value if condition else false_value +int n = 10; +do { + System.out.println("Runs once even though n > 5"); + n++; +} while (n <= 5); ``` -### Example +### 8. break and continue + ```java -age = 20 -status = "Adult" if age >= 18 else "Minor" -print(status) - -# Find max of two numbers -a, b = 10, 20 -maximum = a if a > b else b -print(f"Max: {maximum}") +// break exits the loop entirely +for (int i = 1; i <= 10; i++) { + if (i == 6) break; + System.out.print(i + " "); +} +// Output: 1 2 3 4 5 + +// continue skips to the next iteration +for (int i = 1; i <= 10; i++) { + if (i % 2 == 0) continue; // skip even numbers + System.out.print(i + " "); +} +// Output: 1 3 5 7 9 ``` ---- - -## 6. `match-case` Statement (Java 3.10+) - -Similar to switch-case in other languages. +## Full Example ```java -match variable: - case value1: - # code - case value2: - # code - case _: - # default (like else) +public class ControlFlowDemo { + public static void main(String[] args) { + // Multiplication table for 7 + System.out.println("--- 7 Times Table ---"); + for (int i = 1; i <= 10; i++) { + System.out.printf("7 x %2d = %d%n", i, 7 * i); + } + + // Find first number divisible by both 3 and 7 + System.out.println("\n--- First number divisible by 3 AND 7 ---"); + int n = 1; + while (true) { + if (n % 3 == 0 && n % 7 == 0) { + System.out.println(n); + break; + } + n++; + } + + // Print only odd numbers 1-20 + System.out.println("\n--- Odd numbers 1-20 ---"); + for (int i = 1; i <= 20; i++) { + if (i % 2 == 0) continue; + System.out.print(i + " "); + } + System.out.println(); + } +} ``` -### Example -```java -day = "Monday" - -match day: - case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday": - print("Weekday") - case "Saturday" | "Sunday": - print("Weekend") - case _: - print("Invalid day") +**Expected output:** ``` +--- 7 Times Table --- +7 x 1 = 7 +7 x 2 = 14 +... +7 x 10 = 70 ---- - -## Comparison Operators - -| Operator | Meaning | Example | -|----------|-----------------------|-----------------| -| `==` | Equal to | `5 == 5` → True | -| `!=` | Not equal to | `5 != 3` → True | -| `>` | Greater than | `5 > 3` → True | -| `<` | Less than | `3 < 5` → True | -| `>=` | Greater than or equal | `5 >= 5` → True | -| `<=` | Less than or equal | `3 <= 5` → True | - ---- +--- First number divisible by 3 AND 7 --- +21 -## Logical Operators +--- Odd numbers 1-20 --- +1 3 5 7 9 11 13 15 17 19 +``` -| Operator | Meaning | Example | -|----------|---------------------------|-------------------------------| -| `and` | Both must be True | `5 > 3 and 10 > 7` → True | -| `or` | At least one must be True | `5 > 10 or 3 > 1` → True | -| `not` | Reverses the condition | `not (5 > 3)` → False | +## Exercise ---- +1. Print a triangle of stars using nested loops (5 rows). +2. Write a loop that sums all integers from 1 to 100 and prints the result. +3. Use a `switch` to print the name of a month given its number (1-12). -## Special Conditions +## Checkpoint -```java -# Check if value is None -x = None -if x is None: - print("No value") - -# Check membership -fruits = ["apple", "banana"] -if "apple" in fruits: - print("Apple found!") - -# Check empty string/list -name = "" -if not name: - print("Name is empty") -``` +You are ready for the next lesson when you can: +- Choose correctly between `for`, `while`, and `do-while` +- Explain what happens if you forget `break` in a `switch` +- Write a nested loop without an infinite loop --- - -## Summary - -| Statement | Use Case | -|-----------------|-----------------------------------------| -| `if` | One condition | -| `if-else` | Two paths (True/False) | -| `if-elif-else` | Multiple conditions | -| Nested `if` | Condition within condition | -| Ternary | One-line simple condition | -| `match-case` | Match one value against many patterns | - -> 💡 **Key Tip**: Java uses **indentation** (spaces/tabs) to define code blocks — not curly braces `{}`. \ No newline at end of file +**Next:** Lesson 06 — Methods diff --git a/data/Java/data/01-beginner/06-methods-basics.md b/data/Java/data/01-beginner/06-methods-basics.md index d7df01fd..cba37b06 100644 --- a/data/Java/data/01-beginner/06-methods-basics.md +++ b/data/Java/data/01-beginner/06-methods-basics.md @@ -2,298 +2,157 @@ **Module 01 · Beginner · Lesson 06 of 10** -# Java Functions +## Learning Objectives -## What are Functions? -A **function** is a reusable block of code that performs a specific task. Instead of writing the same code multiple times, you define it once and call it whenever needed. +- Define and call methods with parameters and return values +- Understand method overloading +- Know the difference between `void` and non-void methods -### Benefits -- Reusability — write once, use many times -- Readability — code is organized and easier to understand -- Maintainability — fix a bug in one place +## Overview ---- +A **method** is a named block of code that performs a specific task. Instead of writing the same logic repeatedly, you write it once as a method and call it whenever needed. Methods make code **reusable**, **readable**, and **easier to test**. -## 1. Defining and Calling a Function +## Key Concepts -```java -def function_name(parameters): - """Docstring — describes the function""" - # code - return value # optional -``` +### 1. Method Anatomy -### Example ```java -def greet(): - print("Hello, World!") - -greet() # Calling the function -greet() # Can call multiple times +// accessModifier returnType methodName(parameterList) { body } +public static int add(int a, int b) { + return a + b; +} ``` ---- +| Part | Meaning | +|------|---------| +| `public` | Callable from anywhere | +| `static` | Can be called without creating an object | +| `int` | Return type (use `void` if nothing is returned) | +| `add` | Method name (use camelCase) | +| `int a, int b` | Parameters (inputs) | +| `return a + b` | Return value | -## 2. Function with Parameters +### 2. void Methods (no return value) ```java -def greet(name): - print(f"Hello, {name}!") +public static void greet(String name) { + System.out.println("Hello, " + name + "!"); +} -greet("Alice") -greet("Bob") +// Calling it: +greet("Alice"); // Hello, Alice! ``` ---- - -## 3. Function with Return Value +### 3. Methods with Return Values ```java -def add(a, b): - return a + b +public static double circleArea(double radius) { + return Math.PI * radius * radius; +} -result = add(5, 3) -print(result) # 8 +// Calling it: +double area = circleArea(5.0); +System.out.printf("Area: %.2f%n", area); // Area: 78.54 ``` ---- - -## 4. Types of Function Arguments - -### 4.1 — Positional Arguments -Arguments matched by position. -```java -def power(base, exponent): - return base ** exponent - -print(power(2, 10)) # 1024 -``` - -### 4.2 — Keyword Arguments -Arguments matched by name (order doesn't matter). -```java -def describe_person(name, age, city): - print(f"{name}, {age}, from {city}") - -describe_person(age=25, city="Paris", name="Alice") -``` - -### 4.3 — Default Arguments -Parameters with default values (used if not provided). -```java -def greet(name, greeting="Hello"): - print(f"{greeting}, {name}!") - -greet("Alice") # Hello, Alice! -greet("Bob", "Hi there") # Hi there, Bob! -``` - -### 4.4 — `*args` — Variable Positional Arguments -Accept any number of positional arguments (stored as a tuple). -```java -def total(*numbers): - return sum(numbers) - -print(total(1, 2, 3)) # 6 -print(total(10, 20, 30, 40)) # 100 -``` - -### 4.5 — `**kwargs` — Variable Keyword Arguments -Accept any number of keyword arguments (stored as a dict). -```java -def show_info(**details): - for key, value in details.items(): - print(f"{key}: {value}") - -show_info(name="Alice", age=25, job="Developer") -``` - -### 4.6 — Combining All Types -```java -def mixed(a, b, *args, key="default", **kwargs): - print(f"a={a}, b={b}") - print(f"args={args}") - print(f"key={key}") - print(f"kwargs={kwargs}") - -mixed(1, 2, 3, 4, key="hello", x=10, y=20) -``` - ---- - -## 5. Return Values - -### Return a Single Value -```java -def square(n): - return n * n +### 4. Method Overloading -print(square(7)) # 49 -``` +Multiple methods can share the same name if their **parameter lists differ** (different types or number of parameters). -### Return Multiple Values (as tuple) ```java -def min_max(numbers): - return min(numbers), max(numbers) +public static int multiply(int a, int b) { + return a * b; +} -low, high = min_max([3, 1, 7, 4, 9, 2]) -print(f"Min: {low}, Max: {high}") -``` +public static double multiply(double a, double b) { + return a * b; +} -### Return Nothing (None) -```java -def say_hi(): - print("Hi!") - # no return → returns None implicitly +public static int multiply(int a, int b, int c) { + return a * b * c; +} -result = say_hi() -print(result) # None +// Java picks the right one automatically: +multiply(3, 4); // calls int version → 12 +multiply(2.5, 4.0); // calls double version → 10.0 +multiply(2, 3, 4); // calls 3-parameter version → 24 ``` ---- +### 5. Parameters vs Arguments -## 6. Lambda Functions (Anonymous Functions) +- **Parameter**: variable in the method definition (`int a`) +- **Argument**: actual value passed when calling (`add(5, 3)` — here `5` and `3` are arguments) -Short, one-line functions without a name. +### 6. Scope -```java -lambda parameters: expression -``` +Variables declared inside a method only exist inside that method. -### Examples ```java -square = lambda x: x ** 2 -print(square(5)) # 25 - -add = lambda a, b: a + b -print(add(3, 4)) # 7 - -# Common use: with sorted(), map(), filter() -numbers = [5, 2, 9, 1, 7] -sorted_nums = sorted(numbers, key=lambda x: x) -print(sorted_nums) # [1, 2, 5, 7, 9] - -doubled = list(map(lambda x: x * 2, numbers)) -print(doubled) # [10, 4, 18, 2, 14] - -evens = list(filter(lambda x: x % 2 == 0, numbers)) -print(evens) # [2] +public static void example() { + int local = 10; // only visible inside example() +} +// System.out.println(local); ← compile error! local doesn't exist here ``` ---- - -## 7. Recursive Functions - -A function that **calls itself**. +## Full Example ```java -def factorial(n): - if n == 0 or n == 1: # base case - return 1 - return n * factorial(n - 1) # recursive call +public class MethodsDemo { -print(factorial(5)) # 120 -``` + public static int max(int a, int b) { + return (a > b) ? a : b; + } -### Fibonacci with Recursion -```java -def fibonacci(n): - if n <= 1: - return n - return fibonacci(n - 1) + fibonacci(n - 2) + public static boolean isPrime(int n) { + if (n < 2) return false; + for (int i = 2; i <= Math.sqrt(n); i++) { + if (n % i == 0) return false; + } + return true; + } -for i in range(8): - print(fibonacci(i), end=" ") # 0 1 1 2 3 5 8 13 -``` + public static String repeat(String text, int times) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < times; i++) { + sb.append(text); + } + return sb.toString(); + } ---- + public static void main(String[] args) { + System.out.println("Max of 17 and 42: " + max(17, 42)); -## 8. Scope — Local vs Global Variables + System.out.println("Primes up to 30:"); + for (int i = 2; i <= 30; i++) { + if (isPrime(i)) System.out.print(i + " "); + } + System.out.println(); -```java -x = 10 # global variable - -def my_func(): - y = 20 # local variable — only exists inside function - print(f"Inside: x={x}, y={y}") - -my_func() -print(f"Outside: x={x}") -# print(y) # ERROR — y doesn't exist here + System.out.println(repeat("Java! ", 3)); + } +} ``` -### `global` Keyword -```java -counter = 0 - -def increment(): - global counter # access the global variable - counter += 1 - -increment() -increment() -print(counter) # 2 +**Expected output:** ``` - ---- - -## 9. Docstrings - -Document your functions with docstrings. - -```java -def calculate_area(length, width): - """ - Calculate the area of a rectangle. - - Args: - length (float): The length of the rectangle. - width (float): The width of the rectangle. - - Returns: - float: The area. - """ - return length * width - -help(calculate_area) # shows the docstring +Max of 17 and 42: 42 +Primes up to 30: +2 3 5 7 11 13 17 19 23 29 +Java! Java! Java! ``` ---- +## Exercise -## 10. Higher-Order Functions +1. Write a method `factorial(int n)` that returns `n!` (e.g., `factorial(5)` = 120). +2. Write an overloaded `power` method: one taking `int` base and exponent, another taking `double`. +3. Write a method `reverseString(String s)` that returns the string reversed. -Functions that accept other functions as arguments. +## Checkpoint -```java -# map() — apply function to each element -numbers = [1, 2, 3, 4, 5] -squares = list(map(lambda x: x**2, numbers)) -print(squares) # [1, 4, 9, 16, 25] - -# filter() — keep elements where function returns True -evens = list(filter(lambda x: x % 2 == 0, numbers)) -print(evens) # [2, 4] - -# reduce() — combine elements -from functools import reduce -total = reduce(lambda a, b: a + b, numbers) -print(total) # 15 -``` +You are ready for the next lesson when you can: +- Write a method that takes parameters and returns a value +- Explain what method overloading is and when to use it +- Describe what `static` means on a method --- - -## Summary - -| Function Type | Description | -|-----------------|----------------------------------------------| -| Regular function | `def` with parameters and return | -| Positional args | Matched by position | -| Keyword args | Matched by name | -| Default args | Has default value | -| `*args` | Variable number of positional arguments | -| `**kwargs` | Variable number of keyword arguments | -| Lambda | One-line anonymous function | -| Recursive | Calls itself with a base case | -| Higher-order | Takes function as argument or returns one | - -> 💡 **Key Tip**: Every function should do **one thing well**. Keep them small and focused. \ No newline at end of file +**Next:** Lesson 07 — Arrays diff --git a/data/Java/data/01-beginner/07-arrays.md b/data/Java/data/01-beginner/07-arrays.md index ad9b7845..da056cc9 100644 --- a/data/Java/data/01-beginner/07-arrays.md +++ b/data/Java/data/01-beginner/07-arrays.md @@ -2,40 +2,173 @@ **Module 01 · Beginner · Lesson 07 of 10** +## Learning Objectives -## Learning objectives - -- Understand **arrays** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Declare, initialise, and access arrays +- Iterate over arrays with loops and the enhanced for loop +- Use 2D arrays for grid-style data ## Overview -Arrays is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. +An **array** is a fixed-size, ordered collection of elements of the same type. Once created, an array's size cannot change. Arrays are the foundation for all data structures in Java. + +## Key Concepts + +### 1. Declaring and Creating Arrays + +```java +// Declare an empty array of 5 integers +int[] scores = new int[5]; // all elements start as 0 + +// Declare and initialise with values +int[] primes = {2, 3, 5, 7, 11}; + +// String array +String[] days = {"Mon", "Tue", "Wed", "Thu", "Fri"}; +``` + +### 2. Accessing Elements (zero-indexed) + +```java +int[] nums = {10, 20, 30, 40, 50}; +System.out.println(nums[0]); // 10 (first element) +System.out.println(nums[4]); // 50 (last element) +System.out.println(nums.length); // 5 + +nums[2] = 99; // Change element at index 2 +// Array is now: {10, 20, 99, 40, 50} +``` + +> Accessing `nums[5]` on a 5-element array throws `ArrayIndexOutOfBoundsException`! + +### 3. Iterating with a for Loop + +```java +int[] scores = {88, 72, 95, 61, 84}; + +// Standard for loop +for (int i = 0; i < scores.length; i++) { + System.out.println("Score " + (i + 1) + ": " + scores[i]); +} +``` + +### 4. Enhanced for Loop (for-each) -## Key concepts +```java +int[] scores = {88, 72, 95, 61, 84}; -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes +for (int score : scores) { + System.out.println(score); +} +``` -## Example +Use the enhanced loop when you don't need the index. + +### 5. Useful `Arrays` Class Methods ```java -// Arrays — practice sketch -// add your code here +import java.util.Arrays; + +int[] nums = {5, 2, 8, 1, 9}; + +Arrays.sort(nums); // sort in place: {1, 2, 5, 8, 9} +System.out.println(Arrays.toString(nums)); // [1, 2, 5, 8, 9] + +int[] copy = Arrays.copyOf(nums, 3); // {1, 2, 5} +boolean equal = Arrays.equals(nums, copy); // false +``` + +### 6. 2D Arrays + +```java +int[][] grid = new int[3][3]; // 3 rows, 3 columns + +// Initialise with values +int[][] matrix = { + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9} +}; + +// Access: matrix[row][column] +System.out.println(matrix[1][2]); // 6 (row 1, column 2) + +// Iterate with nested loops +for (int row = 0; row < matrix.length; row++) { + for (int col = 0; col < matrix[row].length; col++) { + System.out.printf("%3d", matrix[row][col]); + } + System.out.println(); +} +``` + +## Full Example + +```java +import java.util.Arrays; + +public class ArraysDemo { + public static void main(String[] args) { + // Student scores + int[] scores = {78, 92, 55, 88, 73, 95, 61}; + + // Statistics + int sum = 0, max = scores[0], min = scores[0]; + for (int s : scores) { + sum += s; + if (s > max) max = s; + if (s < min) min = s; + } + double avg = (double) sum / scores.length; + + System.out.printf("Scores: %s%n", Arrays.toString(scores)); + System.out.printf("Count: %d%n", scores.length); + System.out.printf("Sum: %d%n", sum); + System.out.printf("Avg: %.1f%n", avg); + System.out.printf("Max: %d%n", max); + System.out.printf("Min: %d%n", min); + + Arrays.sort(scores); + System.out.printf("Sorted: %s%n", Arrays.toString(scores)); + + // 2D: 3x3 identity matrix + int[][] identity = {{1,0,0},{0,1,0},{0,0,1}}; + System.out.println("\nIdentity matrix:"); + for (int[] row : identity) { + System.out.println(Arrays.toString(row)); + } + } +} +``` + +**Expected output:** +``` +Scores: [78, 92, 55, 88, 73, 95, 61] +Count: 7 +Sum: 542 +Avg: 77.4 +Max: 95 +Min: 55 +Sorted: [55, 61, 73, 78, 88, 92, 95] + +Identity matrix: +[1, 0, 0] +[0, 1, 0] +[0, 0, 1] ``` ## Exercise -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). +1. Write a method `reverse(int[] arr)` that reverses an array in place (no new array). +2. Write a method that searches an array for a value and returns its index, or -1 if not found. +3. Create a 5×5 2D array and fill it so that each cell contains `row * column`. ## Checkpoint -You are ready for the next lesson when you can solve the exercise without copying the example. +You are ready for the next lesson when you can: +- Explain why arrays are zero-indexed +- Choose between standard and enhanced for loops +- Access any element in a 2D array using row/column indices --- - -**Next:** Continue to lesson 08 in this module. +**Next:** Lesson 08 — Introduction to Classes diff --git a/data/Java/data/01-beginner/08-classes-intro.md b/data/Java/data/01-beginner/08-classes-intro.md index c0484ea3..f5db26d3 100644 --- a/data/Java/data/01-beginner/08-classes-intro.md +++ b/data/Java/data/01-beginner/08-classes-intro.md @@ -1,41 +1,182 @@ -# Lesson 08 — Classes Introduction +# Lesson 08 — Introduction to Classes and Objects **Module 01 · Beginner · Lesson 08 of 10** +## Learning Objectives -## Learning objectives - -- Understand **classes introduction** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Define a class with fields, constructors, and methods +- Create objects and call their methods +- Understand the `this` keyword ## Overview -Classes Introduction is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. +Java is an **object-oriented language**. A **class** is a blueprint, and an **object** is a real instance created from that blueprint. For example, `Car` is a class; your red Toyota is an object. + +Classes bundle related **data** (fields) and **behaviour** (methods) together — this is called **encapsulation**. + +## Key Concepts + +### 1. Defining a Class + +```java +public class Dog { + // Fields (data) + String name; + String breed; + int age; + + // Constructor (called when creating an object) + public Dog(String name, String breed, int age) { + this.name = name; + this.breed = breed; + this.age = age; + } + + // Method (behaviour) + public void bark() { + System.out.println(name + " says: Woof!"); + } + + public String describe() { + return name + " is a " + age + "-year-old " + breed; + } +} +``` + +### 2. Creating Objects + +```java +// new ClassName(constructor arguments) +Dog rex = new Dog("Rex", "German Shepherd", 3); +Dog buddy = new Dog("Buddy", "Golden Retriever", 5); + +rex.bark(); // Rex says: Woof! +System.out.println(buddy.describe()); // Buddy is a 5-year-old Golden Retriever +``` + +### 3. The `this` Keyword + +`this` refers to the **current object**. It's used when a parameter name shadows a field name. -## Key concepts +```java +public Dog(String name, int age) { + this.name = name; // this.name = field, name = parameter + this.age = age; +} +``` + +### 4. Multiple Constructors (Constructor Overloading) + +```java +public class Dog { + String name; + int age; + + // Full constructor + public Dog(String name, int age) { + this.name = name; + this.age = age; + } + + // Default age constructor + public Dog(String name) { + this(name, 1); // calls the full constructor + } +} + +Dog puppy = new Dog("Max"); // age defaults to 1 +Dog adult = new Dog("Rex", 4); +``` + +### 5. Getters and Setters (best practice) -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes +Fields should be `private`, accessed through public methods. -## Example +```java +public class Person { + private String name; // private — hidden from outside + private int age; + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + // Getter + public String getName() { return name; } + public int getAge() { return age; } + + // Setter with validation + public void setAge(int age) { + if (age >= 0) this.age = age; + } +} +``` + +## Full Example ```java -// Classes Introduction — practice sketch -// add your code here +public class BankAccount { + private String owner; + private double balance; + + public BankAccount(String owner, double initialBalance) { + this.owner = owner; + this.balance = initialBalance; + } + + public void deposit(double amount) { + if (amount > 0) { + balance += amount; + System.out.printf("Deposited %.2f. New balance: %.2f%n", amount, balance); + } + } + + public void withdraw(double amount) { + if (amount > balance) { + System.out.println("Insufficient funds!"); + } else { + balance -= amount; + System.out.printf("Withdrawn %.2f. New balance: %.2f%n", amount, balance); + } + } + + public void printStatement() { + System.out.printf("[%s] Balance: $%.2f%n", owner, balance); + } + + public static void main(String[] args) { + BankAccount acc = new BankAccount("Alice", 1000.00); + acc.printStatement(); + acc.deposit(500.00); + acc.withdraw(200.00); + acc.withdraw(2000.00); // insufficient + acc.printStatement(); + } +} +``` + +**Expected output:** +``` +[Alice] Balance: $1000.00 +Deposited 500.00. New balance: $1500.00 +Withdrawn 200.00. New balance: $1300.00 +Insufficient funds! +[Alice] Balance: $1300.00 ``` ## Exercise -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). +1. Create a `Rectangle` class with `width` and `height` fields, a constructor, and methods `area()` and `perimeter()`. +2. Create a `Student` class with `name`, `id`, and `grades` (array). Add a method `average()` that returns the average grade. +3. Add private fields and public getters/setters to both classes. ## Checkpoint -You are ready for the next lesson when you can solve the exercise without copying the example. +You are ready for the next lesson when you can: +- Write a class from scratch with fields, constructor, and methods +- Explain why fields should be `private` +- Use `this` correctly --- - -**Next:** Continue to lesson 09 in this module. +**Next:** Lesson 09 — Strings diff --git a/data/Java/data/01-beginner/09-strings.md b/data/Java/data/01-beginner/09-strings.md index 7deff8b4..e4ee20e9 100644 --- a/data/Java/data/01-beginner/09-strings.md +++ b/data/Java/data/01-beginner/09-strings.md @@ -2,40 +2,168 @@ **Module 01 · Beginner · Lesson 09 of 10** +## Learning Objectives -## Learning objectives - -- Understand **strings** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Use common `String` methods confidently +- Understand immutability and why `==` doesn't compare string content +- Use `StringBuilder` for efficient string building ## Overview -Strings is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. +`String` is one of the most-used types in Java. Unlike primitives, `String` is a class with dozens of methods. A critical feature: **strings are immutable** — once created, a String object cannot be changed. Every operation creates a new String. + +## Key Concepts + +### 1. Creating Strings + +```java +String a = "Hello"; // String literal (preferred) +String b = new String("Hello"); // Explicit object (rarely needed) +``` + +### 2. Comparing Strings + +**Never use `==` to compare string content.** Use `.equals()`. + +```java +String s1 = "Java"; +String s2 = "Java"; +String s3 = new String("Java"); + +System.out.println(s1 == s2); // true (same literal, same object in pool) +System.out.println(s1 == s3); // false (different objects in memory!) +System.out.println(s1.equals(s3)); // true ← always use this +System.out.println(s1.equalsIgnoreCase("JAVA")); // true +``` + +### 3. Essential String Methods + +```java +String s = " Hello, Java World! "; + +s.length() // 22 +s.trim() // "Hello, Java World!" (removes leading/trailing spaces) +s.toLowerCase() // " hello, java world! " +s.toUpperCase() // " HELLO, JAVA WORLD! " +s.contains("Java") // true +s.startsWith(" Hello") // true +s.endsWith("!") // false (has trailing space) +s.indexOf("Java") // 9 (index of first occurrence) +s.replace("Java", "Python") // " Hello, Python World! " +s.substring(8, 12) // "Java" (index 8 inclusive to 12 exclusive) +s.split(", ") // [" Hello", "Java World! "] +s.isEmpty() // false +s.isBlank() // false (Java 11+: checks for whitespace only) +``` + +### 4. String Concatenation and `+` + +```java +String first = "Hello"; +String second = "World"; +String result = first + ", " + second + "!"; // "Hello, World!" + +// Concatenating in a loop is SLOW — use StringBuilder instead +``` + +### 5. StringBuilder — Efficient String Building + +```java +StringBuilder sb = new StringBuilder(); +for (int i = 1; i <= 5; i++) { + sb.append(i); + if (i < 5) sb.append(", "); +} +String result = sb.toString(); +System.out.println(result); // 1, 2, 3, 4, 5 + +// Other StringBuilder methods: +sb.insert(0, "Numbers: "); +sb.reverse(); +sb.delete(0, 3); +``` + +### 6. String Formatting + +```java +String name = "Alice"; +int age = 25; + +// printf style +String msg = String.format("Name: %s, Age: %d", name, age); + +// Modern: formatted() in Java 15+ +String msg2 = "Name: %s, Age: %d".formatted(name, age); +``` -## Key concepts +### 7. Converting Between Types -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes +```java +// String → number +int n = Integer.parseInt("42"); +double d = Double.parseDouble("3.14"); + +// Number → String +String s1 = String.valueOf(42); +String s2 = Integer.toString(42); +String s3 = "" + 42; // quick but less readable +``` -## Example +## Full Example ```java -// Strings — practice sketch -// add your code here +public class StringsDemo { + public static void main(String[] args) { + String sentence = "The quick brown fox jumps over the lazy dog"; + + System.out.println("Original: " + sentence); + System.out.println("Length: " + sentence.length()); + System.out.println("Upper: " + sentence.toUpperCase()); + System.out.println("Contains 'fox': " + sentence.contains("fox")); + System.out.println("Word count: " + sentence.split(" ").length); + System.out.println("Replace: " + sentence.replace("fox", "cat")); + + // Reverse words + String[] words = sentence.split(" "); + StringBuilder reversed = new StringBuilder(); + for (int i = words.length - 1; i >= 0; i--) { + reversed.append(words[i]); + if (i > 0) reversed.append(" "); + } + System.out.println("Reversed words: " + reversed); + + // Palindrome check + String test = "racecar"; + String rev = new StringBuilder(test).reverse().toString(); + System.out.println(test + " is palindrome: " + test.equals(rev)); + } +} +``` + +**Expected output:** +``` +Original: The quick brown fox jumps over the lazy dog +Length: 43 +Upper: THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG +Contains 'fox': true +Word count: 9 +Replace: The quick brown cat jumps over the lazy dog +Reversed words: dog lazy the over jumps fox brown quick The +racecar is palindrome: true ``` ## Exercise -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). +1. Write a method `countVowels(String s)` that counts vowels (a, e, i, o, u) in a string. +2. Write a method `titleCase(String s)` that capitalises the first letter of every word. +3. Write a method `isPalindrome(String s)` that returns `true` if the string reads the same forwards and backwards (ignore case and spaces). ## Checkpoint -You are ready for the next lesson when you can solve the exercise without copying the example. +You are ready for the next lesson when you can: +- Explain why `==` fails for string comparison +- Choose between `String` and `StringBuilder` appropriately +- Convert a `String` to an `int` and back --- - -**Next:** Continue to lesson 10 in this module. +**Next:** Lesson 10 — Scanner and User Input diff --git a/data/Java/data/01-beginner/10-scanner-input.md b/data/Java/data/01-beginner/10-scanner-input.md index 03881d82..15919de5 100644 --- a/data/Java/data/01-beginner/10-scanner-input.md +++ b/data/Java/data/01-beginner/10-scanner-input.md @@ -1,41 +1,139 @@ -# Lesson 10 — User Input with Scanner +# Lesson 10 — Scanner and User Input **Module 01 · Beginner · Lesson 10 of 10** +## Learning Objectives -## Learning objectives - -- Understand **user input with scanner** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Read user input from the console using `Scanner` +- Handle different input types (int, double, String) +- Validate input and handle common errors ## Overview -User Input with Scanner is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. +The `Scanner` class (in `java.util`) reads input from the keyboard (or files). It's the standard way beginners accept user input in console Java programs. + +## Key Concepts -## Key concepts +### 1. Setting Up Scanner + +```java +import java.util.Scanner; -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes +public class InputDemo { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); // attach to keyboard + + System.out.print("Enter your name: "); + String name = sc.nextLine(); + + System.out.println("Hello, " + name + "!"); + sc.close(); // always close when done + } +} +``` -## Example +### 2. Reading Different Types ```java -// User Input with Scanner — practice sketch -// add your code here +Scanner sc = new Scanner(System.in); + +int age = sc.nextInt(); // reads an integer +double salary = sc.nextDouble(); // reads a decimal +String word = sc.next(); // reads one word (stops at space) +String line = sc.nextLine(); // reads the entire line +``` + +### 3. The Newline Trap + +After `nextInt()` or `nextDouble()`, a leftover newline character stays in the buffer. Calling `nextLine()` immediately after reads that empty newline, not the user's input. + +```java +Scanner sc = new Scanner(System.in); + +System.out.print("Enter age: "); +int age = sc.nextInt(); +sc.nextLine(); // ← consume the leftover newline + +System.out.print("Enter name: "); +String name = sc.nextLine(); // now works correctly +``` + +### 4. Input Validation Loop + +```java +Scanner sc = new Scanner(System.in); +int number = -1; + +while (true) { + System.out.print("Enter a positive number: "); + if (sc.hasNextInt()) { + number = sc.nextInt(); + if (number > 0) break; + System.out.println("Must be positive!"); + } else { + System.out.println("That's not an integer!"); + sc.next(); // discard the invalid token + } +} +System.out.println("You entered: " + number); +``` + +## Full Example — Simple Calculator + +```java +import java.util.Scanner; + +public class Calculator { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + System.out.println("=== Simple Calculator ==="); + System.out.print("Enter first number: "); + double a = sc.nextDouble(); + System.out.print("Enter operator (+,-,*,/): "); + String op = sc.next(); + System.out.print("Enter second number: "); + double b = sc.nextDouble(); + + double result; + switch (op) { + case "+" -> result = a + b; + case "-" -> result = a - b; + case "*" -> result = a * b; + case "/" -> { + if (b == 0) { System.out.println("Cannot divide by zero!"); sc.close(); return; } + result = a / b; + } + default -> { System.out.println("Unknown operator: " + op); sc.close(); return; } + } + + System.out.printf("Result: %.2f %s %.2f = %.2f%n", a, op, b, result); + sc.close(); + } +} +``` + +**Sample run:** +``` +=== Simple Calculator === +Enter first number: 15 +Enter operator (+,-,*,/): / +Enter second number: 4 +Result: 15.00 / 4.00 = 3.75 ``` ## Exercise -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). +1. Write a program that asks for 5 integers one by one and prints their sum, average, max, and min. +2. Write a number-guessing game: the program picks a random number 1-100, the user guesses, and the program says "Too high", "Too low", or "Correct!". +3. Extend the calculator above to loop until the user types `q` to quit. ## Checkpoint -You are ready for the next lesson when you can solve the exercise without copying the example. +You are ready for the next module when you can: +- Read integers, doubles, and full lines from `Scanner` +- Fix the newline trap between `nextInt()` and `nextLine()` +- Write an input-validation loop --- - -**Next:** Continue to lesson 11 in this module. +**Module 01 Complete!** You are ready for **Module 02 — Intermediate Java**. diff --git a/data/Java/data/02-intermediate/01-oop-inheritance.md b/data/Java/data/02-intermediate/01-oop-inheritance.md index d308ca8b..48fa047b 100644 --- a/data/Java/data/02-intermediate/01-oop-inheritance.md +++ b/data/Java/data/02-intermediate/01-oop-inheritance.md @@ -1,609 +1,201 @@ -# Lesson 01 — Inheritance and Polymorphism +# Lesson 01 — OOP: Inheritance and Polymorphism **Module 02 · Intermediate · Lesson 01 of 06** +## Learning Objectives -## Learning objectives - -- Understand **inheritance and polymorphism** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Use `extends` to create subclasses +- Override methods with `@Override` +- Understand polymorphism — treating subclasses as their parent type ## Overview -Inheritance and Polymorphism is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. - -## Key concepts - -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes - -## Example - -```java -// Inheritance and Polymorphism — practice sketch -// add your code here -``` - -## Exercise - -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). - -## Checkpoint - -You are ready for the next lesson when you can solve the exercise without copying the example. - ---- - -**Next:** Continue to lesson 02 in this module. - ---- - -## Additional reference - -# Java Object-Oriented Programming +**Inheritance** lets one class (child) reuse and extend the behaviour of another (parent). **Polymorphism** lets you write code that works with any subclass through the parent type, making programs flexible and extensible. -## Classes and Objects - -### Class Definition -```java -public class Person { - // Instance variables (fields) - private String name; - private int age; - private String email; - - // Constructor - public Person(String name, int age, String email) { - this.name = name; - this.age = age; - this.email = email; - } - - // Default constructor - public Person() { - this.name = "Unknown"; - this.age = 0; - this.email = "unknown@example.com"; - } - - // Methods - public void displayInfo() { - System.out.println("Name: " + name); - System.out.println("Age: " + age); - System.out.println("Email: " + email); - } - - // Getters and setters - public String getName() { return name; } - public void setName(String name) { this.name = name; } - - public int getAge() { return age; } - public void setAge(int age) { this.age = age; } - - public String getEmail() { return email; } - public void setEmail(String email) { this.email = email; } -} -``` - -### Object Creation -```java -// Creating objects -Person person1 = new Person("John Doe", 30, "john@example.com"); -Person person2 = new Person(); - -// Using methods -person1.displayInfo(); -person2.setName("Jane Smith"); -person2.setAge(25); -person2.displayInfo(); - -// Accessing properties -String name = person1.getName(); -int age = person1.getAge(); -``` - -## Encapsulation - -### Access Modifiers -```java -public class BankAccount { - // Private fields - encapsulation - private String accountNumber; - private double balance; - private String ownerName; - - // Public methods - controlled access - public BankAccount(String accountNumber, String ownerName, double initialBalance) { - this.accountNumber = accountNumber; - this.ownerName = ownerName; - this.balance = initialBalance; - } - - // Public getter for balance (read-only access) - public double getBalance() { - return balance; - } - - // Public method for deposit (with validation) - public void deposit(double amount) { - if (amount > 0) { - balance += amount; - System.out.println("Deposited: $" + amount); - } else { - System.out.println("Invalid deposit amount"); - } - } - - // Public method for withdrawal (with validation) - public void withdraw(double amount) { - if (amount > 0 && amount <= balance) { - balance -= amount; - System.out.println("Withdrew: $" + amount); - } else { - System.out.println("Invalid withdrawal amount"); - } - } - - // Private helper method - private boolean isValidAmount(double amount) { - return amount > 0; - } -} -``` +## Key Concepts -## Inheritance +### 1. extends -### Superclass and Subclass ```java -// Superclass +// Parent class public class Animal { protected String name; protected int age; - + public Animal(String name, int age) { this.name = name; this.age = age; } - - public void eat() { - System.out.println(name + " is eating"); - } - - public void sleep() { - System.out.println(name + " is sleeping"); + + public void speak() { + System.out.println(name + " makes a sound."); } - - public void makeSound() { - System.out.println(name + " makes a sound"); + + public String describe() { + return name + " (age " + age + ")"; } - - // Getters - public String getName() { return name; } - public int getAge() { return age; } } -// Subclass +// Child class public class Dog extends Animal { private String breed; - + public Dog(String name, int age, String breed) { - super(name, age); // Call superclass constructor + super(name, age); // calls Animal's constructor this.breed = breed; } - - // Override superclass method + @Override - public void makeSound() { + public void speak() { // override Animal's speak() System.out.println(name + " barks: Woof!"); } - - // New method specific to Dog - public void wagTail() { - System.out.println(name + " wags tail"); - } - - // Getter - public String getBreed() { return breed; } -} -// Another subclass -public class Cat extends Animal { - private boolean isIndoor; - - public Cat(String name, int age, boolean isIndoor) { - super(name, age); - this.isIndoor = isIndoor; - } - - @Override - public void makeSound() { - System.out.println(name + " meows: Meow!"); - } - - public void purr() { - System.out.println(name + " purrs"); - } - - public boolean isIndoor() { return isIndoor; } + public String getBreed() { return breed; } } ``` -### Using Inheritance -```java -public class AnimalDemo { - public static void main(String[] args) { - // Create objects - Dog dog = new Dog("Buddy", 3, "Golden Retriever"); - Cat cat = new Cat("Whiskers", 2, true); - - // Use inherited methods - dog.eat(); // From Animal class - dog.sleep(); // From Animal class - dog.makeSound(); // Overridden in Dog - dog.wagTail(); // Dog-specific - - cat.eat(); // From Animal class - cat.sleep(); // From Animal class - cat.makeSound(); // Overridden in Cat - cat.purr(); // Cat-specific - - // Polymorphism - Animal animal1 = new Dog("Max", 4, "Labrador"); - Animal animal2 = new Cat("Luna", 1, false); - - animal1.makeSound(); // Calls Dog's makeSound - animal2.makeSound(); // Calls Cat's makeSound - } -} -``` +### 2. super keyword -## Polymorphism +- `super(args)` — calls the parent constructor (must be first line) +- `super.method()` — calls the parent version of an overridden method -### Method Overriding ```java -public class Shape { - protected String color; - - public Shape(String color) { - this.color = color; - } - - public double getArea() { - return 0.0; // Default implementation - } - - public void draw() { - System.out.println("Drawing a " + color + " shape"); - } +@Override +public void speak() { + super.speak(); // prints "Rex makes a sound." + System.out.println(name + " also barks!"); } +``` -public class Circle extends Shape { - private double radius; - - public Circle(String color, double radius) { - super(color); - this.radius = radius; - } - - @Override - public double getArea() { - return Math.PI * radius * radius; - } - - @Override - public void draw() { - System.out.println("Drawing a " + color + " circle with radius " + radius); - } -} +### 3. @Override Annotation -public class Rectangle extends Shape { - private double width; - private double height; - - public Rectangle(String color, double width, double height) { - super(color); - this.width = width; - this.height = height; - } - - @Override - public double getArea() { - return width * height; - } - - @Override - public void draw() { - System.out.println("Drawing a " + color + " rectangle " + width + "x" + height); - } -} -``` +Always use `@Override` when overriding. It makes the compiler verify you're actually overriding (catches typos in method names). + +### 4. Polymorphism -### Polymorphic Behavior ```java -public class ShapeDemo { - public static void main(String[] args) { - // Create shapes array - Shape[] shapes = { - new Circle("red", 5.0), - new Rectangle("blue", 4.0, 6.0), - new Circle("green", 3.0) - }; - - // Polymorphic behavior - for (Shape shape : shapes) { - shape.draw(); // Calls appropriate draw method - System.out.println("Area: " + shape.getArea()); - System.out.println(); - } - - // Method with polymorphic parameter - printShapeInfo(new Circle("yellow", 2.5)); - printShapeInfo(new Rectangle("purple", 3.0, 4.0)); - } - - public static void printShapeInfo(Shape shape) { - System.out.println("Shape info:"); - shape.draw(); - System.out.println("Area: " + shape.getArea()); - } +Animal[] animals = { + new Dog("Rex", 3, "Shepherd"), + new Cat("Whiskers", 5), + new Bird("Tweety", 2) +}; + +for (Animal a : animals) { + a.speak(); // calls each subclass's version automatically } ``` -## Abstraction +### 5. instanceof Check -### Abstract Classes ```java -public abstract class Vehicle { - protected String brand; - protected String model; - protected int year; - - public Vehicle(String brand, String model, int year) { - this.brand = brand; - this.model = model; - this.year = year; - } - - // Concrete method - public void displayInfo() { - System.out.println(year + " " + brand + " " + model); - } - - // Abstract methods (must be implemented by subclasses) - public abstract void start(); - public abstract void stop(); - public abstract double getFuelEfficiency(); -} - -public class Car extends Vehicle { - private int numberOfDoors; - - public Car(String brand, String model, int year, int numberOfDoors) { - super(brand, model, year); - this.numberOfDoors = numberOfDoors; - } - - @Override - public void start() { - System.out.println("Car engine starting..."); - } - - @Override - public void stop() { - System.out.println("Car engine stopping..."); - } - - @Override - public double getFuelEfficiency() { - return 25.5; // miles per gallon - } -} +Animal a = new Dog("Rex", 3, "Shepherd"); -public class Motorcycle extends Vehicle { - private boolean hasSidecar; - - public Motorcycle(String brand, String model, int year, boolean hasSidecar) { - super(brand, model, year); - this.hasSidecar = hasSidecar; - } - - @Override - public void start() { - System.out.println("Motorcycle engine starting..."); - } - - @Override - public void stop() { - System.out.println("Motorcycle engine stopping..."); - } - - @Override - public double getFuelEfficiency() { - return 45.0; // miles per gallon - } +if (a instanceof Dog dog) { // Java 16+ pattern matching + System.out.println("Breed: " + dog.getBreed()); } ``` -### Interfaces +### 6. Abstract Classes + +An abstract class cannot be instantiated — it exists only to be extended. + ```java -public interface Drawable { - void draw(); - void setColor(String color); - String getColor(); -} +public abstract class Shape { + public abstract double area(); // must be implemented by subclasses + public abstract double perimeter(); -public interface Movable { - void move(int x, int y); - int getX(); - int getY(); + public void printInfo() { + System.out.printf("Area: %.2f, Perimeter: %.2f%n", area(), perimeter()); + } } -public class Point implements Drawable, Movable { - private int x, y; - private String color; - - public Point(int x, int y, String color) { - this.x = x; - this.y = y; - this.color = color; - } - - @Override - public void draw() { - System.out.println("Drawing point at (" + x + ", " + y + ") with color " + color); - } - - @Override - public void setColor(String color) { - this.color = color; - } - - @Override - public String getColor() { - return color; - } - - @Override - public void move(int x, int y) { - this.x = x; - this.y = y; - } - - @Override - public int getX() { return x; } - - @Override - public int getY() { return y; } +public class Circle extends Shape { + private double radius; + public Circle(double radius) { this.radius = radius; } + + @Override public double area() { return Math.PI * radius * radius; } + @Override public double perimeter() { return 2 * Math.PI * radius; } } ``` -## Examples +## Full Example -### Complete OOP Example ```java -public class BankingSystem { - public static void main(String[] args) { - // Create accounts - SavingsAccount savings = new SavingsAccount("12345", "John Doe", 1000.0, 0.05); - CheckingAccount checking = new CheckingAccount("67890", "Jane Smith", 500.0, 1000.0); - - // Use polymorphism - Account[] accounts = {savings, checking}; - - for (Account account : accounts) { - account.displayInfo(); - account.deposit(200.0); - account.withdraw(100.0); - System.out.println("Balance: $" + account.getBalance()); - System.out.println(); +public class InheritanceDemo { + abstract static class Vehicle { + protected String brand; + protected int year; + + public Vehicle(String brand, int year) { + this.brand = brand; this.year = year; } - - // Specific method calls - savings.addInterest(); - checking.checkOverdraft(); - } -} -// Abstract base class -abstract class Account { - protected String accountNumber; - protected String ownerName; - protected double balance; - - public Account(String accountNumber, String ownerName, double balance) { - this.accountNumber = accountNumber; - this.ownerName = ownerName; - this.balance = balance; - } - - public abstract void withdraw(double amount); - - public void deposit(double amount) { - if (amount > 0) { - balance += amount; - System.out.println("Deposited: $" + amount); + public abstract String fuelType(); + + public void describe() { + System.out.printf("%d %s — runs on %s%n", year, brand, fuelType()); } } - - public void displayInfo() { - System.out.println("Account: " + accountNumber); - System.out.println("Owner: " + ownerName); - System.out.println("Balance: $" + balance); - } - - // Getters - public String getAccountNumber() { return accountNumber; } - public String getOwnerName() { return ownerName; } - public double getBalance() { return balance; } -} -// Concrete subclass -class SavingsAccount extends Account { - private double interestRate; - - public SavingsAccount(String accountNumber, String ownerName, double balance, double interestRate) { - super(accountNumber, ownerName, balance); - this.interestRate = interestRate; - } - - @Override - public void withdraw(double amount) { - if (amount > 0 && amount <= balance) { - balance -= amount; - System.out.println("Withdrew: $" + amount); - } else { - System.out.println("Invalid withdrawal amount"); + static class Car extends Vehicle { + private int doors; + public Car(String brand, int year, int doors) { + super(brand, year); this.doors = doors; + } + @Override public String fuelType() { return "petrol"; } + @Override public void describe() { + super.describe(); + System.out.println(" Doors: " + doors); } } - - public void addInterest() { - double interest = balance * interestRate; - balance += interest; - System.out.println("Interest added: $" + interest); - } -} -// Another concrete subclass -class CheckingAccount extends Account { - private double overdraftLimit; - - public CheckingAccount(String accountNumber, String ownerName, double balance, double overdraftLimit) { - super(accountNumber, ownerName, balance); - this.overdraftLimit = overdraftLimit; - } - - @Override - public void withdraw(double amount) { - if (amount > 0 && amount <= (balance + overdraftLimit)) { - balance -= amount; - System.out.println("Withdrew: $" + amount); - } else { - System.out.println("Exceeds overdraft limit"); + static class ElectricCar extends Car { + private int range; + public ElectricCar(String brand, int year, int doors, int range) { + super(brand, year, doors); this.range = range; + } + @Override public String fuelType() { return "electricity"; } + @Override public void describe() { + super.describe(); + System.out.println(" Range: " + range + " km"); } } - - public void checkOverdraft() { - if (balance < 0) { - System.out.println("Account is overdrawn by: $" + Math.abs(balance)); - } else { - System.out.println("Account is not overdrawn"); + + public static void main(String[] args) { + Vehicle[] fleet = { + new Car("Toyota", 2020, 4), + new ElectricCar("Tesla", 2023, 4, 560) + }; + for (Vehicle v : fleet) { + v.describe(); + System.out.println(); } } } ``` -## Best Practices -- Use private fields and public methods for encapsulation -- Favor composition over inheritance when appropriate -- Use abstract classes for shared implementation -- Use interfaces for shared behavior -- Follow single responsibility principle -- Use meaningful names for classes, methods, and variables -- Override toString() for better debugging -- Implement equals() and hashCode() for object comparison -- Use polymorphism to write flexible code -- Keep inheritance hierarchies shallow and focused +**Expected output:** +``` +2020 Toyota — runs on petrol + Doors: 4 + +2023 Tesla — runs on electricity + Doors: 4 + Range: 560 km +``` + +## Exercise + +1. Create a `Shape` hierarchy: abstract `Shape`, then `Rectangle`, `Circle`, and `Triangle` subclasses. Each implements `area()` and `perimeter()`. +2. Create an array of 5 different shapes and print all their info using polymorphism. +3. Add an abstract `Employee` class with `calculatePay()`, then create `FullTimeEmployee` and `FreelanceEmployee` subclasses. + +## Checkpoint + +You are ready for the next lesson when you can: +- Write a 3-level inheritance hierarchy +- Explain the difference between `abstract` class and regular class +- Describe what polymorphism achieves + +--- +**Next:** Lesson 02 — Interfaces diff --git a/data/Java/data/02-intermediate/02-interfaces.md b/data/Java/data/02-intermediate/02-interfaces.md index 23802cc0..6f2feace 100644 --- a/data/Java/data/02-intermediate/02-interfaces.md +++ b/data/Java/data/02-intermediate/02-interfaces.md @@ -1,41 +1,184 @@ -# Lesson 02 — Interfaces and Abstract Classes +# Lesson 02 — Interfaces **Module 02 · Intermediate · Lesson 02 of 06** +## Learning Objectives -## Learning objectives - -- Understand **interfaces and abstract classes** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Define and implement interfaces +- Understand how interfaces differ from abstract classes +- Use default and static interface methods (Java 8+) ## Overview -Interfaces and Abstract Classes is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. +An **interface** is a contract — it defines methods a class *must* implement, without providing the implementation. A class can implement **multiple interfaces** (unlike inheritance, where only one parent class is allowed). Interfaces are how Java achieves multiple-type behaviour. + +## Key Concepts + +### 1. Defining an Interface + +```java +public interface Drawable { + void draw(); // implicitly public abstract + double getArea(); +} + +public interface Resizable { + void resize(double factor); +} +``` + +### 2. Implementing an Interface + +```java +public class Circle implements Drawable, Resizable { + private double radius; + + public Circle(double radius) { this.radius = radius; } + + @Override + public void draw() { + System.out.println("Drawing circle with radius " + radius); + } + + @Override + public double getArea() { return Math.PI * radius * radius; } + + @Override + public void resize(double factor) { radius *= factor; } +} +``` + +### 3. Interface vs Abstract Class + +| Feature | Interface | Abstract Class | +|---------|-----------|----------------| +| Multiple inheritance | ✅ (implement many) | ❌ (extend only one) | +| Constructor | ❌ | ✅ | +| Fields | Only constants (`static final`) | Any fields | +| Methods | Abstract + default/static | Any methods | +| Use when | Defining capability | Sharing common code | + +### 4. Default Methods (Java 8+) + +Provide a default implementation — implementing classes can override it or use it as-is. -## Key concepts +```java +public interface Logger { + void log(String message); // must implement + + default void logError(String message) { // optional to override + log("[ERROR] " + message); + } + + default void logInfo(String message) { + log("[INFO] " + message); + } +} +``` + +### 5. static Methods in Interfaces + +```java +public interface MathUtils { + static double clamp(double value, double min, double max) { + return Math.max(min, Math.min(max, value)); + } +} + +// Usage: +double result = MathUtils.clamp(150, 0, 100); // 100.0 +``` + +### 6. Functional Interfaces (1 abstract method) -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes +An interface with exactly one abstract method can be used with **lambda expressions**. -## Example +```java +@FunctionalInterface +public interface Validator { + boolean validate(String input); +} + +// Lambda usage: +Validator emailCheck = email -> email.contains("@"); +System.out.println(emailCheck.validate("user@example.com")); // true +``` + +## Full Example ```java -// Interfaces and Abstract Classes — practice sketch -// add your code here +public class InterfaceDemo { + interface Payable { + double calculatePay(); + default String paymentSummary() { + return String.format("Pay: $%.2f", calculatePay()); + } + } + + interface Taxable { + double TAX_RATE = 0.20; // implicitly public static final + double calculateTax(); + } + + static class Employee implements Payable, Taxable { + private String name; + private double hourlyRate; + private int hoursWorked; + + public Employee(String name, double hourlyRate, int hoursWorked) { + this.name = name; + this.hourlyRate = hourlyRate; + this.hoursWorked = hoursWorked; + } + + @Override public double calculatePay() { return hourlyRate * hoursWorked; } + @Override public double calculateTax() { return calculatePay() * TAX_RATE; } + + public void printSlip() { + System.out.println("Employee: " + name); + System.out.println(paymentSummary()); + System.out.printf("Tax (20%%): $%.2f%n", calculateTax()); + System.out.printf("Net: $%.2f%n", calculatePay() - calculateTax()); + System.out.println("---"); + } + } + + public static void main(String[] args) { + Employee[] staff = { + new Employee("Alice", 30.0, 160), + new Employee("Bob", 25.0, 120) + }; + for (Employee e : staff) e.printSlip(); + } +} +``` + +**Expected output:** +``` +Employee: Alice +Pay: $4800.00 +Tax (20%): $960.00 +Net: $3840.00 +--- +Employee: Bob +Pay: $3000.00 +Tax (20%): $600.00 +Net: $2400.00 +--- ``` ## Exercise -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). +1. Create a `Sortable` interface with methods `sortAscending()` and `sortDescending()`. Implement it in a `NumberList` class. +2. Create a `Playable` interface for a media player (play, pause, stop, seek). Implement it in `AudioPlayer` and `VideoPlayer` classes. +3. Write a `@FunctionalInterface` called `StringTransformer` and use it with lambdas to reverse, uppercase, and remove spaces from strings. ## Checkpoint -You are ready for the next lesson when you can solve the exercise without copying the example. +You are ready for the next lesson when you can: +- Implement two interfaces in one class +- Explain when to choose an interface over an abstract class +- Write a default method in an interface --- - -**Next:** Continue to lesson 03 in this module. +**Next:** Lesson 03 — Collections Framework diff --git a/data/Java/data/02-intermediate/03-collections.md b/data/Java/data/02-intermediate/03-collections.md index a5e29c0d..ae1493bb 100644 --- a/data/Java/data/02-intermediate/03-collections.md +++ b/data/Java/data/02-intermediate/03-collections.md @@ -2,469 +2,191 @@ **Module 02 · Intermediate · Lesson 03 of 06** -# Java Collections Framework +## Learning Objectives -## List Interface +- Use `ArrayList`, `LinkedList`, `HashMap`, `HashSet`, and `LinkedHashMap` +- Iterate collections using for-each and iterators +- Choose the right collection for the job + +## Overview + +Arrays are fixed-size. The **Collections Framework** gives you dynamic, resizable data structures. `java.util` contains List, Set, Map, and Queue interfaces with multiple implementations. Knowing which to use and why is a core Java skill. + +## Key Concepts + +### 1. List — ArrayList and LinkedList + +`List` is ordered and allows duplicates. -### ArrayList ```java import java.util.ArrayList; import java.util.List; -// Create ArrayList List names = new ArrayList<>(); -List numbers = new ArrayList<>(); - -// Add elements names.add("Alice"); names.add("Bob"); names.add("Charlie"); +names.add("Alice"); // duplicates allowed -// Add at specific index -names.add(1, "David"); - -// Access elements -String first = names.get(0); -String last = names.get(names.size() - 1); +System.out.println(names.size()); // 4 +System.out.println(names.get(1)); // Bob +System.out.println(names.contains("Bob")); // true -// Modify elements -names.set(0, "Alice Smith"); - -// Remove elements -names.remove("Bob"); -names.remove(0); // Remove by index - -// Check if contains -boolean hasAlice = names.contains("Alice"); - -// Get size -int size = names.size(); +names.remove("Bob"); // remove by value +names.remove(0); // remove by index // Iterate for (String name : names) { System.out.println(name); } - -// Clear all elements -names.clear(); ``` -### LinkedList -```java -import java.util.LinkedList; - -// Create LinkedList -LinkedList list = new LinkedList<>(); - -// Add elements -list.add("First"); -list.add("Second"); -list.add("Third"); +**ArrayList vs LinkedList:** +| | ArrayList | LinkedList | +|--|-----------|------------| +| Get by index | O(1) — fast | O(n) — slow | +| Insert/delete at middle | O(n) | O(1) | +| Use when | Most cases | Frequent insertions/deletions | -// Add to beginning and end -list.addFirst("Beginning"); -list.addLast("End"); +### 2. Set — HashSet, LinkedHashSet, TreeSet -// Remove from beginning and end -list.removeFirst(); -list.removeLast(); +`Set` has **no duplicates**. HashSet has no order, LinkedHashSet preserves insertion order, TreeSet sorts. -// Get first and last elements -String first = list.getFirst(); -String last = list.getLast(); -``` - -## Set Interface - -### HashSet ```java import java.util.HashSet; import java.util.Set; -// Create HashSet -Set uniqueNames = new HashSet<>(); - -// Add elements (duplicates are ignored) -uniqueNames.add("Alice"); -uniqueNames.add("Bob"); -uniqueNames.add("Alice"); // Duplicate - ignored - -// Check if contains -boolean hasBob = uniqueNames.contains("Bob"); - -// Get size -int size = uniqueNames.size(); - -// Remove element -uniqueNames.remove("Bob"); +Set fruits = new HashSet<>(); +fruits.add("Apple"); +fruits.add("Banana"); +fruits.add("Apple"); // duplicate — ignored +fruits.add("Cherry"); -// Iterate -for (String name : uniqueNames) { - System.out.println(name); -} - -// Clear all -uniqueNames.clear(); +System.out.println(fruits.size()); // 3 +System.out.println(fruits.contains("Banana")); // true ``` -### TreeSet -```java -import java.util.TreeSet; -import java.util.Set; +### 3. Map — HashMap, LinkedHashMap, TreeMap -// Create TreeSet (sorted) -Set sortedNumbers = new TreeSet<>(); +`Map` stores key-value pairs. Keys must be unique. -// Add elements (automatically sorted) -sortedNumbers.add(5); -sortedNumbers.add(2); -sortedNumbers.add(8); -sortedNumbers.add(1); - -// Get first and last (smallest and largest) -int first = sortedNumbers.first(); -int last = sortedNumbers.last(); - -// Get subset -Set subset = sortedNumbers.headSet(5); // Elements < 5 -Set tailset = sortedNumbers.tailSet(5); // Elements >= 5 -``` - -## Map Interface - -### HashMap ```java import java.util.HashMap; import java.util.Map; -// Create HashMap Map scores = new HashMap<>(); - -// Put key-value pairs -scores.put("Alice", 85); -scores.put("Bob", 92); +scores.put("Alice", 92); +scores.put("Bob", 85); scores.put("Charlie", 78); -// Get value by key -Integer aliceScore = scores.get("Alice"); - -// Check if key exists -boolean hasAlice = scores.containsKey("Alice"); +System.out.println(scores.get("Bob")); // 85 +System.out.println(scores.containsKey("Alice")); // true +scores.put("Bob", 90); // update existing key -// Check if value exists -boolean hasScore92 = scores.containsValue(92); - -// Get all keys -Set keys = scores.keySet(); - -// Get all values -Collection values = scores.values(); - -// Get all entries -Set> entries = scores.entrySet(); - -// Iterate over entries +// Iterate entries for (Map.Entry entry : scores.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } -// Remove entry -scores.remove("Bob"); - -// Replace value -scores.replace("Alice", 90); - -// Get or default -Integer score = scores.getOrDefault("David", 0); - -// Put if absent -scores.putIfAbsent("David", 88); +// Helpful methods +scores.getOrDefault("Dave", 0); // 0 (Dave doesn't exist) +scores.putIfAbsent("Eve", 88); // only adds if key absent ``` -### TreeMap -```java -import java.util.TreeMap; - -// Create TreeMap (sorted by key) -TreeMap sortedScores = new TreeMap<>(); - -// Add elements (automatically sorted by key) -sortedScores.put("Charlie", 78); -sortedScores.put("Alice", 85); -sortedScores.put("Bob", 92); - -// Get first and last keys -String firstKey = sortedScores.firstKey(); -String lastKey = sortedScores.lastKey(); - -// Get submap -Map submap = sortedScores.subMap("Alice", "Charlie"); -``` +### 4. Queue and Deque -## Queue Interface - -### LinkedList as Queue ```java +import java.util.ArrayDeque; import java.util.Queue; -import java.util.LinkedList; - -// Create Queue -Queue queue = new LinkedList<>(); - -// Add elements -queue.offer("First"); -queue.offer("Second"); -queue.offer("Third"); -// Peek at front element (without removing) -String front = queue.peek(); +Queue queue = new ArrayDeque<>(); +queue.offer("Task 1"); // add to back +queue.offer("Task 2"); +queue.offer("Task 3"); -// Remove and return front element -String removed = queue.poll(); - -// Check if empty -boolean empty = queue.isEmpty(); - -// Get size -int size = queue.size(); +System.out.println(queue.peek()); // Task 1 (look without removing) +System.out.println(queue.poll()); // Task 1 (remove from front) +System.out.println(queue.size()); // 2 ``` -### PriorityQueue -```java -import java.util.PriorityQueue; +### 5. Collections Utility Methods -// Create PriorityQueue (sorted) -PriorityQueue pq = new PriorityQueue<>(); - -// Add elements -pq.offer(5); -pq.offer(2); -pq.offer(8); -pq.offer(1); - -// Elements are automatically sorted -while (!pq.isEmpty()) { - System.out.println(pq.poll()); // Prints in sorted order -} -``` - -## Stack - -### Stack Class -```java -import java.util.Stack; - -// Create Stack -Stack stack = new Stack<>(); - -// Push elements -stack.push("First"); -stack.push("Second"); -stack.push("Third"); - -// Peek at top element -String top = stack.peek(); - -// Pop top element -String popped = stack.pop(); - -// Check if empty -boolean empty = stack.isEmpty(); - -// Search for element -int position = stack.search("First"); -``` - -## Collections Utility Class - -### Sorting and Searching ```java import java.util.Collections; import java.util.List; -import java.util.ArrayList; -// Create list -List numbers = new ArrayList<>(); -numbers.add(5); -numbers.add(2); -numbers.add(8); -numbers.add(1); +List nums = new ArrayList<>(List.of(5, 2, 8, 1, 9)); +Collections.sort(nums); // [1, 2, 5, 8, 9] +Collections.reverse(nums); // [9, 8, 5, 2, 1] +Collections.shuffle(nums); // random order +int max = Collections.max(nums); +int min = Collections.min(nums); +``` -// Sort list -Collections.sort(numbers); +## Full Example -// Reverse list -Collections.reverse(numbers); +```java +import java.util.*; -// Shuffle list -Collections.shuffle(numbers); +public class CollectionsDemo { + public static void main(String[] args) { + // Word frequency counter + String text = "the cat sat on the mat the cat sat"; + String[] words = text.split(" "); -// Binary search (list must be sorted) -int index = Collections.binarySearch(numbers, 5); + Map freq = new LinkedHashMap<>(); + for (String word : words) { + freq.put(word, freq.getOrDefault(word, 0) + 1); + } -// Find max and min -int max = Collections.max(numbers); -int min = Collections.min(numbers); + System.out.println("Word frequencies:"); + freq.forEach((word, count) -> + System.out.printf(" %-8s: %d%n", word, count)); -// Fill list with value -Collections.fill(numbers, 0); + // Unique words sorted + Set unique = new TreeSet<>(freq.keySet()); + System.out.println("\nUnique words (sorted): " + unique); -// Create unmodifiable list -List unmodifiable = Collections.unmodifiableList(numbers); -``` + // Top 3 most frequent + List> entries = new ArrayList<>(freq.entrySet()); + entries.sort((a, b) -> b.getValue() - a.getValue()); -### Synchronized Collections -```java -// Create synchronized collections -List syncList = Collections.synchronizedList(new ArrayList<>()); -Set syncSet = Collections.synchronizedSet(new HashSet<>()); -Map syncMap = Collections.synchronizedMap(new HashMap<>()); - -// Must use synchronized block when iterating -synchronized (syncList) { - for (String item : syncList) { - System.out.println(item); + System.out.println("\nTop 3 most frequent:"); + entries.stream().limit(3).forEach(e -> + System.out.println(" " + e.getKey() + " x" + e.getValue())); } } ``` -## Custom Objects in Collections - -### Comparable Interface -```java -public class Person implements Comparable { - private String name; - private int age; - - public Person(String name, int age) { - this.name = name; - this.age = age; - } - - @Override - public int compareTo(Person other) { - return this.name.compareTo(other.name); // Sort by name - } - - @Override - public String toString() { - return name + " (" + age + ")"; - } - - // Getters - public String getName() { return name; } - public int getAge() { return age; } -} - -// Using in collections -List people = new ArrayList<>(); -people.add(new Person("Alice", 30)); -people.add(new Person("Bob", 25)); -people.add(new Person("Charlie", 35)); - -// Sort using natural ordering -Collections.sort(people); +**Expected output:** ``` - -### Comparator Interface -```java -import java.util.Comparator; - -// Custom comparator -class AgeComparator implements Comparator { - @Override - public int compare(Person p1, Person p2) { - return Integer.compare(p1.getAge(), p2.getAge()); - } -} - -// Using comparator -List people = new ArrayList<>(); -// ... add people - -// Sort by age using comparator -Collections.sort(people, new AgeComparator()); - -// Lambda comparator (Java 8+) -Collections.sort(people, (p1, p2) -> Integer.compare(p1.getAge(), p2.getAge())); +Word frequencies: + the : 3 + cat : 2 + sat : 2 + on : 1 + mat : 1 + +Unique words (sorted): [cat, mat, on, sat, the] + +Top 3 most frequent: + the x3 + cat x2 + sat x2 ``` -## Examples +## Exercise -### Collection Examples -```java -import java.util.*; +1. Write a program that reads 10 integers from the user and uses a `Set` to find duplicates. +2. Implement a simple phone book using `TreeMap` (name → phone number) with add, remove, and search operations. +3. Use a `Queue` (ArrayDeque) to simulate a print spooler that processes jobs in order. -public class CollectionExamples { - public static void main(String[] args) { - // List example - List fruits = new ArrayList<>(); - fruits.add("Apple"); - fruits.add("Banana"); - fruits.add("Orange"); - fruits.add("Apple"); // Duplicate allowed - - System.out.println("List:"); - for (String fruit : fruits) { - System.out.println(fruit); - } - - // Set example - Set uniqueFruits = new HashSet<>(); - uniqueFruits.add("Apple"); - uniqueFruits.add("Banana"); - uniqueFruits.add("Orange"); - uniqueFruits.add("Apple"); // Duplicate ignored - - System.out.println("\nSet:"); - for (String fruit : uniqueFruits) { - System.out.println(fruit); - } - - // Map example - Map fruitPrices = new HashMap<>(); - fruitPrices.put("Apple", 50); - fruitPrices.put("Banana", 30); - fruitPrices.put("Orange", 40); - - System.out.println("\nMap:"); - for (Map.Entry entry : fruitPrices.entrySet()) { - System.out.println(entry.getKey() + ": $" + entry.getValue()); - } - - // Queue example - Queue queue = new LinkedList<>(); - queue.offer("First"); - queue.offer("Second"); - queue.offer("Third"); - - System.out.println("\nQueue:"); - while (!queue.isEmpty()) { - System.out.println("Processing: " + queue.poll()); - } - - // Stack example - Stack stack = new Stack<>(); - stack.push("First"); - stack.push("Second"); - stack.push("Third"); - - System.out.println("\nStack:"); - while (!stack.isEmpty()) { - System.out.println("Popping: " + stack.pop()); - } - } -} -``` +## Checkpoint + +You are ready for the next lesson when you can: +- Explain the difference between List, Set, and Map +- Choose between HashMap and TreeMap +- Iterate a Map using `entrySet()` -## Best Practices -- Choose the right collection type for your needs -- Use ArrayList for random access, LinkedList for frequent insertions/deletions -- Use HashSet for uniqueness, TreeSet for sorted unique elements -- Use HashMap for key-value pairs, TreeMap for sorted keys -- Use generics for type safety -- Consider memory usage for large collections -- Use enhanced for loop for iteration -- Use Collections utility class for common operations -- Implement equals() and hashCode() for custom objects -- Use appropriate initial capacity for better performance \ No newline at end of file +--- +**Next:** Lesson 04 — Exception Handling diff --git a/data/Java/data/02-intermediate/04-exceptions.md b/data/Java/data/02-intermediate/04-exceptions.md index 636742f2..97ae24fd 100644 --- a/data/Java/data/02-intermediate/04-exceptions.md +++ b/data/Java/data/02-intermediate/04-exceptions.md @@ -2,494 +2,185 @@ **Module 02 · Intermediate · Lesson 04 of 06** -# Java Exception Handling +## Learning Objectives -## Exception Basics +- Use try-catch-finally to handle exceptions +- Distinguish checked vs unchecked exceptions +- Create and throw custom exceptions -### Try-Catch Block -```java -public class BasicException { - public static void main(String[] args) { - try { - int result = 10 / 0; // This will throw ArithmeticException - System.out.println("Result: " + result); - } catch (ArithmeticException e) { - System.out.println("Cannot divide by zero: " + e.getMessage()); - } - - try { - String str = null; - int length = str.length(); // This will throw NullPointerException - } catch (NullPointerException e) { - System.out.println("Null reference: " + e.getMessage()); - } - - try { - int[] numbers = {1, 2, 3}; - int value = numbers[5]; // This will throw ArrayIndexOutOfBoundsException - } catch (ArrayIndexOutOfBoundsException e) { - System.out.println("Array index out of bounds: " + e.getMessage()); - } - } -} -``` +## Overview + +When something goes wrong at runtime (dividing by zero, file not found, invalid input), Java throws an **exception** — an object describing what went wrong. If not caught, the program crashes with a stack trace. Proper exception handling makes programs robust and user-friendly. + +## Key Concepts + +### 1. The Exception Hierarchy -### Multiple Catch Blocks -```java -public class MultipleCatch { - public static void main(String[] args) { - try { - String[] args2 = {"10", "abc", "0"}; - int a = Integer.parseInt(args2[0]); - int b = Integer.parseInt(args2[1]); - int result = a / b; - System.out.println("Result: " + result); - } catch (ArrayIndexOutOfBoundsException e) { - System.out.println("Please provide 2 arguments"); - } catch (NumberFormatException e) { - System.out.println("Invalid number format: " + e.getMessage()); - } catch (ArithmeticException e) { - System.out.println("Cannot divide by zero"); - } - } -} ``` +Throwable +├── Error (JVM problems — don't catch these: OutOfMemoryError) +└── Exception + ├── RuntimeException (unchecked — not required to handle) + │ ├── NullPointerException + │ ├── ArrayIndexOutOfBoundsException + │ ├── ClassCastException + │ └── NumberFormatException + └── IOException (checked — must handle or declare) + ├── FileNotFoundException + └── ... +``` + +### 2. try-catch-finally -### Finally Block ```java -public class FinallyBlock { - public static void main(String[] args) { - try { - System.out.println("In try block"); - int result = 10 / 2; - System.out.println("Result: " + result); - } catch (Exception e) { - System.out.println("In catch block: " + e.getMessage()); - } finally { - System.out.println("In finally block - always executes"); - } - - // Example with exception - try { - System.out.println("\nIn try block"); - int result = 10 / 0; - System.out.println("Result: " + result); - } catch (Exception e) { - System.out.println("In catch block: " + e.getMessage()); - } finally { - System.out.println("In finally block - always executes"); - } - } +try { + int result = 10 / 0; // throws ArithmeticException +} catch (ArithmeticException e) { + System.out.println("Cannot divide by zero: " + e.getMessage()); +} finally { + System.out.println("This always runs — cleanup here"); } ``` -## Custom Exceptions +### 3. Multiple catch Blocks -### Creating Custom Exceptions ```java -// Custom exception class -public class InvalidAgeException extends Exception { - public InvalidAgeException(String message) { - super(message); - } +try { + String s = null; + System.out.println(s.length()); // NullPointerException + int n = Integer.parseInt("abc"); // NumberFormatException +} catch (NullPointerException e) { + System.out.println("Null value: " + e.getMessage()); +} catch (NumberFormatException e) { + System.out.println("Bad number format: " + e.getMessage()); +} catch (Exception e) { + System.out.println("Unexpected error: " + e.getMessage()); } +``` -// Another custom exception -public class InsufficientFundsException extends Exception { - private double amount; - private double balance; - - public InsufficientFundsException(String message, double amount, double balance) { - super(message); - this.amount = amount; - this.balance = balance; - } - - public double getAmount() { return amount; } - public double getBalance() { return balance; } -} +### 4. Multi-catch (Java 7+) -// Using custom exceptions -public class BankAccount { - private String accountNumber; - private double balance; - - public BankAccount(String accountNumber, double balance) { - this.accountNumber = accountNumber; - this.balance = balance; - } - - public void withdraw(double amount) throws InsufficientFundsException { - if (amount > balance) { - throw new InsufficientFundsException( - "Insufficient funds for withdrawal", amount, balance); - } - balance -= amount; - System.out.println("Withdrew: $" + amount); - } - - public void deposit(double amount) { - if (amount <= 0) { - throw new IllegalArgumentException("Deposit amount must be positive"); - } - balance += amount; - System.out.println("Deposited: $" + amount); - } - - public double getBalance() { return balance; } +```java +try { + // risky code +} catch (NullPointerException | NumberFormatException e) { + System.out.println("Input error: " + e.getMessage()); } ``` -### Using Custom Exceptions +### 5. Throwing Exceptions + ```java -public class CustomExceptionDemo { - public static void main(String[] args) { - BankAccount account = new BankAccount("12345", 1000.0); - - try { - account.withdraw(500.0); - account.withdraw(600.0); // This will throw exception - } catch (InsufficientFundsException e) { - System.out.println("Error: " + e.getMessage()); - System.out.println("Attempted to withdraw: $" + e.getAmount()); - System.out.println("Available balance: $" + e.getBalance()); - } - - try { - account.deposit(-100.0); // This will throw exception - } catch (IllegalArgumentException e) { - System.out.println("Error: " + e.getMessage()); - } +public static int divide(int a, int b) { + if (b == 0) { + throw new IllegalArgumentException("Divisor cannot be zero"); } + return a / b; } ``` -## Try-With-Resources +### 6. Custom Exceptions -### Auto Resource Management ```java -import java.io.*; +// Custom checked exception +public class InsufficientFundsException extends Exception { + private double amount; -public class TryWithResources { - public static void main(String[] args) { - // Traditional way - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader("file.txt")); - String line = reader.readLine(); - System.out.println(line); - } catch (IOException e) { - System.out.println("Error reading file: " + e.getMessage()); - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - System.out.println("Error closing reader: " + e.getMessage()); - } - } - } - - // Try-with-resources (Java 7+) - try (BufferedReader autoReader = new BufferedReader(new FileReader("file.txt"))) { - String line = autoReader.readLine(); - System.out.println(line); - } catch (IOException e) { - System.out.println("Error reading file: " + e.getMessage()); - } - // Reader is automatically closed - - // Multiple resources - try (BufferedReader reader1 = new BufferedReader(new FileReader("input.txt")); - BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) { - - String line; - while ((line = reader1.readLine()) != null) { - writer.write(line.toUpperCase()); - writer.newLine(); - } - } catch (IOException e) { - System.out.println("Error processing files: " + e.getMessage()); - } + public InsufficientFundsException(double amount) { + super("Insufficient funds. Short by: $" + amount); + this.amount = amount; } -} -``` -### Custom Auto-Closeable -```java -public class CustomResource implements AutoCloseable { - private String name; - private boolean isOpen; - - public CustomResource(String name) { - this.name = name; - this.isOpen = true; - System.out.println(name + " opened"); - } - - public void doSomething() { - if (!isOpen) { - throw new IllegalStateException("Resource is closed"); - } - System.out.println(name + " is doing something"); - } - - @Override - public void close() { - if (isOpen) { - isOpen = false; - System.out.println(name + " closed"); - } - } + public double getShortfall() { return amount; } } -public class CustomResourceDemo { - public static void main(String[] args) { - try (CustomResource resource = new CustomResource("MyResource")) { - resource.doSomething(); - } // Resource is automatically closed here +// Custom unchecked exception +public class InvalidAgeException extends RuntimeException { + public InvalidAgeException(int age) { + super("Invalid age: " + age + ". Must be between 0 and 150."); } } ``` -## Exception Hierarchy +### 7. try-with-resources (Java 7+) + +Automatically closes resources (files, connections) — no need for `finally`. -### Built-in Exception Types ```java -public class ExceptionHierarchy { - public static void demonstrateExceptions() { - // Checked exceptions (must be handled) - try { - Thread.sleep(1000); // InterruptedException - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - - try { - FileInputStream fis = new FileInputStream("nonexistent.txt"); // FileNotFoundException - } catch (FileNotFoundException e) { - System.out.println("File not found: " + e.getMessage()); - } - - // Unchecked exceptions (runtime exceptions) - try { - String str = null; - int length = str.length(); // NullPointerException - } catch (NullPointerException e) { - System.out.println("Null pointer: " + e.getMessage()); - } - - try { - int[] arr = new int[5]; - int value = arr[10]; // ArrayIndexOutOfBoundsException - } catch (ArrayIndexOutOfBoundsException e) { - System.out.println("Array index out of bounds: " + e.getMessage()); - } - - try { - Object obj = new String("Hello"); - Integer num = (Integer) obj; // ClassCastException - } catch (ClassCastException e) { - System.out.println("Class cast exception: " + e.getMessage()); - } +try (Scanner sc = new Scanner(new File("data.txt"))) { + while (sc.hasNextLine()) { + System.out.println(sc.nextLine()); } +} catch (FileNotFoundException e) { + System.out.println("File not found: " + e.getMessage()); } +// Scanner is automatically closed here ``` -## Exception Handling Best Practices +## Full Example -### Proper Exception Handling ```java -public class ExceptionBestPractices { - - // Handle exceptions at appropriate level - public static void readFile(String filename) { - try (BufferedReader reader = new BufferedReader(new FileReader(filename))) { - String line; - while ((line = reader.readLine()) != null) { - processLine(line); - } - } catch (FileNotFoundException e) { - System.err.println("File not found: " + filename); - // Log error and continue - } catch (IOException e) { - System.err.println("Error reading file: " + e.getMessage()); - // Log error and continue - } - } - - // Throw exceptions to caller when appropriate - public static int calculateAge(int birthYear) throws InvalidAgeException { - int currentYear = java.time.Year.now().getValue(); - int age = currentYear - birthYear; - - if (age < 0 || age > 150) { - throw new InvalidAgeException("Invalid age calculated: " + age); - } - - return age; - } - - // Use specific exceptions - public static void processData(String data) { - try { - if (data == null) { - throw new IllegalArgumentException("Data cannot be null"); - } - - int number = Integer.parseInt(data); - if (number < 0) { - throw new IllegalArgumentException("Number cannot be negative"); - } - - // Process valid data - System.out.println("Processing: " + number); - - } catch (NumberFormatException e) { - System.err.println("Invalid number format: " + data); - } - } - - // Finally block for cleanup - public static void databaseOperation() { - Connection conn = null; - try { - conn = getDatabaseConnection(); - // Perform database operations - executeQuery(conn); - } catch (SQLException e) { - System.err.println("Database error: " + e.getMessage()); - } finally { - if (conn != null) { - try { - conn.close(); - } catch (SQLException e) { - System.err.println("Error closing connection: " + e.getMessage()); - } - } - } - } - - // Helper methods (simplified) - private static Connection getDatabaseConnection() throws SQLException { - // Simulated database connection - return null; - } - - private static void executeQuery(Connection conn) throws SQLException { - // Simulated query execution - } - - private static void processLine(String line) { - // Process line - } -} -``` +public class ExceptionDemo { -## Examples + static class BankAccount { + private double balance; -### Complete Exception Handling Example -```java -import java.io.*; -import java.util.*; + public BankAccount(double balance) { this.balance = balance; } -public class CompleteExceptionExample { - public static void main(String[] args) { - try { - // Process file with numbers - List numbers = processNumberFile("numbers.txt"); - - // Calculate statistics - double average = calculateAverage(numbers); - System.out.println("Average: " + average); - - // Find max and min - int max = findMax(numbers); - int min = findMin(numbers); - System.out.println("Max: " + max + ", Min: " + min); - - } catch (FileNotFoundException e) { - System.err.println("File not found: " + e.getMessage()); - } catch (InvalidDataException e) { - System.err.println("Invalid data in file: " + e.getMessage()); - } catch (Exception e) { - System.err.println("Unexpected error: " + e.getMessage()); + public void withdraw(double amount) throws InsufficientFundsException { + if (amount <= 0) throw new IllegalArgumentException("Amount must be positive"); + if (amount > balance) throw new InsufficientFundsException(amount - balance); + balance -= amount; + System.out.printf("Withdrew $%.2f. Balance: $%.2f%n", amount, balance); } } - - public static List processNumberFile(String filename) - throws FileNotFoundException, InvalidDataException { - - List numbers = new ArrayList<>(); - - try (BufferedReader reader = new BufferedReader(new FileReader(filename))) { - String line; - int lineNumber = 0; - - while ((line = reader.readLine()) != null) { - lineNumber++; - line = line.trim(); - - // Skip empty lines - if (line.isEmpty()) continue; - - try { - int number = Integer.parseInt(line); - numbers.add(number); - } catch (NumberFormatException e) { - throw new InvalidDataException( - "Invalid number at line " + lineNumber + ": " + line); - } - } - - } catch (IOException e) { - throw new InvalidDataException("Error reading file: " + e.getMessage()); + + static class InsufficientFundsException extends Exception { + private final double shortfall; + public InsufficientFundsException(double shortfall) { + super(String.format("Need $%.2f more", shortfall)); + this.shortfall = shortfall; } - - return numbers; + public double getShortfall() { return shortfall; } } - - public static double calculateAverage(List numbers) throws InvalidDataException { - if (numbers.isEmpty()) { - throw new InvalidDataException("No numbers to calculate average"); - } - - int sum = 0; - for (int number : numbers) { - if (number < 0) { - throw new InvalidDataException("Negative number found: " + number); + + public static void main(String[] args) { + BankAccount acc = new BankAccount(500.0); + + double[] withdrawals = {100.0, 250.0, 300.0, -50.0}; + for (double amount : withdrawals) { + try { + acc.withdraw(amount); + } catch (InsufficientFundsException e) { + System.out.println("Failed: " + e.getMessage()); + } catch (IllegalArgumentException e) { + System.out.println("Invalid: " + e.getMessage()); } - sum += number; } - - return (double) sum / numbers.size(); - } - - public static int findMax(List numbers) { - return Collections.max(numbers); - } - - public static int findMin(List numbers) { - return Collections.min(numbers); } } +``` -// Custom exception -class InvalidDataException extends Exception { - public InvalidDataException(String message) { - super(message); - } -} +**Expected output:** +``` +Withdrew $100.00. Balance: $400.00 +Withdrew $250.00. Balance: $150.00 +Failed: Need $150.00 more +Invalid: Amount must be positive ``` -## Best Practices -- Handle exceptions at the appropriate level -- Use specific exceptions rather than general ones -- Use try-with-resources for automatic resource management -- Create custom exceptions for domain-specific errors -- Log exceptions with sufficient context -- Don't swallow exceptions (empty catch blocks) -- Use finally blocks for cleanup -- Document exceptions in method signatures -- Consider performance implications of exception handling -- Use exceptions for exceptional conditions, not normal flow control \ No newline at end of file +## Exercise + +1. Write a method `parseAndDivide(String a, String b)` that parses two strings as integers and divides them, handling `NumberFormatException` and `ArithmeticException`. +2. Create a `PasswordValidator` that throws a custom `WeakPasswordException` if the password is shorter than 8 characters or has no numbers. +3. Write a try-with-resources example that reads a text file line by line. + +## Checkpoint + +You are ready for the next lesson when you can: +- Explain the difference between checked and unchecked exceptions +- Write a custom exception class +- Use try-with-resources correctly + +--- +**Next:** Lesson 05 — Generics diff --git a/data/Java/data/02-intermediate/05-generics-intro.md b/data/Java/data/02-intermediate/05-generics-intro.md index 8dbcf569..bf2975ad 100644 --- a/data/Java/data/02-intermediate/05-generics-intro.md +++ b/data/Java/data/02-intermediate/05-generics-intro.md @@ -1,41 +1,194 @@ -# Lesson 05 — Generics Introduction +# Lesson 05 — Generics **Module 02 · Intermediate · Lesson 05 of 06** +## Learning Objectives -## Learning objectives - -- Understand **generics introduction** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Write generic classes and methods +- Use bounded type parameters (`extends`, `super`) +- Understand wildcards `` ## Overview -Generics Introduction is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. +**Generics** let you write code that works with any type while keeping **compile-time type safety**. Instead of writing a `StringBox`, `IntBox`, and `DoublBox` separately, you write one `Box` that works for all. This is how all Java collections (like `ArrayList`) are built. + +## Key Concepts + +### 1. Generic Class + +```java +public class Box { + private T value; + + public Box(T value) { this.value = value; } + public T getValue() { return value; } + public void setValue(T value) { this.value = value; } + + @Override + public String toString() { return "Box[" + value + "]"; } +} + +// Usage: +Box strBox = new Box<>("Hello"); +Box intBox = new Box<>(42); +Box dblBox = new Box<>(3.14); + +System.out.println(strBox.getValue().toUpperCase()); // HELLO +System.out.println(intBox.getValue() * 2); // 84 +``` + +### 2. Multiple Type Parameters -## Key concepts +```java +public class Pair { + private A first; + private B second; -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes + public Pair(A first, B second) { this.first = first; this.second = second; } + public A getFirst() { return first; } + public B getSecond() { return second; } -## Example + @Override + public String toString() { return "(" + first + ", " + second + ")"; } +} + +Pair person = new Pair<>("Alice", 30); +System.out.println(person); // (Alice, 30) +``` + +### 3. Generic Methods ```java -// Generics Introduction — practice sketch -// add your code here +public static T getMiddle(T[] array) { + return array[array.length / 2]; +} + +String[] names = {"Alice", "Bob", "Charlie", "Dave"}; +System.out.println(getMiddle(names)); // Bob + +Integer[] nums = {10, 20, 30, 40, 50}; +System.out.println(getMiddle(nums)); // 30 +``` + +### 4. Bounded Type Parameters + +Restrict `T` to a specific type or its subtypes: + +```java +// T must be a Number or subclass (Integer, Double, etc.) +public static double sum(List list) { + double total = 0; + for (T item : list) { + total += item.doubleValue(); + } + return total; +} + +System.out.println(sum(List.of(1, 2, 3, 4, 5))); // 15.0 +System.out.println(sum(List.of(1.1, 2.2, 3.3))); // 6.6 +// sum(List.of("a", "b")); ← compile error! String is not a Number +``` + +### 5. Wildcards + +```java +// Unknown type — read-only +public static void printList(List list) { + for (Object item : list) System.out.println(item); +} + +// Upper bound wildcard — anything extending Number +public static double sumList(List list) { + double total = 0; + for (Number n : list) total += n.doubleValue(); + return total; +} + +// Lower bound wildcard — Number or its supertypes +public static void addNumbers(List list) { + list.add(10); + list.add(20); +} +``` + +## Full Example + +```java +import java.util.ArrayList; +import java.util.List; + +public class GenericsDemo { + // Generic stack implementation + static class Stack { + private List items = new ArrayList<>(); + + public void push(T item) { items.add(item); } + + public T pop() { + if (isEmpty()) throw new RuntimeException("Stack is empty"); + return items.remove(items.size() - 1); + } + + public T peek() { + if (isEmpty()) throw new RuntimeException("Stack is empty"); + return items.get(items.size() - 1); + } + + public boolean isEmpty() { return items.isEmpty(); } + public int size() { return items.size(); } + + @Override + public String toString() { return items.toString(); } + } + + // Generic method with bound + static > T findMax(List list) { + T max = list.get(0); + for (T item : list) { + if (item.compareTo(max) > 0) max = item; + } + return max; + } + + public static void main(String[] args) { + // String stack + Stack history = new Stack<>(); + history.push("page1.html"); + history.push("page2.html"); + history.push("page3.html"); + System.out.println("History: " + history); + System.out.println("Back: " + history.pop()); + System.out.println("Current: " + history.peek()); + + // Generic findMax + System.out.println("\nMax int: " + findMax(List.of(3, 7, 1, 9, 4))); + System.out.println("Max str: " + findMax(List.of("banana", "apple", "cherry"))); + } +} +``` + +**Expected output:** +``` +History: [page1.html, page2.html, page3.html] +Back: page3.html +Current: page2.html + +Max int: 9 +Max str: cherry ``` ## Exercise -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). +1. Create a generic `Result` class that holds either a value or an error message (like Kotlin's Result type). It should have methods `isSuccess()`, `getValue()`, `getError()`. +2. Write a generic `swap(T[] array, int i, int j)` method that swaps two elements. +3. Write a bounded generic method `> List filterGreaterThan(List list, T threshold)`. ## Checkpoint -You are ready for the next lesson when you can solve the exercise without copying the example. +You are ready for the next lesson when you can: +- Write a generic class with a type parameter +- Explain what `>` means +- Describe when to use `? extends` vs `? super` --- - -**Next:** Continue to lesson 06 in this module. +**Next:** Lesson 06 — File I/O diff --git a/data/Java/data/02-intermediate/06-file-io.md b/data/Java/data/02-intermediate/06-file-io.md index ae0c2226..ff51db07 100644 --- a/data/Java/data/02-intermediate/06-file-io.md +++ b/data/Java/data/02-intermediate/06-file-io.md @@ -2,40 +2,187 @@ **Module 02 · Intermediate · Lesson 06 of 06** +## Learning Objectives -## Learning objectives - -- Understand **file i/o** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Read and write text files using `BufferedReader` / `BufferedWriter` +- Use the modern `Files` API (Java 11+) +- Handle file exceptions correctly ## Overview -File I/O is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. +Real applications constantly read config files, write logs, and process data files. Java provides two approaches: the classic `java.io` streams and the modern `java.nio.file.Files` API. The modern API is simpler for most tasks. + +## Key Concepts + +### 1. Writing a File (Modern API) + +```java +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +Path file = Path.of("students.txt"); + +List lines = List.of( + "Alice, 92", + "Bob, 85", + "Charlie, 78" +); + +Files.write(file, lines); // creates or overwrites the file +System.out.println("File written: " + file.toAbsolutePath()); +``` + +### 2. Reading a File (Modern API) + +```java +// Read all lines at once +List lines = Files.readAllLines(Path.of("students.txt")); +for (String line : lines) { + System.out.println(line); +} + +// Read entire file as a single String (Java 11+) +String content = Files.readString(Path.of("students.txt")); +System.out.println(content); +``` + +### 3. Appending to a File + +```java +import java.nio.file.StandardOpenOption; + +Files.writeString( + Path.of("log.txt"), + "New log entry\n", + StandardOpenOption.CREATE, + StandardOpenOption.APPEND +); +``` + +### 4. Classic BufferedReader / BufferedWriter -## Key concepts +Useful for large files — reads line by line without loading everything into memory. -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes +```java +import java.io.*; + +// Writing +try (BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) { + writer.write("Line 1"); + writer.newLine(); + writer.write("Line 2"); +} + +// Reading +try (BufferedReader reader = new BufferedReader(new FileReader("output.txt"))) { + String line; + while ((line = reader.readLine()) != null) { + System.out.println(line); + } +} +``` -## Example +### 5. Checking and Managing Files ```java -// File I/O — practice sketch -// add your code here +Path p = Path.of("data.txt"); + +Files.exists(p); // does it exist? +Files.isReadable(p); // can we read it? +Files.size(p); // size in bytes +Files.delete(p); // delete it +Files.copy(p, Path.of("backup.txt")); // copy +Files.move(p, Path.of("archive/data.txt")); // move/rename +``` + +### 6. Working with Directories + +```java +Path dir = Path.of("reports"); +Files.createDirectories(dir); // create dir (and parents) + +// List all files in a directory +Files.list(dir).forEach(System.out::println); + +// Walk entire directory tree +Files.walk(dir) + .filter(f -> f.toString().endsWith(".txt")) + .forEach(System.out::println); +``` + +## Full Example + +```java +import java.io.*; +import java.nio.file.*; +import java.util.*; + +public class FileIODemo { + record Student(String name, int score) {} + + public static void main(String[] args) throws IOException { + Path file = Path.of("scores.csv"); + + // 1. Write CSV + List students = List.of( + new Student("Alice", 92), + new Student("Bob", 85), + new Student("Charlie", 78), + new Student("Diana", 96) + ); + + try (BufferedWriter bw = Files.newBufferedWriter(file)) { + bw.write("name,score"); + bw.newLine(); + for (Student s : students) { + bw.write(s.name() + "," + s.score()); + bw.newLine(); + } + } + System.out.println("Written to: " + file.toAbsolutePath()); + + // 2. Read back and parse + System.out.println("\n--- Student Report ---"); + int total = 0, count = 0; + List lines = Files.readAllLines(file); + for (int i = 1; i < lines.size(); i++) { // skip header + String[] parts = lines.get(i).split(","); + String name = parts[0]; + int score = Integer.parseInt(parts[1]); + total += score; + count++; + System.out.printf("%-10s %d%n", name, score); + } + System.out.printf("Average: %.1f%n", (double) total / count); + } +} +``` + +**Expected output:** +``` +Written to: /home/user/scores.csv + +--- Student Report --- +Alice 92 +Bob 85 +Charlie 78 +Diana 96 +Average: 87.8 ``` ## Exercise -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). +1. Write a program that reads a `.txt` file and counts the number of lines, words, and characters (like the Unix `wc` command). +2. Write a simple CSV parser that reads a file of `name,age,city` records and prints only rows where age > 25. +3. Create a `Logger` class with a method `log(String message)` that appends a timestamped line to `app.log`. ## Checkpoint -You are ready for the next lesson when you can solve the exercise without copying the example. +You are ready for Module 03 when you can: +- Write and read files using both the classic and modern APIs +- Append to an existing file without overwriting it +- Use try-with-resources to safely close file handles --- - -**Next:** Continue to lesson 07 in this module. +**Module 02 Complete!** You are ready for **Module 03 — Advanced Java**. diff --git a/data/Java/data/03-advanced/01-streams-api.md b/data/Java/data/03-advanced/01-streams-api.md index 0d5436ec..6dfaf2f7 100644 --- a/data/Java/data/03-advanced/01-streams-api.md +++ b/data/Java/data/03-advanced/01-streams-api.md @@ -1,41 +1,203 @@ # Lesson 01 — Streams API -**Module 03 · Advanced · Lesson 01 of 07** +**Module 03 · Advanced · Lesson 01 of 10** +## Learning Objectives -## Learning objectives - -- Understand **streams api** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Build stream pipelines with `filter`, `map`, `sorted`, `reduce`, and `collect` +- Understand the difference between intermediate and terminal operations +- Use `Collectors` to group and summarise data ## Overview -Streams API is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. +The **Stream API** (Java 8+) lets you process collections declaratively — describing *what* you want rather than *how* to do it. A stream pipeline is: **source → intermediate operations → terminal operation**. Streams don't modify the original collection; they produce new values. + +## Key Concepts + +### 1. Creating Streams + +```java +import java.util.stream.*; + +// From a collection +List names = List.of("Alice", "Bob", "Charlie"); +Stream stream = names.stream(); + +// From values directly +Stream nums = Stream.of(1, 2, 3, 4, 5); + +// Infinite stream +Stream evens = Stream.iterate(0, n -> n + 2); // 0, 2, 4, 6... + +// IntStream for primitives (no boxing overhead) +IntStream range = IntStream.rangeClosed(1, 10); // 1 to 10 inclusive +``` + +### 2. Intermediate Operations (lazy — return a new Stream) + +```java +List names = List.of("Alice", "Bob", "Charlie", "Anna", "Brian"); + +names.stream() + .filter(n -> n.startsWith("A")) // keep only names starting with A + .map(String::toUpperCase) // transform each + .sorted() // sort alphabetically + .forEach(System.out::println); +// Output: +// ALICE +// ANNA +``` + +| Operation | What it does | +|-----------|-------------| +| `filter(predicate)` | Keep elements matching condition | +| `map(function)` | Transform each element | +| `mapToInt/Double/Long` | Map to primitive stream | +| `sorted()` / `sorted(comparator)` | Sort elements | +| `distinct()` | Remove duplicates | +| `limit(n)` | Take first n elements | +| `skip(n)` | Skip first n elements | +| `peek(consumer)` | Debug — inspect without changing | + +### 3. Terminal Operations (trigger execution) + +```java +List numbers = List.of(3, 1, 4, 1, 5, 9, 2, 6); + +long count = numbers.stream().filter(n -> n > 3).count(); // 4 +int sum = numbers.stream().mapToInt(Integer::intValue).sum(); // 31 +int max = numbers.stream().mapToInt(Integer::intValue).max().getAsInt(); // 9 +boolean any = numbers.stream().anyMatch(n -> n > 8); // true +boolean all = numbers.stream().allMatch(n -> n > 0); // true +List sorted = numbers.stream().sorted().collect(Collectors.toList()); +``` + +### 4. collect() and Collectors -## Key concepts +```java +import java.util.stream.Collectors; + +List names = List.of("Alice", "Bob", "Charlie", "Anna"); + +// To List +List result = names.stream() + .filter(n -> n.length() > 3) + .collect(Collectors.toList()); // [Alice, Charlie, Anna] + +// To Map +Map> byLength = names.stream() + .collect(Collectors.groupingBy(String::length)); +// {5=[Alice, Anna (4)...], actually: {5=[Alice], 3=[Bob], 7=[Charlie], 4=[Anna]} + +// Joining +String joined = names.stream() + .collect(Collectors.joining(", ", "[", "]")); +// [Alice, Bob, Charlie, Anna] + +// Counting per group +Map countByLength = names.stream() + .collect(Collectors.groupingBy(String::length, Collectors.counting())); +``` + +### 5. reduce() + +```java +// Sum using reduce +int sum = IntStream.rangeClosed(1, 100).reduce(0, Integer::sum); // 5050 -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes +// Factorial +int factorial = IntStream.rangeClosed(1, 5).reduce(1, (a, b) -> a * b); // 120 +``` + +### 6. flatMap() + +Flattens a stream of streams into one stream: + +```java +List> nested = List.of( + List.of(1, 2, 3), + List.of(4, 5), + List.of(6, 7, 8, 9) +); + +List flat = nested.stream() + .flatMap(Collection::stream) + .collect(Collectors.toList()); +// [1, 2, 3, 4, 5, 6, 7, 8, 9] +``` -## Example +## Full Example ```java -// Streams API — practice sketch -// add your code here +import java.util.*; +import java.util.stream.*; + +public class StreamsDemo { + record Employee(String name, String dept, double salary) {} + + public static void main(String[] args) { + List employees = List.of( + new Employee("Alice", "Engineering", 95000), + new Employee("Bob", "Marketing", 72000), + new Employee("Charlie", "Engineering", 88000), + new Employee("Diana", "HR", 65000), + new Employee("Eve", "Engineering", 105000), + new Employee("Frank", "Marketing", 78000) + ); + + // Average salary per department + System.out.println("=== Avg Salary by Department ==="); + employees.stream() + .collect(Collectors.groupingBy(Employee::dept, + Collectors.averagingDouble(Employee::salary))) + .forEach((dept, avg) -> + System.out.printf("%-15s $%.0f%n", dept, avg)); + + // Top 3 earners + System.out.println("\n=== Top 3 Earners ==="); + employees.stream() + .sorted(Comparator.comparingDouble(Employee::salary).reversed()) + .limit(3) + .forEach(e -> System.out.printf("%-10s $%.0f%n", e.name(), e.salary())); + + // All Engineering employees earning > $90k + System.out.println("\n=== Senior Engineers (>$90k) ==="); + employees.stream() + .filter(e -> e.dept().equals("Engineering") && e.salary() > 90000) + .map(Employee::name) + .collect(Collectors.joining(", ")); + } +} +``` + +**Expected output:** +``` +=== Avg Salary by Department === +Engineering $96000 +Marketing $75000 +HR $65000 + +=== Top 3 Earners === +Eve $105000 +Alice $95000 +Charlie $88000 + +=== Senior Engineers (>$90k) === +Alice, Eve ``` ## Exercise -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). +1. Given a list of integers, use streams to find all perfect squares, double them, and collect into a sorted list. +2. Given a list of sentences, use `flatMap` to get a frequency map of all words. +3. Given a list of `Product(name, category, price)`, group by category and find the most expensive product per category. ## Checkpoint -You are ready for the next lesson when you can solve the exercise without copying the example. +You are ready for the next lesson when you can: +- Build a 3-stage stream pipeline from memory +- Use `groupingBy` with a downstream collector +- Explain why intermediate operations are lazy --- - -**Next:** Continue to lesson 02 in this module. +**Next:** Lesson 02 — Lambda Expressions and Functional Interfaces diff --git a/data/Java/data/03-advanced/02-lambdas-functional.md b/data/Java/data/03-advanced/02-lambdas-functional.md new file mode 100644 index 00000000..46e95b09 --- /dev/null +++ b/data/Java/data/03-advanced/02-lambdas-functional.md @@ -0,0 +1,207 @@ +# Lesson 02 — Lambda Expressions and Functional Interfaces + +**Module 03 · Advanced · Lesson 02 of 10** + +## Learning Objectives + +- Write lambda expressions for common functional interfaces +- Use `Function`, `Predicate`, `Consumer`, `Supplier`, and `BiFunction` +- Chain functions with `andThen`, `compose`, and `and`/`or` + +## Overview + +A **lambda expression** is a short, anonymous function you can pass around like a value. Combined with **functional interfaces** (interfaces with one abstract method), lambdas let you write concise, expressive code — no need to create a separate class just to pass behaviour. + +## Key Concepts + +### 1. Lambda Syntax + +```java +// Full form +(int a, int b) -> { return a + b; } + +// Inferred types +(a, b) -> { return a + b; } + +// Single expression (return is implicit) +(a, b) -> a + b + +// Single parameter (parentheses optional) +name -> name.toUpperCase() + +// No parameters +() -> System.out.println("Hello!") +``` + +### 2. Built-in Functional Interfaces (`java.util.function`) + +| Interface | Signature | Use | +|-----------|-----------|-----| +| `Predicate` | `T → boolean` | Test a condition | +| `Function` | `T → R` | Transform a value | +| `Consumer` | `T → void` | Use a value, no return | +| `Supplier` | `() → T` | Provide a value | +| `BiFunction` | `T,U → R` | Two inputs, one output | +| `UnaryOperator` | `T → T` | Transform, same type | +| `BinaryOperator` | `T,T → T` | Combine two same-type values | + +### 3. Predicate + +```java +import java.util.function.Predicate; + +Predicate isLong = s -> s.length() > 5; +Predicate startsA = s -> s.startsWith("A"); + +System.out.println(isLong.test("Hello")); // false +System.out.println(isLong.test("Hello World")); // true + +// Compose predicates +Predicate longAndA = isLong.and(startsA); +Predicate longOrA = isLong.or(startsA); +Predicate notLong = isLong.negate(); + +System.out.println(longAndA.test("Alexander")); // true +``` + +### 4. Function and Chaining + +```java +import java.util.function.Function; + +Function strLen = String::length; +Function intToStr = n -> "Length: " + n; + +// andThen: apply strLen, then intToStr +Function combined = strLen.andThen(intToStr); +System.out.println(combined.apply("Hello")); // Length: 5 + +// compose: apply intToStr first, then strLen (opposite order) +``` + +### 5. Consumer + +```java +import java.util.function.Consumer; + +Consumer print = System.out::println; +Consumer shout = s -> System.out.println(s.toUpperCase()); + +// Chain consumers +Consumer both = print.andThen(shout); +both.accept("hello"); +// hello +// HELLO +``` + +### 6. Supplier + +```java +import java.util.function.Supplier; + +Supplier greeting = () -> "Good morning!"; +Supplier random = Math::random; + +System.out.println(greeting.get()); // Good morning! +System.out.println(random.get()); // 0.7364... +``` + +### 7. Method References + +Shorthand for lambdas that just call an existing method: + +```java +// Static method +Function parse = Integer::parseInt; + +// Instance method on parameter +Function upper = String::toUpperCase; + +// Instance method on specific object +String prefix = "Hello, "; +Function greet = prefix::concat; + +// Constructor reference +Supplier> listFactory = ArrayList::new; +``` + +## Full Example + +```java +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +public class LambdaDemo { + // Higher-order function: takes a function as parameter + static List transform(List list, Function fn) { + return list.stream().map(fn).collect(Collectors.toList()); + } + + static List filter(List list, Predicate predicate) { + return list.stream().filter(predicate).collect(Collectors.toList()); + } + + static void process(List list, Consumer action) { + list.forEach(action); + } + + public static void main(String[] args) { + List names = List.of("Alice", "Bob", "Charlie", "Anna", "Brian"); + + // Transform: names → lengths + List lengths = transform(names, String::length); + System.out.println("Lengths: " + lengths); + + // Filter: names starting with A + List aNames = filter(names, n -> n.startsWith("A")); + System.out.println("A names: " + aNames); + + // Compose predicates + Predicate longName = n -> n.length() > 4; + Predicate startsB = n -> n.startsWith("B"); + List special = filter(names, longName.or(startsB)); + System.out.println("Long or B: " + special); + + // Consumer chain + Consumer upper = s -> System.out.print(s.toUpperCase()); + Consumer comma = s -> System.out.print(", "); + process(aNames, upper.andThen(comma)); + System.out.println(); + + // Function pipeline + Function clean = String::trim; + Function titleCase = s -> + Character.toUpperCase(s.charAt(0)) + s.substring(1).toLowerCase(); + Function pipeline = clean.andThen(titleCase); + + List messy = List.of(" alice ", "BOB", " CHARLIE"); + System.out.println(transform(messy, pipeline)); + } +} +``` + +**Expected output:** +``` +Lengths: [5, 3, 7, 4, 5] +A names: [Alice, Anna] +Long or B: [Alice, Charlie, Brian] +ALICE, ANNA, +[Alice, Bob, Charlie] +``` + +## Exercise + +1. Write a method `applyTwice(Function f, T value)` that applies a function to a value twice. +2. Build a validation pipeline for a registration form: check that a username is non-null, length ≥ 3, and contains only letters using composed `Predicate`s. +3. Create a `BiFunction, Predicate, Map>>` that partitions a list into matching and non-matching elements. + +## Checkpoint + +You are ready for the next lesson when you can: +- Write all 5 core functional interfaces from memory +- Chain predicates with `and`, `or`, `negate` +- Use method references for static, instance, and constructor calls + +--- +**Next:** Lesson 03 — Multithreading and Concurrency diff --git a/data/Java/data/03-advanced/02-multithreading.md b/data/Java/data/03-advanced/03-multithreading.md similarity index 92% rename from data/Java/data/03-advanced/02-multithreading.md rename to data/Java/data/03-advanced/03-multithreading.md index 5e329faf..4ead2e7b 100644 --- a/data/Java/data/03-advanced/02-multithreading.md +++ b/data/Java/data/03-advanced/03-multithreading.md @@ -1,6 +1,6 @@ -# Lesson 02 — Multithreading Basics +# Lesson 03 — Multithreading Basics -**Module 03 · Advanced · Lesson 02 of 07** +**Module 03 · Advanced · Lesson 03 of 10** ## Learning objectives diff --git a/data/Java/data/03-advanced/03-lambdas.md b/data/Java/data/03-advanced/04-lambdas.md similarity index 92% rename from data/Java/data/03-advanced/03-lambdas.md rename to data/Java/data/03-advanced/04-lambdas.md index 3c6f180e..78bc7efb 100644 --- a/data/Java/data/03-advanced/03-lambdas.md +++ b/data/Java/data/03-advanced/04-lambdas.md @@ -1,6 +1,6 @@ -# Lesson 03 — Lambda Expressions +# Lesson 04 — Lambda Expressions -**Module 03 · Advanced · Lesson 03 of 07** +**Module 03 · Advanced · Lesson 04 of 10** ## Learning objectives diff --git a/data/Java/data/03-advanced/04-jdbc-basics.md b/data/Java/data/03-advanced/05-jdbc-basics.md similarity index 92% rename from data/Java/data/03-advanced/04-jdbc-basics.md rename to data/Java/data/03-advanced/05-jdbc-basics.md index 459bb7a6..8a3b91fc 100644 --- a/data/Java/data/03-advanced/04-jdbc-basics.md +++ b/data/Java/data/03-advanced/05-jdbc-basics.md @@ -1,6 +1,6 @@ -# Lesson 04 — JDBC and Databases +# Lesson 05 — JDBC and Databases -**Module 03 · Advanced · Lesson 04 of 07** +**Module 03 · Advanced · Lesson 05 of 10** ## Learning objectives diff --git a/data/Java/data/03-advanced/06-jdbc.md b/data/Java/data/03-advanced/06-jdbc.md new file mode 100644 index 00000000..80054c57 --- /dev/null +++ b/data/Java/data/03-advanced/06-jdbc.md @@ -0,0 +1,218 @@ +# Lesson 06 — JDBC and Database Access + +**Module 03 · Advanced · Lesson 06 of 10** + +## Learning Objectives + +- Connect to a database using JDBC +- Execute queries and updates with `PreparedStatement` +- Map `ResultSet` rows to Java objects + +## Overview + +**JDBC (Java Database Connectivity)** is Java's standard API for talking to relational databases (MySQL, PostgreSQL, SQLite, etc.). You write SQL; JDBC sends it to the database and brings back the results. In production you'd use Spring Data or Hibernate on top, but understanding raw JDBC is essential for debugging and optimisation. + +## Key Concepts + +### 1. Adding the Driver (Maven/Gradle) + +```xml + + + org.xerial + sqlite-jdbc + 3.45.1.0 + + + + + com.mysql + mysql-connector-j + 8.3.0 + +``` + +### 2. Connecting + +```java +import java.sql.*; + +String url = "jdbc:sqlite:students.db"; // SQLite +// String url = "jdbc:mysql://localhost:3306/mydb"; // MySQL + +try (Connection conn = DriverManager.getConnection(url)) { + System.out.println("Connected: " + conn.getMetaData().getDatabaseProductName()); +} +``` + +### 3. Creating a Table + +```java +String sql = """ + CREATE TABLE IF NOT EXISTS students ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + email TEXT UNIQUE, + score REAL DEFAULT 0 + ) + """; + +try (Connection conn = DriverManager.getConnection(url); + Statement stmt = conn.createStatement()) { + stmt.execute(sql); +} +``` + +### 4. PreparedStatement — Insert / Update / Delete + +Always use `PreparedStatement` for user-supplied data — it prevents **SQL injection**. + +```java +String insert = "INSERT INTO students (name, email, score) VALUES (?, ?, ?)"; + +try (Connection conn = DriverManager.getConnection(url); + PreparedStatement ps = conn.prepareStatement(insert)) { + + ps.setString(1, "Alice"); + ps.setString(2, "alice@example.com"); + ps.setDouble(3, 92.5); + ps.executeUpdate(); + + // Batch insert for multiple rows + String[][] data = {{"Bob","bob@ex.com","85"},{"Charlie","c@ex.com","78"}}; + for (String[] row : data) { + ps.setString(1, row[0]); + ps.setString(2, row[1]); + ps.setDouble(3, Double.parseDouble(row[2])); + ps.addBatch(); + } + ps.executeBatch(); +} +``` + +### 5. Querying — ResultSet + +```java +String query = "SELECT * FROM students WHERE score > ? ORDER BY score DESC"; + +try (Connection conn = DriverManager.getConnection(url); + PreparedStatement ps = conn.prepareStatement(query)) { + + ps.setDouble(1, 80.0); + ResultSet rs = ps.executeQuery(); + + while (rs.next()) { + int id = rs.getInt("id"); + String name = rs.getString("name"); + double score = rs.getDouble("score"); + System.out.printf("%-3d %-10s %.1f%n", id, name, score); + } +} +``` + +### 6. Transactions + +Wrap related operations in a transaction — either all succeed or all roll back. + +```java +Connection conn = DriverManager.getConnection(url); +conn.setAutoCommit(false); // start transaction + +try { + // debit account A + // credit account B + conn.commit(); +} catch (SQLException e) { + conn.rollback(); // undo everything + throw e; +} finally { + conn.setAutoCommit(true); + conn.close(); +} +``` + +## Full Example + +```java +import java.sql.*; +import java.util.*; + +public class JdbcDemo { + record Student(int id, String name, String email, double score) {} + + static final String URL = "jdbc:sqlite:demo.db"; + + static void createTable() throws SQLException { + try (Connection c = DriverManager.getConnection(URL); + Statement s = c.createStatement()) { + s.execute(""" + CREATE TABLE IF NOT EXISTS students ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT, email TEXT, score REAL) + """); + } + } + + static void insert(String name, String email, double score) throws SQLException { + String sql = "INSERT INTO students (name,email,score) VALUES (?,?,?)"; + try (Connection c = DriverManager.getConnection(URL); + PreparedStatement ps = c.prepareStatement(sql)) { + ps.setString(1, name); ps.setString(2, email); ps.setDouble(3, score); + ps.executeUpdate(); + } + } + + static List findTopStudents(double minScore) throws SQLException { + List result = new ArrayList<>(); + String sql = "SELECT * FROM students WHERE score >= ? ORDER BY score DESC"; + try (Connection c = DriverManager.getConnection(URL); + PreparedStatement ps = c.prepareStatement(sql)) { + ps.setDouble(1, minScore); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + result.add(new Student(rs.getInt("id"), rs.getString("name"), + rs.getString("email"), rs.getDouble("score"))); + } + } + return result; + } + + public static void main(String[] args) throws SQLException { + createTable(); + insert("Alice", "alice@ex.com", 92.5); + insert("Bob", "bob@ex.com", 85.0); + insert("Charlie", "charlie@ex.com", 78.3); + insert("Diana", "diana@ex.com", 96.1); + + System.out.println("Top students (score ≥ 85):"); + for (Student s : findTopStudents(85)) { + System.out.printf(" [%d] %-8s %.1f %s%n", + s.id(), s.name(), s.score(), s.email()); + } + } +} +``` + +**Expected output:** +``` +Top students (score ≥ 85): + [4] Diana 96.1 diana@ex.com + [1] Alice 92.5 alice@ex.com + [2] Bob 85.0 bob@ex.com +``` + +## Exercise + +1. Add an `updateScore(int id, double newScore)` method to the demo above. +2. Add a `deleteStudent(int id)` method and verify the row is gone. +3. Write a transaction that transfers "grade points" from one student to another — roll back if either student doesn't exist. + +## Checkpoint + +You are ready for Module 04 when you can: +- Connect to a database and run a query +- Explain why PreparedStatement prevents SQL injection +- Wrap multiple inserts in a transaction + +--- +**Module 03 Complete!** You are ready for **Module 04 — Professional Java**. diff --git a/data/Java/data/03-advanced/05-unit-testing-junit.md b/data/Java/data/03-advanced/07-unit-testing-junit.md similarity index 92% rename from data/Java/data/03-advanced/05-unit-testing-junit.md rename to data/Java/data/03-advanced/07-unit-testing-junit.md index bcfb008b..f819f6de 100644 --- a/data/Java/data/03-advanced/05-unit-testing-junit.md +++ b/data/Java/data/03-advanced/07-unit-testing-junit.md @@ -1,6 +1,6 @@ -# Lesson 05 — JUnit Testing +# Lesson 07 — JUnit Testing -**Module 03 · Advanced · Lesson 05 of 07** +**Module 03 · Advanced · Lesson 07 of 10** ## Learning objectives diff --git a/data/Java/data/03-advanced/06-design-patterns.md b/data/Java/data/03-advanced/08-design-patterns.md similarity index 92% rename from data/Java/data/03-advanced/06-design-patterns.md rename to data/Java/data/03-advanced/08-design-patterns.md index aa1989e8..729b3a8b 100644 --- a/data/Java/data/03-advanced/06-design-patterns.md +++ b/data/Java/data/03-advanced/08-design-patterns.md @@ -1,6 +1,6 @@ -# Lesson 06 — Design Patterns Intro +# Lesson 08 — Design Patterns Intro -**Module 03 · Advanced · Lesson 06 of 07** +**Module 03 · Advanced · Lesson 08 of 10** ## Learning objectives diff --git a/data/Java/data/03-advanced/07-jvm-and-memory.md b/data/Java/data/03-advanced/09-jvm-and-memory.md similarity index 92% rename from data/Java/data/03-advanced/07-jvm-and-memory.md rename to data/Java/data/03-advanced/09-jvm-and-memory.md index 5cb40078..81c248c2 100644 --- a/data/Java/data/03-advanced/07-jvm-and-memory.md +++ b/data/Java/data/03-advanced/09-jvm-and-memory.md @@ -1,6 +1,6 @@ -# Lesson 07 — JVM and Memory +# Lesson 09 — JVM and Memory -**Module 03 · Advanced · Lesson 07 of 07** +**Module 03 · Advanced · Lesson 09 of 10** ## Learning objectives diff --git a/data/Java/data/03-advanced/10-optional-null-safety.md b/data/Java/data/03-advanced/10-optional-null-safety.md new file mode 100644 index 00000000..706ef939 --- /dev/null +++ b/data/Java/data/03-advanced/10-optional-null-safety.md @@ -0,0 +1,155 @@ +# Lesson 10 — Optional and Null Safety + +**Module 03 · Advanced · Lesson 10 of 10** + +## Learning Objectives + +- Use `Optional` to represent values that may be absent +- Chain Optional operations with `map`, `flatMap`, and `filter` +- Avoid `NullPointerException` in real-world code + +## Overview + +`NullPointerException` is the most common Java runtime crash. Java 8 introduced `Optional` — a container that either holds a value or explicitly represents "no value". Using Optional forces callers to handle the absent case, eliminating silent null bugs. + +## Key Concepts + +### 1. Creating Optionals + +```java +import java.util.Optional; + +Optional present = Optional.of("Hello"); // must be non-null +Optional empty = Optional.empty(); // explicitly absent +Optional maybe = Optional.ofNullable(getValue()); // null becomes empty +``` + +### 2. Checking and Getting + +```java +Optional opt = Optional.of("Alice"); + +opt.isPresent() // true +opt.isEmpty() // false (Java 11+) +opt.get() // "Alice" — throws NoSuchElementException if empty! + +// Safer alternatives: +opt.orElse("default") // return value or fallback +opt.orElseGet(() -> computeDefault()) // lazy fallback +opt.orElseThrow(() -> new RuntimeException("Not found")) +``` + +### 3. Transforming with map and flatMap + +```java +Optional name = Optional.of(" alice "); + +Optional upper = name + .map(String::trim) + .map(String::toUpperCase); + +System.out.println(upper.orElse("nobody")); // ALICE + +// flatMap: when the mapping function itself returns Optional +Optional email = findUser("alice") + .flatMap(user -> user.getEmail()); // getEmail() returns Optional +``` + +### 4. filter + +```java +Optional age = Optional.of(17); + +Optional legalAge = age.filter(a -> a >= 18); +System.out.println(legalAge.isPresent()); // false +``` + +### 5. ifPresent / ifPresentOrElse + +```java +Optional name = Optional.of("Alice"); + +name.ifPresent(n -> System.out.println("Hello, " + n)); +// Hello, Alice + +name.ifPresentOrElse( + n -> System.out.println("Found: " + n), + () -> System.out.println("Not found") +); +``` + +### 6. When NOT to use Optional + +- **Don't** use Optional as a field type in a class +- **Don't** use Optional in method parameters (use overloading instead) +- **Don't** use Optional with collections (return an empty list instead) +- **Do** use Optional as a **return type** for methods that may not find a value + +## Full Example + +```java +import java.util.*; + +public class OptionalDemo { + record User(String id, String name, String email) { + Optional getEmail() { + return email == null ? Optional.empty() : Optional.of(email); + } + } + + static Map db = Map.of( + "u1", new User("u1", "Alice", "alice@example.com"), + "u2", new User("u2", "Bob", null) // no email + ); + + static Optional findUser(String id) { + return Optional.ofNullable(db.get(id)); + } + + static String getEmailDomain(String userId) { + return findUser(userId) + .flatMap(User::getEmail) + .map(email -> email.substring(email.indexOf('@') + 1)) + .map(String::toUpperCase) + .orElse("NO EMAIL"); + } + + public static void main(String[] args) { + String[] ids = {"u1", "u2", "u3"}; + + for (String id : ids) { + System.out.printf("User %-3s → domain: %s%n", id, getEmailDomain(id)); + } + + // Safe update + findUser("u1").ifPresentOrElse( + u -> System.out.println("Found: " + u.name()), + () -> System.out.println("User not found") + ); + } +} +``` + +**Expected output:** +``` +User u1 → domain: EXAMPLE.COM +User u2 → domain: NO EMAIL +User u3 → domain: NO EMAIL +Found: Alice +``` + +## Exercise + +1. Write a method `findFirstEven(List list)` that returns `Optional` — the first even number, or empty if none. +2. Chain three Optional operations: find a user by ID, get their address, get the city — returning `Optional`. +3. Refactor an existing class that returns `null` on "not found" to return `Optional` instead, and update all callers. + +## Checkpoint + +You are ready for the next lesson when you can: +- Chain `map`, `flatMap`, and `filter` on Optional +- Explain when `get()` is dangerous +- Describe the 3 situations where Optional should NOT be used + +--- +**Next:** Lesson 05 — JDBC and Database Access diff --git a/data/Java/data/04-professional/01-spring-boot-intro.md b/data/Java/data/04-professional/01-spring-boot-intro.md index 2c66ae0b..77e49bfb 100644 --- a/data/Java/data/04-professional/01-spring-boot-intro.md +++ b/data/Java/data/04-professional/01-spring-boot-intro.md @@ -1,41 +1,213 @@ # Lesson 01 — Spring Boot Introduction -**Module 04 · Professional · Lesson 01 of 06** +**Module 04 · Professional · Lesson 01 of 05** +## Learning Objectives -## Learning objectives - -- Understand **spring boot introduction** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Create a Spring Boot project and run it +- Understand auto-configuration and the application context +- Build your first REST endpoint ## Overview -Spring Boot Introduction is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. +**Spring Boot** is the industry-standard way to build Java backend applications. It eliminates boilerplate by auto-configuring everything based on what's on your classpath. A production-ready web server starts with a single `main` method. + +## Key Concepts + +### 1. Project Setup (Spring Initializr) + +Go to **https://start.spring.io** and select: +- **Project:** Maven +- **Language:** Java +- **Spring Boot:** 3.x +- **Dependencies:** Spring Web, Spring Data JPA, H2 Database (for dev) + +Download and open in IntelliJ or VS Code. + +Your `pom.xml` key dependencies: +```xml + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + runtime + + +``` + +### 2. The Entry Point + +```java +@SpringBootApplication // = @Configuration + @EnableAutoConfiguration + @ComponentScan +public class MyApp { + public static void main(String[] args) { + SpringApplication.run(MyApp.class, args); + // Starts embedded Tomcat on port 8080 + } +} +``` + +### 3. Your First REST Controller + +```java +import org.springframework.web.bind.annotation.*; + +@RestController // = @Controller + @ResponseBody +@RequestMapping("/api") +public class HelloController { + + @GetMapping("/hello") + public String hello() { + return "Hello from Spring Boot!"; + } + + @GetMapping("/hello/{name}") + public String greet(@PathVariable String name) { + return "Hello, " + name + "!"; + } + + @GetMapping("/add") + public int add(@RequestParam int a, @RequestParam int b) { + return a + b; + } +} +``` + +Access at: +- `GET http://localhost:8080/api/hello` → `Hello from Spring Boot!` +- `GET http://localhost:8080/api/hello/Alice` → `Hello, Alice!` +- `GET http://localhost:8080/api/add?a=5&b=3` → `8` + +### 4. Returning JSON + +Spring Boot automatically converts Java objects to JSON using Jackson. -## Key concepts +```java +public record Product(int id, String name, double price) {} + +@GetMapping("/product") +public Product getProduct() { + return new Product(1, "Laptop", 999.99); +} +// Response: {"id":1,"name":"Laptop","price":999.99} + +@GetMapping("/products") +public List getAll() { + return List.of( + new Product(1, "Laptop", 999.99), + new Product(2, "Mouse", 29.99) + ); +} +``` -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes +### 5. application.properties -## Example +```properties +# src/main/resources/application.properties +server.port=8080 +spring.application.name=my-app + +# H2 in-memory database +spring.datasource.url=jdbc:h2:mem:testdb +spring.h2.console.enabled=true +spring.jpa.show-sql=true +``` + +### 6. Dependency Injection with @Autowired / Constructor Injection ```java -// Spring Boot Introduction — practice sketch -// add your code here +@Service +public class ProductService { + public List getAllNames() { + return List.of("Laptop", "Mouse", "Keyboard"); + } +} + +@RestController +@RequestMapping("/api") +public class ProductController { + private final ProductService productService; + + // Constructor injection (preferred over @Autowired on field) + public ProductController(ProductService productService) { + this.productService = productService; + } + + @GetMapping("/names") + public List names() { + return productService.getAllNames(); + } +} +``` + +## Full Example — Mini REST API + +```java +// Model +public record Student(Long id, String name, int score) {} + +// Service +@Service +public class StudentService { + private final List students = new ArrayList<>(List.of( + new Student(1L, "Alice", 92), + new Student(2L, "Bob", 85), + new Student(3L, "Diana", 96) + )); + + public List getAll() { return students; } + public Optional getById(Long id) { + return students.stream().filter(s -> s.id().equals(id)).findFirst(); + } +} + +// Controller +@RestController +@RequestMapping("/api/students") +public class StudentController { + private final StudentService service; + + public StudentController(StudentService service) { this.service = service; } + + @GetMapping + public List all() { return service.getAll(); } + + @GetMapping("/{id}") + public ResponseEntity byId(@PathVariable Long id) { + return service.getById(id) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } +} +``` + +Test with: +``` +GET http://localhost:8080/api/students → all students +GET http://localhost:8080/api/students/2 → Bob +GET http://localhost:8080/api/students/99 → 404 Not Found ``` ## Exercise -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). +1. Add a `@PostMapping` endpoint that accepts a `Student` JSON body and adds it to the list. +2. Add a `@DeleteMapping("/{id}")` that removes a student by ID. +3. Add a `@GetMapping("/top")` that returns only students with score ≥ 90. ## Checkpoint -You are ready for the next lesson when you can solve the exercise without copying the example. +You are ready for the next lesson when you can: +- Run a Spring Boot app and hit an endpoint in a browser +- Explain the difference between `@RestController` and `@Controller` +- Use `@PathVariable`, `@RequestParam`, and `@RequestBody` --- - -**Next:** Continue to lesson 02 in this module. +**Next:** Lesson 02 — Spring Data JPA and Database Integration diff --git a/data/Java/data/04-professional/03-rest-api-design.md b/data/Java/data/04-professional/03-rest-api-design.md new file mode 100644 index 00000000..c46cee7e --- /dev/null +++ b/data/Java/data/04-professional/03-rest-api-design.md @@ -0,0 +1,210 @@ +# Lesson 03 — REST API Design and Exception Handling + +**Module 04 · Professional · Lesson 03 of 05** + +## Learning Objectives + +- Follow REST conventions for URLs, HTTP methods, and status codes +- Use `@ControllerAdvice` for global exception handling +- Validate request bodies with Bean Validation + +## Overview + +A well-designed REST API is predictable, consistent, and communicates errors clearly. This lesson covers the conventions every professional Java developer uses when building APIs, plus the Spring tools that enforce them. + +## Key Concepts + +### 1. REST URL and Method Conventions + +| Action | Method | URL | Status | +|--------|--------|-----|--------| +| List all | GET | `/api/students` | 200 | +| Get one | GET | `/api/students/{id}` | 200 / 404 | +| Create | POST | `/api/students` | 201 | +| Full update | PUT | `/api/students/{id}` | 200 / 404 | +| Partial update | PATCH | `/api/students/{id}` | 200 / 404 | +| Delete | DELETE | `/api/students/{id}` | 204 / 404 | + +Rules: +- URLs are **nouns**, not verbs (`/students`, not `/getStudents`) +- Use **plural** resource names +- Nest related resources: `/api/courses/{id}/students` + +### 2. Bean Validation (Jakarta Validation) + +Add `spring-boot-starter-validation` dependency, then annotate your DTO: + +```java +import jakarta.validation.constraints.*; + +public class StudentRequest { + @NotBlank(message = "Name is required") + @Size(min = 2, max = 50) + private String name; + + @Email(message = "Must be a valid email") + @NotNull + private String email; + + @Min(value = 0, message = "Score cannot be negative") + @Max(value = 100) + private double score; + + // getters and setters +} +``` + +In the controller, add `@Valid`: + +```java +@PostMapping +public ResponseEntity create(@Valid @RequestBody StudentRequest req) { + // if validation fails, Spring throws MethodArgumentNotValidException + Student student = new Student(req.getName(), req.getEmail(), req.getScore()); + return ResponseEntity.status(HttpStatus.CREATED).body(service.save(student)); +} +``` + +### 3. Global Exception Handler with @ControllerAdvice + +Handle all exceptions in one place instead of duplicating try-catch across controllers. + +```java +import org.springframework.web.bind.annotation.*; +import org.springframework.http.*; +import java.util.*; + +@ControllerAdvice +public class GlobalExceptionHandler { + + // 404 — Resource not found + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity> handleNotFound(ResourceNotFoundException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(Map.of("error", e.getMessage())); + } + + // 400 — Validation errors + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity> handleValidation( + MethodArgumentNotValidException e) { + Map fieldErrors = new LinkedHashMap<>(); + e.getBindingResult().getFieldErrors().forEach(fe -> + fieldErrors.put(fe.getField(), fe.getDefaultMessage())); + + return ResponseEntity.badRequest().body(Map.of( + "status", 400, + "message", "Validation failed", + "errors", fieldErrors + )); + } + + // 500 — Unexpected errors + @ExceptionHandler(Exception.class) + public ResponseEntity> handleGeneral(Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(Map.of("error", "An unexpected error occurred")); + } +} +``` + +### 4. Custom Exception Classes + +```java +@ResponseStatus(HttpStatus.NOT_FOUND) +public class ResourceNotFoundException extends RuntimeException { + public ResourceNotFoundException(String resource, Long id) { + super(resource + " with id " + id + " not found"); + } +} + +// In your service: +public Student getById(Long id) { + return repo.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("Student", id)); +} +``` + +### 5. Consistent Error Response Body + +Always return the same error structure: + +```json +{ + "timestamp": "2024-03-15T10:30:00", + "status": 404, + "error": "Not Found", + "message": "Student with id 99 not found", + "path": "/api/students/99" +} +``` + +```java +public record ErrorResponse( + LocalDateTime timestamp, + int status, + String error, + String message, + String path +) {} +``` + +## Full Example — Production-grade Controller + +```java +@RestController +@RequestMapping("/api/v1/students") +@Validated +public class StudentController { + private final StudentService service; + + public StudentController(StudentService service) { this.service = service; } + + @GetMapping + public ResponseEntity> getAll( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size) { + return ResponseEntity.ok(service.getAll(page, size)); + } + + @GetMapping("/{id}") + public ResponseEntity getById(@PathVariable Long id) { + return ResponseEntity.ok(service.getById(id)); // throws 404 if not found + } + + @PostMapping + public ResponseEntity create(@Valid @RequestBody StudentRequest req) { + Student created = service.create(req); + URI location = URI.create("/api/v1/students/" + created.getId()); + return ResponseEntity.created(location).body(created); + } + + @PutMapping("/{id}") + public ResponseEntity update(@PathVariable Long id, + @Valid @RequestBody StudentRequest req) { + return ResponseEntity.ok(service.update(id, req)); + } + + @DeleteMapping("/{id}") + public ResponseEntity delete(@PathVariable Long id) { + service.delete(id); + return ResponseEntity.noContent().build(); + } +} +``` + +## Exercise + +1. Add `@NotBlank` and `@Email` validation to your `StudentRequest`, test that sending an empty name returns a 400 with a clear message. +2. Add a `ConflictException` (409) thrown when trying to create a student with a duplicate email. +3. Add a `GET /api/v1/students/search?name=ali` endpoint that uses a derived query and returns 404 if no results. + +## Checkpoint + +You are ready for the next lesson when you can: +- Design REST URLs following standard conventions +- Return proper HTTP status codes for all outcomes +- Handle all exceptions in one `@ControllerAdvice` class + +--- +**Next:** Lesson 04 — Maven, Build Tools and Project Structure diff --git a/data/Java/data/04-professional/04-maven-build-tools.md b/data/Java/data/04-professional/04-maven-build-tools.md new file mode 100644 index 00000000..0eee740f --- /dev/null +++ b/data/Java/data/04-professional/04-maven-build-tools.md @@ -0,0 +1,198 @@ +# Lesson 04 — Maven and Project Structure + +**Module 04 · Professional · Lesson 04 of 05** + +## Learning Objectives + +- Understand Maven's build lifecycle and directory structure +- Manage dependencies with `pom.xml` +- Run, test, and package a project from the command line + +## Overview + +**Maven** is the most widely used Java build tool. It manages dependencies (downloading JARs from the internet), compiles your code, runs tests, and packages everything into a deployable JAR. Understanding Maven is essential for working in any professional Java team. + +## Key Concepts + +### 1. Standard Directory Structure + +``` +my-project/ +├── pom.xml ← project config and dependencies +└── src/ + ├── main/ + │ ├── java/ + │ │ └── com/company/app/ ← your production code + │ └── resources/ + │ └── application.properties + └── test/ + ├── java/ + │ └── com/company/app/ ← your test code + └── resources/ +``` + +### 2. pom.xml Structure + +```xml + + + + 4.0.0 + + + com.quantumlogics + polycode-backend + 1.0.0-SNAPSHOT + jar + + + + org.springframework.boot + spring-boot-starter-parent + 3.2.3 + + + + 21 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + com.mysql + mysql-connector-j + runtime + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + +``` + +### 3. Dependency Scopes + +| Scope | Available in | Packaged in JAR | +|-------|-------------|-----------------| +| `compile` (default) | Compile + run | ✅ | +| `runtime` | Run only | ✅ | +| `test` | Tests only | ❌ | +| `provided` | Compile only (e.g. servlet API) | ❌ | + +### 4. Maven Lifecycle Commands + +```bash +# Compile source code +mvn compile + +# Run tests +mvn test + +# Package into target/your-app.jar +mvn package + +# Skip tests while packaging +mvn package -DskipTests + +# Clean compiled files and start fresh +mvn clean + +# Clean, compile, test, and package +mvn clean package + +# Run a Spring Boot app +mvn spring-boot:run + +# Install into local Maven repository (~/.m2) +mvn install +``` + +### 5. Maven Wrapper (mvnw) + +Spring Boot projects include `mvnw` / `mvnw.cmd` — a self-contained Maven script so teammates don't need Maven installed: + +```bash +./mvnw spring-boot:run # Linux/Mac +mvnw.cmd spring-boot:run # Windows +``` + +### 6. Multi-module Project Structure + +For larger apps, split into modules: + +``` +parent-pom/ +├── pom.xml ← parent pom with shared config +├── api/ ← REST controllers module +│ └── pom.xml +├── service/ ← business logic module +│ └── pom.xml +└── data/ ← JPA entities and repositories + └── pom.xml +``` + +## Common Maven Problems and Fixes + +```bash +# Dependency not downloading? +mvn clean install -U # force update snapshots + +# "Could not find artifact" error? +# Check ~/.m2/repository and delete the broken folder, then retry + +# Port 8080 already in use? +# application.properties: server.port=8081 + +# Tests failing in CI but passing locally? +mvn test -Dspring.profiles.active=test +``` + +## Exercise + +1. Add `spring-boot-devtools` as a `runtime` dependency and observe how it auto-restarts on code changes. +2. Add the `jacoco-maven-plugin` to your `pom.xml` and run `mvn verify` to generate a test coverage report. +3. Create a Maven profile (`-Pproduction`) that swaps in `application-prod.properties` with a real database URL. + +## Checkpoint + +You are ready for the next lesson when you can: +- Navigate a Maven project structure confidently +- Add a dependency to `pom.xml` and understand its scope +- Run `mvn clean package` and execute the resulting JAR + +--- +**Next:** Lesson 05 — Unit Testing with JUnit 5 diff --git a/data/Java/data/04-professional/03-maven-gradle.md b/data/Java/data/04-professional/04-maven-gradle.md similarity index 92% rename from data/Java/data/04-professional/03-maven-gradle.md rename to data/Java/data/04-professional/04-maven-gradle.md index e2a6680b..bebc38d3 100644 --- a/data/Java/data/04-professional/03-maven-gradle.md +++ b/data/Java/data/04-professional/04-maven-gradle.md @@ -1,6 +1,6 @@ -# Lesson 03 — Maven and Gradle +# Lesson 04 — Maven and Gradle -**Module 04 · Professional · Lesson 03 of 06** +**Module 4 · Professional · Lesson 04 of 10** ## Learning objectives diff --git a/data/Java/data/04-professional/04-spring-data-jpa.md b/data/Java/data/04-professional/04-spring-data-jpa.md new file mode 100644 index 00000000..516ef555 --- /dev/null +++ b/data/Java/data/04-professional/04-spring-data-jpa.md @@ -0,0 +1,176 @@ +# Lesson 02 — Spring Data JPA + +**Module 04 · Professional · Lesson 02 of 05** + +## Learning Objectives + +- Map a Java class to a database table with JPA annotations +- Use `JpaRepository` for CRUD without writing SQL +- Write custom queries with `@Query` + +## Overview + +**JPA (Java Persistence API)** is the standard for mapping Java objects to database tables (ORM — Object-Relational Mapping). **Spring Data JPA** builds on top of it to generate common database operations automatically — you define an interface and Spring writes the implementation. + +## Key Concepts + +### 1. Entity — Mapping a Class to a Table + +```java +import jakarta.persistence.*; + +@Entity +@Table(name = "students") +public class Student { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) // auto-increment + private Long id; + + @Column(nullable = false) + private String name; + + @Column(unique = true) + private String email; + + private double score; + + // Constructors, getters, setters + public Student() {} // JPA requires a no-arg constructor + + public Student(String name, String email, double score) { + this.name = name; this.email = email; this.score = score; + } + + // getters / setters... +} +``` + +### 2. Repository — Auto-generated CRUD + +```java +import org.springframework.data.jpa.repository.JpaRepository; + +public interface StudentRepository extends JpaRepository { + // Spring generates: save(), findById(), findAll(), delete(), count(), etc. +} +``` + +That's it — no SQL, no implementation class needed. + +### 3. Using the Repository in a Service + +```java +@Service +public class StudentService { + private final StudentRepository repo; + + public StudentService(StudentRepository repo) { this.repo = repo; } + + public List getAll() { return repo.findAll(); } + public Optional getById(Long id) { return repo.findById(id); } + public Student save(Student s) { return repo.save(s); } + public void delete(Long id) { repo.deleteById(id); } +} +``` + +### 4. Derived Query Methods (Spring generates SQL from method name) + +```java +public interface StudentRepository extends JpaRepository { + // SELECT * FROM students WHERE name = ? + List findByName(String name); + + // SELECT * FROM students WHERE score >= ? ORDER BY score DESC + List findByScoreGreaterThanEqualOrderByScoreDesc(double minScore); + + // SELECT * FROM students WHERE email LIKE ? + Optional findByEmail(String email); + + // SELECT COUNT(*) FROM students WHERE score > ? + long countByScoreGreaterThan(double threshold); +} +``` + +### 5. Custom JPQL Query with @Query + +```java +@Query("SELECT s FROM Student s WHERE s.score BETWEEN :min AND :max") +List findInScoreRange(@Param("min") double min, @Param("max") double max); + +// Native SQL +@Query(value = "SELECT * FROM students ORDER BY score DESC LIMIT :n", + nativeQuery = true) +List findTopN(@Param("n") int n); +``` + +### 6. Full Controller (CRUD REST API) + +```java +@RestController +@RequestMapping("/api/students") +public class StudentController { + private final StudentService service; + + public StudentController(StudentService service) { this.service = service; } + + @GetMapping + public List all() { return service.getAll(); } + + @GetMapping("/{id}") + public ResponseEntity byId(@PathVariable Long id) { + return service.getById(id) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public Student create(@RequestBody Student student) { + return service.save(student); + } + + @PutMapping("/{id}") + public ResponseEntity update(@PathVariable Long id, + @RequestBody Student updated) { + return service.getById(id).map(s -> { + updated.setId(id); + return ResponseEntity.ok(service.save(updated)); + }).orElse(ResponseEntity.notFound().build()); + } + + @DeleteMapping("/{id}") + public ResponseEntity delete(@PathVariable Long id) { + if (service.getById(id).isEmpty()) return ResponseEntity.notFound().build(); + service.delete(id); + return ResponseEntity.noContent().build(); + } +} +``` + +### 7. application.properties for MySQL + +```properties +spring.datasource.url=jdbc:mysql://localhost:3306/school +spring.datasource.username=root +spring.datasource.password=secret +spring.jpa.hibernate.ddl-auto=update # creates/updates tables on startup +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.format_sql=true +``` + +## Exercise + +1. Add a `Course` entity and a `StudentCourse` many-to-many relationship using `@ManyToMany`. +2. Add a `findByNameContainingIgnoreCase` derived query for a search endpoint. +3. Write a `@Transactional` service method that enrolls a student in a course, throwing an exception (and rolling back) if the course is full. + +## Checkpoint + +You are ready for the next lesson when you can: +- Write an Entity class with all JPA annotations +- Create a repository and use auto-generated methods +- Build a full CRUD REST API with Spring Data JPA + +--- +**Next:** Lesson 03 — REST API Design and Exception Handling diff --git a/data/Java/data/04-professional/04-logging.md b/data/Java/data/04-professional/05-logging.md similarity index 91% rename from data/Java/data/04-professional/04-logging.md rename to data/Java/data/04-professional/05-logging.md index a0601338..9cd61532 100644 --- a/data/Java/data/04-professional/04-logging.md +++ b/data/Java/data/04-professional/05-logging.md @@ -1,6 +1,6 @@ -# Lesson 04 — Logging Best Practices +# Lesson 05 — Logging Best Practices -**Module 04 · Professional · Lesson 04 of 06** +**Module 4 · Professional · Lesson 5 of 10** ## Learning objectives diff --git a/data/Java/data/04-professional/05-security-basics.md b/data/Java/data/04-professional/05-security-basics.md index 282073bf..368a653a 100644 --- a/data/Java/data/04-professional/05-security-basics.md +++ b/data/Java/data/04-professional/05-security-basics.md @@ -1,6 +1,6 @@ # Lesson 05 — Security Basics -**Module 04 · Professional · Lesson 05 of 06** +**Module 4 · Professional · Lesson 05 of 06** ## Learning objectives diff --git a/data/Java/data/04-professional/05-unit-testing.md b/data/Java/data/04-professional/05-unit-testing.md new file mode 100644 index 00000000..e87712e8 --- /dev/null +++ b/data/Java/data/04-professional/05-unit-testing.md @@ -0,0 +1,198 @@ +# Lesson 05 — Unit Testing with JUnit 5 and Mockito + +**Module 04 · Professional · Lesson 05 of 05** + +## Learning Objectives + +- Write unit tests with JUnit 5 annotations and assertions +- Mock dependencies with Mockito +- Test Spring REST controllers with MockMvc + +## Overview + +Professional code is **tested code**. Unit tests catch bugs early, document expected behaviour, and let you refactor safely. JUnit 5 is the standard Java test framework; Mockito lets you replace real dependencies (like databases) with controlled fakes. + +## Key Concepts + +### 1. JUnit 5 Basics + +```java +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +class CalculatorTest { + + private Calculator calc; + + @BeforeEach // runs before each test + void setUp() { calc = new Calculator(); } + + @AfterEach // runs after each test + void tearDown() {} + + @Test + void addition_returnsCorrectSum() { + int result = calc.add(3, 4); + assertEquals(7, result); + } + + @Test + void division_byZero_throwsException() { + assertThrows(ArithmeticException.class, () -> calc.divide(10, 0)); + } + + @Test + @DisplayName("Negative numbers sum correctly") + void negativeNumbers() { + assertEquals(-5, calc.add(-2, -3)); + } + + @ParameterizedTest + @CsvSource({"1,1,2", "5,3,8", "-1,1,0", "0,0,0"}) + void add_multipleInputs(int a, int b, int expected) { + assertEquals(expected, calc.add(a, b)); + } +} +``` + +### 2. Common Assertions + +```java +assertEquals(expected, actual) +assertNotEquals(a, b) +assertTrue(condition) +assertFalse(condition) +assertNull(value) +assertNotNull(value) +assertThrows(Exception.class, () -> methodThatThrows()) +assertAll( // check multiple conditions at once + () -> assertEquals(5, result.size()), + () -> assertTrue(result.contains("Alice")) +) +``` + +### 3. Mockito — Mocking Dependencies + +```java +import org.mockito.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class StudentServiceTest { + + @Mock + StudentRepository repo; // fake — doesn't touch the database + + @InjectMocks + StudentService service; // real — uses the mock repo + + @Test + void getById_existingId_returnsStudent() { + Student alice = new Student(1L, "Alice", "alice@ex.com", 92.0); + when(repo.findById(1L)).thenReturn(Optional.of(alice)); + + Student result = service.getById(1L); + + assertEquals("Alice", result.getName()); + verify(repo, times(1)).findById(1L); + } + + @Test + void getById_missingId_throwsNotFoundException() { + when(repo.findById(99L)).thenReturn(Optional.empty()); + + assertThrows(ResourceNotFoundException.class, + () -> service.getById(99L)); + } + + @Test + void save_callsRepositorySave() { + Student student = new Student("Bob", "bob@ex.com", 85.0); + when(repo.save(student)).thenReturn(student); + + service.create(student); + + verify(repo).save(student); // verify it was called + } +} +``` + +### 4. MockMvc — Testing REST Controllers + +```java +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.web.servlet.MockMvc; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@WebMvcTest(StudentController.class) // loads only web layer +class StudentControllerTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + StudentService service; // mock the service + + @Test + void getAll_returnsStudentList() throws Exception { + when(service.getAll()).thenReturn(List.of( + new Student(1L, "Alice", "alice@ex.com", 92.0) + )); + + mockMvc.perform(get("/api/students")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].name").value("Alice")) + .andExpect(jsonPath("$[0].score").value(92.0)) + .andExpect(jsonPath("$.length()").value(1)); + } + + @Test + void getById_notFound_returns404() throws Exception { + when(service.getById(99L)).thenThrow(new ResourceNotFoundException("Student", 99L)); + + mockMvc.perform(get("/api/students/99")) + .andExpect(status().isNotFound()); + } + + @Test + void create_validBody_returns201() throws Exception { + String json = """ + {"name":"Bob","email":"bob@ex.com","score":85} + """; + Student bob = new Student(2L, "Bob", "bob@ex.com", 85.0); + when(service.create(any())).thenReturn(bob); + + mockMvc.perform(post("/api/students") + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.id").value(2)); + } +} +``` + +### 5. Test Coverage + +Aim for ≥ 80% line coverage on service and utility classes. Use JaCoCo: + +```bash +mvn test jacoco:report +# Report at: target/site/jacoco/index.html +``` + +## Exercise + +1. Write tests for a `StringUtils` class: `isPalindrome`, `countVowels`, `titleCase`. +2. Write `StudentServiceTest` covering: getAll, getById (found + not found), create, delete. +3. Write `StudentControllerTest` covering all 5 endpoints (GET all, GET by id, POST, PUT, DELETE). + +## Checkpoint + +You are ready for Module 05 when you can: +- Write a JUnit 5 test with `@BeforeEach` and parameterized inputs +- Mock a repository with Mockito and verify it was called +- Test a Spring controller endpoint with MockMvc + +--- +**Module 04 Complete!** You are ready for **Module 05 — Mastery**. diff --git a/data/Java/data/05-mastery/01-algorithms.md b/data/Java/data/05-mastery/01-algorithms.md index 9802f59f..f6dc0c28 100644 --- a/data/Java/data/05-mastery/01-algorithms.md +++ b/data/Java/data/05-mastery/01-algorithms.md @@ -1,41 +1,208 @@ -# Lesson 01 — Algorithms in Java +# Lesson 01 — Algorithms and Data Structures -**Module 05 · Mastery · Lesson 01 of 04** +**Module 05 · Mastery · Lesson 01 of 03** +## Learning Objectives -## Learning objectives - -- Understand **algorithms in java** in Java -- Read and write small examples you can run locally -- Connect this topic to the next lesson in the course +- Implement and analyse common sorting and searching algorithms +- Understand Big-O notation for time and space complexity +- Implement core data structures: Stack, Queue, LinkedList, Binary Search Tree ## Overview -Algorithms in Java is a core topic on the PolyCode **Java Certificate Course** path. Work through the examples, then try the exercise before moving on. +Algorithms and data structures are the foundation of computer science and a staple of technical interviews. This lesson covers the essential algorithms every Java developer must know, with clean implementations and Big-O analysis. + +## Key Concepts + +### 1. Big-O Cheat Sheet + +| Complexity | Name | Example | +|-----------|------|---------| +| O(1) | Constant | Array access, HashMap get | +| O(log n) | Logarithmic | Binary search | +| O(n) | Linear | Loop through array | +| O(n log n) | Log-linear | Merge sort, quick sort | +| O(n²) | Quadratic | Bubble sort, nested loops | +| O(2ⁿ) | Exponential | Recursive Fibonacci | + +### 2. Sorting Algorithms + +#### Bubble Sort — O(n²) +```java +public static void bubbleSort(int[] arr) { + int n = arr.length; + for (int i = 0; i < n - 1; i++) { + for (int j = 0; j < n - i - 1; j++) { + if (arr[j] > arr[j + 1]) { + int temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + } + } + } +} +``` + +#### Merge Sort — O(n log n) +```java +public static void mergeSort(int[] arr, int left, int right) { + if (left >= right) return; + int mid = (left + right) / 2; + mergeSort(arr, left, mid); + mergeSort(arr, mid + 1, right); + merge(arr, left, mid, right); +} + +private static void merge(int[] arr, int left, int mid, int right) { + int[] temp = Arrays.copyOfRange(arr, left, right + 1); + int i = 0, j = mid - left + 1, k = left; + while (i <= mid - left && j <= right - left) { + arr[k++] = (temp[i] <= temp[j]) ? temp[i++] : temp[j++]; + } + while (i <= mid - left) arr[k++] = temp[i++]; + while (j <= right - left) arr[k++] = temp[j++]; +} +``` + +### 3. Searching Algorithms + +#### Linear Search — O(n) +```java +public static int linearSearch(int[] arr, int target) { + for (int i = 0; i < arr.length; i++) { + if (arr[i] == target) return i; + } + return -1; +} +``` + +#### Binary Search — O(log n) — array must be sorted! +```java +public static int binarySearch(int[] arr, int target) { + int left = 0, right = arr.length - 1; + while (left <= right) { + int mid = left + (right - left) / 2; // avoids overflow + if (arr[mid] == target) return mid; + else if (arr[mid] < target) left = mid + 1; + else right = mid - 1; + } + return -1; +} +``` -## Key concepts +### 4. Data Structures -1. **Syntax and structure** — how Java expresses this idea clearly -2. **Common patterns** — what you will see in real projects -3. **Mistakes to avoid** — typical beginner errors and fixes +#### Stack (LIFO) +```java +public class Stack { + private final LinkedList list = new LinkedList<>(); + + public void push(T item) { list.addFirst(item); } + public T pop() { return list.removeFirst(); } + public T peek() { return list.getFirst(); } + public boolean isEmpty() { return list.isEmpty(); } + public int size() { return list.size(); } +} +``` -## Example +#### Queue (FIFO) +```java +public class Queue { + private final LinkedList list = new LinkedList<>(); + + public void enqueue(T item) { list.addLast(item); } + public T dequeue() { return list.removeFirst(); } + public T peek() { return list.getFirst(); } + public boolean isEmpty() { return list.isEmpty(); } +} +``` +#### Binary Search Tree ```java -// Algorithms in Java — practice sketch -// add your code here +public class BST { + private int value; + private BST left, right; + + public BST(int value) { this.value = value; } + + public BST insert(int val) { + if (val < value) { + if (left == null) left = new BST(val); + else left.insert(val); + } else { + if (right == null) right = new BST(val); + else right.insert(val); + } + return this; + } + + public boolean contains(int val) { + if (val == value) return true; + if (val < value) return left != null && left.contains(val); + return right != null && right.contains(val); + } + + // In-order traversal prints sorted values + public void inOrder() { + if (left != null) left.inOrder(); + System.out.print(value + " "); + if (right != null) right.inOrder(); + } +} +``` + +## Full Example + +```java +import java.util.Arrays; + +public class AlgorithmsDemo { + public static void main(String[] args) { + int[] arr = {64, 34, 25, 12, 22, 11, 90}; + System.out.println("Original: " + Arrays.toString(arr)); + + int[] toSort = arr.clone(); + mergeSort(toSort, 0, toSort.length - 1); + System.out.println("Sorted: " + Arrays.toString(toSort)); + + int target = 25; + System.out.println("Binary search for " + target + ": index " + + binarySearch(toSort, target)); + + // BST demo + BST tree = new BST(50); + for (int v : new int[]{30, 70, 20, 40, 60, 80}) tree.insert(v); + System.out.print("In-order: "); + tree.inOrder(); + System.out.println(); + System.out.println("Contains 40: " + tree.contains(40)); + System.out.println("Contains 45: " + tree.contains(45)); + } +} +``` + +**Expected output:** +``` +Original: [64, 34, 25, 12, 22, 11, 90] +Sorted: [11, 12, 22, 25, 34, 64, 90] +Binary search for 25: index 3 +In-order: 20 30 40 50 60 70 80 +Contains 40: true +Contains 45: false ``` ## Exercise -1. Write a short program that uses today's topic. -2. Change one value and predict the output before running. -3. Explain the result in your own words (2–3 sentences). +1. Implement Quick Sort and benchmark it vs Merge Sort on 100,000 random integers. +2. Implement a `MinStack` — a stack that supports `push`, `pop`, `peek`, and `getMin` all in O(1). +3. Implement a doubly-linked list with `addFirst`, `addLast`, `removeFirst`, `removeLast`, and `reverse` operations. ## Checkpoint -You are ready for the next lesson when you can solve the exercise without copying the example. +You are ready for the next lesson when you can: +- Explain the Big-O of Bubble Sort, Merge Sort, and Binary Search +- Implement a BST insert and search from memory +- Write a Stack and Queue using a LinkedList --- - -**Next:** Continue to lesson 02 in this module. +**Next:** Lesson 02 — Design Patterns diff --git a/data/Java/data/05-mastery/02-data-structures.md b/data/Java/data/05-mastery/02-data-structures.md index 2dda60f5..78dfcef9 100644 --- a/data/Java/data/05-mastery/02-data-structures.md +++ b/data/Java/data/05-mastery/02-data-structures.md @@ -1,6 +1,6 @@ # Lesson 02 — Data Structures -**Module 05 · Mastery · Lesson 02 of 04** +**Module 05 · Mastery · Lesson 02 of 05** ## Learning objectives diff --git a/data/Java/data/05-mastery/03-capstone-projects.md b/data/Java/data/05-mastery/03-capstone-projects.md index 6059681f..96b016f4 100644 --- a/data/Java/data/05-mastery/03-capstone-projects.md +++ b/data/Java/data/05-mastery/03-capstone-projects.md @@ -1,6 +1,6 @@ # Lesson 03 — Capstone Projects -**Module 05 · Mastery · Lesson 03 of 04** +**Module 05 · Mastery · Lesson 03 of 05** ## Learning objectives diff --git a/data/Java/data/05-mastery/04-design-patterns.md b/data/Java/data/05-mastery/04-design-patterns.md new file mode 100644 index 00000000..97116874 --- /dev/null +++ b/data/Java/data/05-mastery/04-design-patterns.md @@ -0,0 +1,237 @@ +# Lesson 04 — Design Patterns + +**Module 05 · Mastery · Lesson 04 of 05** + +## Learning Objectives + +- Implement Singleton, Builder, Factory, Observer, and Strategy patterns +- Recognise which pattern solves which class of problem +- Identify these patterns already used in Java's standard library + +## Overview + +**Design patterns** are proven, named solutions to recurring design problems. They are the vocabulary of experienced developers — knowing them lets you communicate intent clearly and write code that is maintainable and extensible. + +## Key Patterns + +### 1. Singleton — One Instance Only + +```java +public class DatabaseConnection { + private static DatabaseConnection instance; + private final String url; + + private DatabaseConnection() { + url = System.getenv("DB_URL"); + } + + // Thread-safe lazy initialisation + public static synchronized DatabaseConnection getInstance() { + if (instance == null) { + instance = new DatabaseConnection(); + } + return instance; + } + + public String getUrl() { return url; } +} + +// Usage — always the same object: +DatabaseConnection conn1 = DatabaseConnection.getInstance(); +DatabaseConnection conn2 = DatabaseConnection.getInstance(); +System.out.println(conn1 == conn2); // true +``` + +**In Java stdlib:** `Runtime.getRuntime()`, `System.console()` + +### 2. Builder — Construct Complex Objects Step-by-Step + +```java +public class HttpRequest { + private final String method; + private final String url; + private final Map headers; + private final String body; + + private HttpRequest(Builder builder) { + this.method = builder.method; + this.url = builder.url; + this.headers = builder.headers; + this.body = builder.body; + } + + public static class Builder { + private String method = "GET"; + private String url; + private Map headers = new HashMap<>(); + private String body; + + public Builder url(String url) { this.url = url; return this; } + public Builder method(String m) { this.method = m; return this; } + public Builder header(String k, String v) { headers.put(k, v); return this; } + public Builder body(String body) { this.body = body; return this; } + public HttpRequest build() { return new HttpRequest(this); } + } +} + +// Usage (fluent API): +HttpRequest req = new HttpRequest.Builder() + .url("https://api.example.com/students") + .method("POST") + .header("Content-Type", "application/json") + .header("Authorization", "Bearer token123") + .body("{\"name\":\"Alice\"}") + .build(); +``` + +**In Java stdlib:** `StringBuilder`, `Stream.Builder`, `Locale.Builder` + +### 3. Factory Method — Let Subclasses Decide What to Create + +```java +public interface Notification { + void send(String message); +} + +public class EmailNotification implements Notification { + private final String email; + public EmailNotification(String email) { this.email = email; } + @Override public void send(String msg) { + System.out.println("Email to " + email + ": " + msg); + } +} + +public class SMSNotification implements Notification { + private final String phone; + public SMSNotification(String phone) { this.phone = phone; } + @Override public void send(String msg) { + System.out.println("SMS to " + phone + ": " + msg); + } +} + +// Factory +public class NotificationFactory { + public static Notification create(String type, String recipient) { + return switch (type.toLowerCase()) { + case "email" -> new EmailNotification(recipient); + case "sms" -> new SMSNotification(recipient); + default -> throw new IllegalArgumentException("Unknown type: " + type); + }; + } +} + +// Usage: +Notification n = NotificationFactory.create("email", "alice@example.com"); +n.send("Your order has shipped!"); +``` + +### 4. Observer — Notify Many Listeners of Events + +```java +public interface EventListener { + void onEvent(T event); +} + +public class EventBus { + private final List> listeners = new ArrayList<>(); + + public void subscribe(EventListener listener) { listeners.add(listener); } + public void unsubscribe(EventListener listener) { listeners.remove(listener); } + public void publish(T event) { listeners.forEach(l -> l.onEvent(event)); } +} + +// Usage: +EventBus bus = new EventBus<>(); +bus.subscribe(msg -> System.out.println("Logger: " + msg)); +bus.subscribe(msg -> System.out.println("Notifier: " + msg.toUpperCase())); +bus.publish("User logged in"); +// Logger: User logged in +// Notifier: USER LOGGED IN +``` + +**In Java stdlib:** `java.util.Observable`, button listeners in Swing/JavaFX, Spring's `ApplicationEventPublisher` + +### 5. Strategy — Swap Algorithms at Runtime + +```java +@FunctionalInterface +public interface SortStrategy { + void sort(int[] arr); +} + +public class Sorter { + private SortStrategy strategy; + + public Sorter(SortStrategy strategy) { this.strategy = strategy; } + public void setStrategy(SortStrategy strategy) { this.strategy = strategy; } + public void sort(int[] arr) { strategy.sort(arr); } +} + +// Strategies as lambdas +SortStrategy bubbleSort = arr -> { /* bubble sort */ }; +SortStrategy javaSort = Arrays::sort; + +Sorter sorter = new Sorter(javaSort); +int[] data = {5, 2, 8, 1}; +sorter.sort(data); // [1, 2, 5, 8] + +sorter.setStrategy(bubbleSort); // swap at runtime +sorter.sort(data); +``` + +**In Java stdlib:** `Comparator` in `Collections.sort()`, `ExecutorService` strategies + +## Full Example — Putting it Together + +```java +public class PatternDemo { + // Strategy pattern for payment processing + @FunctionalInterface + interface PaymentStrategy { boolean pay(double amount); } + + static class Order { + private final String id; + private final double total; + private final List log = new ArrayList<>(); + + public Order(String id, double total) { this.id = id; this.total = total; } + + public boolean checkout(PaymentStrategy payment) { + boolean success = payment.pay(total); + log.add(success ? "Payment of $" + total + " succeeded" + : "Payment failed"); + return success; + } + + public void printLog() { log.forEach(System.out::println); } + } + + public static void main(String[] args) { + PaymentStrategy creditCard = amount -> { System.out.println("Charging card $" + amount); return true; }; + PaymentStrategy paypal = amount -> { System.out.println("PayPal transfer $" + amount); return true; }; + PaymentStrategy declinedCard = amount -> { System.out.println("Card declined!"); return false; }; + + Order order = new Order("ORD-001", 149.99); + order.checkout(creditCard); + order.checkout(declinedCard); + order.checkout(paypal); + order.printLog(); + } +} +``` + +## Exercise + +1. Implement a **Decorator** pattern: create a `TextFormatter` interface, then wrap a base implementation with `BoldDecorator`, `ItalicDecorator`, and `UpperCaseDecorator` that can be combined. +2. Implement the **Command** pattern for a text editor with `TypeCommand`, `DeleteCommand`, and an undo stack. +3. Identify 3 design patterns used in the Spring Boot framework and explain where each is applied. + +## Checkpoint + +You are ready for the final lesson when you can: +- Implement all 5 patterns in this lesson from memory +- Explain the problem each pattern solves in one sentence +- Name where each pattern appears in Java's standard library + +--- +**Next:** Lesson 03 — Java Interview Preparation diff --git a/data/Java/data/05-mastery/04-interview-prep.md b/data/Java/data/05-mastery/05-interview-prep.md similarity index 92% rename from data/Java/data/05-mastery/04-interview-prep.md rename to data/Java/data/05-mastery/05-interview-prep.md index 0f0ea1a2..0d5e9eb6 100644 --- a/data/Java/data/05-mastery/04-interview-prep.md +++ b/data/Java/data/05-mastery/05-interview-prep.md @@ -1,6 +1,6 @@ -# Lesson 04 — Interview Preparation +# Lesson 05 — Interview Preparation -**Module 05 · Mastery · Lesson 04 of 04** +**Module 05 · Mastery · Lesson 05 of 05** ## Learning objectives