PracticalJava

Java Concepts with Code Examples

This project demonstrates various Java concepts through code examples. Each file in the project covers a specific topic, providing explanations and use cases.

Table of Contents

  1. Data Types
  2. Switch Expressions
  3. String Operations
  4. Input and Output
  5. Conditional Statements
  6. Loops
  7. Arrays
  8. Class Relationships
  9. Class Constructors
  10. Class Inheritance
  11. Polymorphism
  12. Class Equality
  13. Abstraction
  14. Comparables
  15. Comparators
  16. Lambda Function Interfaces
  17. Method References
  18. ArrayList
  19. LinkedList
  20. ArrayDeque
  21. HashSet
  22. TreeSet
  23. EnumSet
  24. LinkedHashSet
  25. PriorityQueue
  26. HashMap
  27. TreeMap
  28. EnumMap
  29. LinkedHashMap
  30. WeakHashMap
  31. IdentityHashMap
  32. Threads Basic
  33. Thread Synchronization
  34. FixedThreadPool
  35. CachedThreadPool
  36. SingleThreadExecutor
  37. ScheduledThreadPool

Data Types

File: _1_DataTypes.java

This file demonstrates the use of various data types in Java, including primitive types (int, float, char, etc.) and reference types (String, arrays, etc.).

public class _1_DataTypes {
    public static void main(String[] args) {
        int intVar = 2147483647;
        float floatVar = 3.14f;
        char charVar = 'A';
        boolean boolVar = true;
        String stringVar = "Hello, World!";
        int[] intArray = {10, 20, 30, 40, 50};

        System.out.println("Int Value: " + intVar);
        System.out.println("Float Value: " + floatVar);
        System.out.println("Char Value: " + charVar);
        System.out.println("Boolean Value: " + boolVar);
        System.out.println("String Value: " + stringVar);
        System.out.print("Array Elements: ");
        for (int num : intArray) {
            System.out.print(num + " ");
        }
    }
}

SwitchExpressions

File: _2_SwitchExpressions.java

This file demonstrates the use of switch expressions in Java, which provide a more concise and flexible way to handle multiple conditions.

public class _2_SwitchExpressions {
    enum Day {
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    }

    public static void main(String[] args) {
        int dayOfWeek = 5;
        Day today = Day.THURSDAY;
        String dayName = switch (dayOfWeek) {
            case 1 -> "Monday";
            case 2 -> "Tuesday";
            case 3 -> "Wednesday";
            case 4 -> "Thursday";
            case 5 -> "Friday";
            case 6 -> "Saturday";
            case 7 -> "Sunday";
            default -> "Invalid day";
        };
        System.out.println("Day of the week: " + dayName);
    }
}

StringOperations

  1. Important Properties:
    a. Strings are immutable - once created, their values cannot be changed.
    b. Java provides methods for string operations like concatenation,comparison, and searching.

  2. Common Operations:

    • Concatenation: Combining two strings.
    • Length: Finding the length of a string.
    • Substring: Extracting parts of a string.
    • Comparison: Comparing strings (equals, compareTo, etc.).
    • Case Conversion: Converting to upper/lower case.
    • Searching: Finding characters or substrings.
    • Replacing: Replacing parts of a string.

File: _3_StringOperations.java

This file demonstrates various string operations in Java, including concatenation, length, substring, comparison, case conversion, searching, and replacing.

public class _3_StringOperations {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "World";
        String str3 = new String("Java");

        String concatenated = str1 + " " + str2 + " " + str3;
        System.out.println("Concatenated String: " + concatenated);
        System.out.println("Length of str1: " + str1.length());
        System.out.println("Substring: " + concatenated.substring(6, 11));
        System.out.println("str3 equals str4 (case-sensitive): " + str3.equals("JAVA"));
        System.out.println("str3 equalsIgnoreCase str4: " + str3.equalsIgnoreCase("JAVA"));
        System.out.println("str4 in lowercase: " + "JAVA".toLowerCase());
        System.out.println("str3 in uppercase: " + str3.toUpperCase());
        System.out.println("Index of 'World': " + concatenated.indexOf("World"));
        System.out.println("Does concatenated contain 'Java'? " + concatenated.contains("Java"));
        System.out.println("Replaced String: " + concatenated.replace("World", "Universe"));
    }
}

InputOutputs

File: _4_InputOutputs.java

  1. Output:
    • Displaying information to the user or writing to a file.
    • Classes/Methods: System.out.print, System.out.println, System.out.printf.
  2. Use Cases Covered:
    • Accepting user input for different data types.
    • Handling formatted output for better readability.
    • Reading multi-line input using BufferedReader.
    • Demonstrating formatted strings using System.out.printf.

This file demonstrates various input and output operations in Java, including reading user input using Scanner and BufferedReader, and displaying output using System.out.print, System.out.println, and System.out.printf.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Scanner;

public class _4_InputOutputs {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Enter your name: ");
        String name = scanner.nextLine();

        System.out.print("Enter your age: ");
        int age = scanner.nextInt();

        System.out.print("Enter your GPA: ");
        double gpa = scanner.nextDouble();

        System.out.println("\nOutput:");
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
        System.out.printf("GPA: %.2f\n", gpa);

        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        try {
            System.out.print("Enter your favorite quote: ");
            String quote = reader.readLine();
            System.out.println("Your favorite quote is: \"" + quote + "\"");
        } catch (IOException e) {
            System.out.println("Error reading input: " + e.getMessage());
        }

        scanner.close();
    }
}

ConditionalStatements

File: _5_ConditionalStatements.java

This file demonstrates various conditional statements in Java, including if, if-else, else-if, and switch.

import java.util.Scanner;

public class _5_ConditionalStatements {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int number1 = 10;
        if (number1 > 5) {
            System.out.println("Number1 is greater than 5");
        }

        int number2 = 3;
        if (number2 > 5) {
            System.out.println("Number2 is greater than 5");
        } else {
            System.out.println("Number2 is less than or equal to 5");
        }

        int number3 = 15;
        if (number3 > 20) {
            System.out.println("Number3 is greater than 20");
        } else if (number3 > 10) {
            System.out.println("Number3 is greater than 10 but less than or equal to 20");
        } else {
            System.out.println("Number3 is less than or equal to 10");
        }

        System.out.print("Enter a number between 1 and 7 to represent a day of the week: ");
        int day = scanner.nextInt();
        String dayName;
        switch (day) {
            case 1:
                dayName = "Monday";
                break;
            case 2:
                dayName = "Tuesday";
                break;
            case 3:
                dayName = "Wednesday";
                break;
            case 4:
                dayName = "Thursday";
                break;
            case 5:
                dayName = "Friday";
                break;
            case 6:
                dayName = "Saturday";
                break;
            case 7:
                dayName = "Sunday";
                break;
            default:
                dayName = "Invalid day";
                break;
        }
        System.out.println("The day is: " + dayName);

        scanner.close();
    }
}

Loops

File: _6_Loops.java

public class _6_Loops {
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) {
            System.out.println("For Loop Iteration: " + i);
        }

        int j = 1;
        while (j <= 5) {
            System.out.println("While Loop Iteration: " + j);
            j++;
        }

        int k = 1;
        do {
            System.out.println("Do-While Loop Iteration: " + k);
            k++;
        } while (k <= 5);

        for (int row = 1; row <= 3; row++) {
            for (int col = 1; col <= 3; col++) {
                System.out.print(row + "," + col + " ");
            }
            System.out.println();
        }

        for (int i = 1; i <= 10; i++) {
            if (i == 6) {
                System.out.println("Breaking at i = " + i);
                break;
            }
            System.out.println(i);
        }

        for (int i = 1; i <= 10; i++) {
            if (i == 6) {
                continue;
            }
            System.out.println(i);
        }
    }
}

Arrays

File: _7_Arrays.java

This file demonstrates various operations on arrays in Java, including declaration, initialization, accessing elements, modifying elements, iterating over arrays, and performing array operations like finding the maximum, minimum, and calculating the sum.

public class _7_Arrays {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30, 40, 50};
        System.out.println("Array Elements: ");
        for (int number : numbers) {
            System.out.print(number + " ");
        }

        int firstElement = numbers[0];
        int lastElement = numbers[numbers.length - 1];
        System.out.println("\nFirst Element: " + firstElement);
        System.out.println("Last Element: " + lastElement);

        numbers[2] = 35;
        System.out.println("Modified Array: ");
        for (int number : numbers) {
            System.out.print(number + " ");
        }

        int sum = 0;
        for (int number : numbers) {
            sum += number;
        }
        System.out.println("\nSum of Array Elements: " + sum);

        int max = numbers[0];
        int min = numbers[0];
        for (int number : numbers) {
            if (number > max) {
                max = number;
            }
            if (number < min) {
                min = number;
            }
        }
        System.out.println("Maximum Element: " + max);
        System.out.println("Minimum Element: " + min);

        int elementToFind = 35;
        int index = -1;
        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i] == elementToFind) {
                index = i;
                break;
            }
        }
        if (index != -1) {
            System.out.println("Element " + elementToFind + " found at index " + index);
        } else {
            System.out.println("Element " + elementToFind +"not found");
        }

        
        int[][] matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
        
        System.out.println("2D Matrix: ");
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[i].length; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println();
        }

        int[] copiedArray = new int[numbers.length];
        System.arraycopy(numbers, 0, copiedArray, 0, numbers.length);
        System.out.println("Copied Array: ");
        for (int number : copiedArray) {
            System.out.print(number + " ");
        }
    }
}

Class Relationships

File: _8_ClassRelationshipsDemo.java

  1. Aggregation: A specialized form of Association where one class is a part of another class, but the objects involved can exist independently.
    • Represents a “has-a” relationship.
  2. Composition: A stronger form of Aggregation where one class contains and is responsible for the lifecycle of another class.
    • Also represents a “has-a” relationship, but the contained class cannot exist independently of the container.
  3. Inheritance: A relationship where one class (subclass) inherits the properties and behaviors of another class (superclass).
    • Represents an “is-a” relationship.
public class _8_ClassRelationshipsDemo {
    public static void main(String[] args) {
        Car car = new Car("Toyota");
        Engine engine = new Engine("V8");
        car.setEngine(engine);
        System.out.println(car.getBrand() + " car has engine: " + car.getEngine().getType());

        Department department = new Department("Computer Science");
        Professor professor = new Professor("Dr. Smith", department);
        System.out.println(professor.getName() + " is part of " + professor.getDepartment().getName() + " department.");

        House house = new House("Red");
        house.addRoom(new Room("Living Room"));
        house.showRooms();

        Dog dog = new Dog("Buddy", 5);
        dog.eat();
        dog.bark();
    }
}

class Car {
    private String brand;
    private Engine engine;

    public Car(String brand) {
        this.brand = brand;
    }

    public String getBrand() {
        return brand;
    }

    public Engine getEngine() {
        return engine;
    }

    public void setEngine(Engine engine) {
        this.engine = engine;
    }
}

class Engine {
    private String type;

    public Engine(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }
}

class Department {
    private String name;

    public Department(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

class Professor {
    private String name;
    private Department department;

    public Professor(String name, Department department) {
        this.name = name;
        this.department = department;
    }

    public String getName() {
        return name;
    }

    public Department getDepartment() {
        return department;
    }
}

class House {
    private String color;
    private Room room;

    public House(String color) {
        this.color = color;
    }

    public void addRoom(Room room) {
        this.room = room;
    }

    public void showRooms() {
        System.out.println("House color: " + color + ", with room: " + room.getName());
    }
}

class Room {
    private String name;

    public Room(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

class Animal {
    private String name;
    private int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat() {
        System.out.println(name + " is eating.");
    }
}

class Dog extends Animal {
    public Dog(String name, int age) {
        super(name, age);
    }

    public void bark() {
        System.out.println("Woof! Woof!");
    }
}

Class Constructors

File: _9_ClassConstructors.java

Types of Constructors:

  1. Default Constructor: A constructor that has no parameters and initializes the object with default values.
  2. Parameterized Constructor: A constructor that takes parameters to initialize the object with specific values.
  3. Copy Constructor: A constructor used to create a new object as a copy of an existing object (not natively available in Java, but can be manually defined).
public class _9_ClassConstructors {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        emp1.displayInfo();

        Employee emp2 = new Employee(101, "Alice", 5000);
        emp2.displayInfo();

        Employee emp3 = new Employee(102, "Bob");
        emp3.displayInfo();

        Employee emp4 = new Employee(emp2);
        emp4.displayInfo();
    }
}

class Employee {
    private int id;
    private String name;
    private double salary;

    public Employee() {
        this.id = 0;
        this.name = "Unknown";
        this.salary = 0.0;
    }

    public Employee(int id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
        this.salary = 0.0;
    }

    public Employee(Employee other) {
        this.id = other.id;
        this.name = other.name;
        this.salary = other.salary;
    }

    public void displayInfo() {
        System.out.println("Employee ID: " + id + ", Name: " + name + ", Salary: " + salary);
    }
}

Class Inheritance

File: 10_ClassInheritance.java

Key Concepts:

  1. Superclass: The class whose properties and methods are inherited by another class.
  2. Subclass/DerivedClass: The class that inherits the properties and methods from another class.
  3. “is-a” Relationship: A subclass is a specialized version of the superclass.

Example Explanation:

public class _10_ClassInheritance {

    public static void main(String[] args) {
        // Creating an Employee object
        Employee emp = new Employee(101, "John Doe", 3000);
        emp.displayInfo();  // Displaying employee information

        // Creating a Manager object (which is also an Employee)
        Manager mgr = new Manager(102, "Alice Johnson", 5000, "Marketing");
        mgr.displayInfo();  // Displaying manager information
        mgr.manageTeam();  // Manager-specific method
    }
}

// Superclass - Employee
class Employee {
    private int id;
    private String name;
    private double salary;

    // Constructor to initialize Employee object
    public Employee(int id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    // Method to display Employee information
    public void displayInfo() {
        System.out.println("Employee ID: " + id + ", Name: " + name + ", Salary: " + salary);
    }
}

// Subclass - Manager (inherits from Employee)
class Manager extends Employee {
    private String department;

    // Constructor to initialize Manager object (calls superclass constructor)
    public Manager(int id, String name, double salary, String department) {
        super(id, name, salary);  // Calling the constructor of the superclass (Employee)
        this.department = department;
    }

    // Method to display Manager information
    @Override
    public void displayInfo() {
        // Overriding the displayInfo method to add the department for Manager
        super.displayInfo();  // Calling superclass method
        System.out.println("Department: " + department);
    }

    // Manager-specific method
    public void manageTeam() {
        System.out.println("Managing the " + department + " team.");
    }
}

Polymorphism

File: 11_Polymorphism.java

  1. Compile-time Polymorphism (Method Overloading):
    • This occurs when two or more methods in the same class have the same name but different parameters.
    • It is resolved at compile time.
  2. Runtime Polymorphism (Method Overriding):
    • This occurs when a subclass provides a specific implementation of a method that is already defined in the superclass.
    • It is resolved at runtime.

public class _11_Polymorphism {

    public static void main(String[] args) {

        // Demonstrating Compile-time Polymorphism (Method Overloading)
        System.out.println("=== Method Overloading (Compile-time Polymorphism) ===");
        Calculator calc = new Calculator();
        System.out.println("Sum (int): " + calc.add(5, 10));
        System.out.println("Sum (double): " + calc.add(5.5, 10.5));
        System.out.println("Sum (int, double): " + calc.add(5, 10.5));

        // Demonstrating Runtime Polymorphism (Method Overriding)
        System.out.println("\n=== Method Overriding (Runtime Polymorphism) ===");
        Animal animal = new Animal();
        Dog dog = new Dog();
        animal.sound();  // Calls Animal's sound method
        dog.sound();     // Calls Dog's overridden sound method
        
        // Demonstrating Polymorphism with Interfaces
        System.out.println("\n=== Polymorphism with Interfaces ===");
        Vehicle car = new Car();
        Vehicle bike = new Bike();
        car.start();     // Calls Car's start method
        bike.start();    // Calls Bike's start method
    }
}

// Class demonstrating Compile-time Polymorphism (Method Overloading)
class Calculator {

    // Method to add two integers
    public int add(int a, int b) {
        return a + b;
    }

    // Method to add two doubles
    public double add(double a, double b) {
        return a + b;
    }

    // Method to add an integer and a double
    public double add(int a, double b) {
        return a + b;
    }
}

// Class demonstrating Runtime Polymorphism (Method Overriding)
class Animal {
    
    // Method in the superclass (Animal)
    public void sound() {
        System.out.println("Animals make sounds.");
    }
}

// Subclass of Animal that overrides the sound method
class Dog extends Animal {
    
    // Overriding the sound method
    @Override
    public void sound() {
        System.out.println("The dog barks.");
    }
}

// Interface demonstrating Polymorphism across different classes
interface Vehicle {
    void start();  // Method to start the vehicle
}

// Class implementing Vehicle interface
class Car implements Vehicle {

    // Implementing start method for Car
    @Override
    public void start() {
        System.out.println("The car is starting.");
    }
}

// Class implementing Vehicle interface
class Bike implements Vehicle {

    // Implementing start method for Bike
    @Override
    public void start() {
        System.out.println("The bike is starting.");
    }
}

Class Equality

File: _12_ClassEquality.java


public class _12_ClassEquality {

    public static void main(String[] args) {

        // Example 1: Reference Equality (using '==')
        System.out.println("=== Reference Equality (using '==') ===");
        Person person1 = new Person("John", 25);
        Person person2 = person1; // Both references point to the same object.
        Person person3 = new Person("John", 25); // Different object with same content.
        System.out.println("person1 == person2: " + (person1 == person2)); // True, both point to the same object
        System.out.println("person1 == person3: " + (person1 == person3)); // False, different objects in memory

        // Example 2: Logical Equality (using overridden 'equals()' method)
        System.out.println("\n=== Logical Equality (using 'equals()') ===");
        System.out.println("person1.equals(person3): " + person1.equals(person3)); // True, same content

        // Example 3: Using 'equals()' in Collections
        System.out.println("\n=== Equality in Collections ===");
        java.util.List<Person> personList = new java.util.ArrayList<>();
        personList.add(person1);
        personList.add(person3);
        System.out.println("List contains person3: " + personList.contains(person3)); // True, 'equals' used for comparison

        // Example 4: Equality with Different Types
        System.out.println("\n=== Comparing Objects of Different Types ===");
        System.out.println("person1.equals(new Car()): " + person1.equals(new Car())); // False, different types
    }
}

// Class representing a Person
class Person {
    private String name;
    private int age;

    // Constructor
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Overriding equals() to check logical equality based on name and age
    @Override
    public boolean equals(Object obj) {
        // Check for self-equality
        if (this == obj) {
            return true;
        }
        // Check for null and type mismatch
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        // Cast the object to the appropriate type
        Person person = (Person) obj;
        return age == person.age && name.equals(person.name); // Compare based on field values
    }

    @Override
    public int hashCode() {
        // Generate a hash code based on the fields for proper hash-based collections (like HashSet)
        return 31 * name.hashCode() + age;
    }
}

// Class representing a Car (for demonstrating different types comparison)
class Car {
    private String model;

    // Constructor
    public Car() {
        this.model = "Sedan";
    }

    // Not overriding equals() for Car, so it uses Object's equals() by default (reference equality)
    @Override
    public boolean equals(Object obj) {
        return false; // Cars are not equal to other objects by default
    }
}

Abstraction

File: _13_Abstraction.java


public class _13_Abstraction {

    public static void main(String[] args) {
        
        // Using the abstract class and concrete classes
        System.out.println("=== Using Abstract Class ===");
        Vehicle car = new Car(); // Car is a concrete subclass of Vehicle
        car.start();  // Calls start() from Car
        car.stop();   // Calls stop() from Vehicle
        
        // Using the interface
        System.out.println("\n=== Using Interface ===");
        Car engine = new Car(); // Car implements Engine
        engine.startEngine();  // Calls startEngine() from Engine interface
    }
}

// Abstract class representing a general Vehicle
abstract class Vehicle {
    public Vehicle() {
        System.out.println("Vehicle object created.");
    }
    // Abstract method - no implementation, must be overridden by subclasses
    public abstract void start();

    // Regular method with implementation
    public void stop() {
        System.out.println("Vehicle is stopping.");
    }
}

// Concrete class extending Vehicle and providing implementation for start method
class Car extends Vehicle implements Engine {

    public Car() {
        super();
        System.out.println("Car object created.");
    }
    @Override
    public void start() {
        System.out.println("Car is starting.");
    }

    @Override
    public void startEngine() {
        System.out.println("Car engine is starting.");
    }
}

// Interface representing an Engine
interface Engine {
    // Abstract method to be implemented by any class that implements this interface
    void startEngine();
}

Comparable Interfaces

File: _15_Comparables.java


import java.util.*;

public class _15_Comparables {

    public static void main(String[] args) {
        
        // Create a list of Employee objects
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee("John", 45000));
        employees.add(new Employee("Alice", 55000));
        employees.add(new Employee("Bob", 35000));
        employees.add(new Employee("Diana", 40000));
        
        // Sort the list of employees using Collections.sort(), which uses compareTo()
        Collections.sort(employees);
        
        // Display the sorted list of employees by salary
        System.out.println("Employees sorted by salary:");
        for (Employee emp : employees) {
            System.out.println(emp);
        }
    }
}

// Employee class implements Comparable to compare employees by salary
class Employee implements Comparable<Employee> {

    private String name;
    private double salary;

    // Constructor
    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    // Getter for salary
    public double getSalary() {
        return salary;
    }

    // Implement the compareTo method to compare employees by salary
    @Override
    public int compareTo(Employee other) {
        // Compare the current object's salary with another Employee's salary
        if (this.salary < other.salary) {
            return -1; // This employee's salary is less
        } else if (this.salary > other.salary) {
            return 1;  // This employee's salary is greater
        }
        return 0;  // Salaries are equal
    }

    // Override toString method to display employee details
    @Override
    public String toString() {
        return name + " - $" + salary;
    }
}

Comparators

File: _16_Comparators.java


 import java.util.*;

 public class _16_Comparators {
 
     public static void main(String[] args) {
 
         // Create a list of Employee objects
         List<Employee> employees = new ArrayList<>();
         employees.add(new Employee("John", 45000));
         employees.add(new Employee("Alice", 55000));
         employees.add(new Employee("Bob", 35000));
         employees.add(new Employee("Diana", 40000));
         
         // Sort the employees first by name, and if equal, by salary
         Collections.sort(employees, new EmployeeNameSalaryComparator());
         
         // Display the sorted list of employees
         System.out.println("Employees sorted by name and salary:");
         for (Employee emp : employees) {
             System.out.println(emp);
         }

            // Sort the employees by name
        Collections.sort(employees, new EmployeeNameComparator());
        System.out.println("Employees sorted by name:");
        for (Employee emp : employees) {
            System.out.println(emp);
        }
     }
 }
 
 // Employee class with name and salary attributes
 class Employee {
 
     private String name;
     private double salary;
 
     // Constructor with parameters
     public Employee(String name, double salary) {
         this.name = name;
         this.salary = salary;
     }
 
     // Getter for name
     public String getName() {
         return name;
     }
 
     // Getter for salary
     public double getSalary() {
         return salary;
     }
 
     // Override toString to display employee details
     @Override
     public String toString() {
         return name + " - $" + salary;
     }
 }
 
 // Comparator to sort Employee objects first by name, then by salary
 class EmployeeNameSalaryComparator implements Comparator<Employee> {
 
     @Override
     public int compare(Employee e1, Employee e2) {
         // First compare by name
         int nameComparison = e1.getName().compareTo(e2.getName());
         if (nameComparison != 0) {
             return nameComparison;
         }
 
         // If names are the same, compare by salary
         return Double.compare(e1.getSalary(), e2.getSalary());
     }
 }

 // Comparator to sort by name
 class EmployeeNameComparator implements Comparator<Employee>{
    @Override
    public int compare(Employee e1, Employee e2){
        return e1.getName().compareTo(e2.getName());
    }
 }

Lambda and Functional Interfaces

File: _17_LambdaFunctionInterfaces.java

 import java.util.*;
 import java.util.function.*;
 
 public class _17_LambdaFunctionInterfaces {
 
     public static void main(String[] args) {
 
         // Example 1: Runnable Interface with Lambda Expression
         Runnable task = () -> {
             System.out.println("Running in a separate thread!");
         };
 
         // Starting the thread
         Thread thread = new Thread(task);
         thread.start();
 
         // Example 2: Comparator Interface with Lambda Expression
         List<Employee> employees = new ArrayList<>();
         employees.add(new Employee("John", 45000));
         employees.add(new Employee("Alice", 55000));
         employees.add(new Employee("Bob", 35000));
         employees.add(new Employee("Diana", 40000));
 
         // Sorting employees by name using lambda expression
         employees.sort((e1, e2) -> e1.getName().compareTo(e2.getName()));
         System.out.println("Employees sorted by name:");
         employees.forEach(emp -> System.out.println(emp));
 
         // Sorting employees by salary using lambda expression
         employees.sort((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
         System.out.println("\nEmployees sorted by salary:");
         employees.forEach(emp -> System.out.println(emp));
 
         // Example 3: Predicate Interface with Lambda Expression
         Predicate<Employee> salaryPredicate = emp -> emp.getSalary() > 40000;
         List<Employee> highSalaryEmployees = filterEmployees(employees, salaryPredicate);
         System.out.println("\nEmployees with salary greater than 40000:");
         highSalaryEmployees.forEach(emp -> System.out.println(emp));
 
         // Example 4: Function Interface with Lambda Expression
         Function<Employee, Double> salaryInUSD = emp -> emp.getSalary() * 1.1;
         System.out.println("\nEmployees' salaries in USD:");
         employees.forEach(emp -> System.out.println(emp.getName() + ": " + salaryInUSD.apply(emp)));
     }
 
     // Method to filter employees based on a given predicate
     public static List<Employee> filterEmployees(List<Employee> employees, Predicate<Employee> predicate) {
         List<Employee> filteredList = new ArrayList<>();
         for (Employee emp : employees) {
             if (predicate.test(emp)) {
                 filteredList.add(emp);
             }
         }
         return filteredList;
     }
 }
 
 // Employee class with name and salary attributes
 class Employee {
 
     private String name;
     private double salary;
 
     // Constructor with parameters
     public Employee(String name, double salary) {
         this.name = name;
         this.salary = salary;
     }
 
     // Getter for name
     public String getName() {
         return name;
     }
 
     // Getter for salary
     public double getSalary() {
         return salary;
     }
 
     // Override toString to display employee details
     @Override
     public String toString() {
         return name + " - $" + salary;
     }
 }

Method References

File: _18_MethodReferences.java

 import java.util.*;
 import java.util.function.*;
 
 public class _18_MethodReferences {
 
     public static void main(String[] args) {
 
         // Example 1: Static Method Reference
         List<String> names = Arrays.asList("John", "Alice", "Bob", "Diana");
         
         // Using method reference to call the static method `printName`
         names.forEach(MethodReferenceDemo::printName);
 
         // Example 2: Instance Method Reference
         Employee emp1 = new Employee("John", 45000);
         Employee emp2 = new Employee("Alice", 55000);
         Employee emp3 = new Employee("Bob", 35000);
         
         // Using method reference to call instance method `printEmployee`
         List<Employee> employees = Arrays.asList(emp1, emp2, emp3);
         employees.forEach(Employee::printEmployee);
 
         // Example 3: Instance Method Reference on an Arbitrary Object of a Particular Type
         List<String> strings = Arrays.asList("hello", "world", "java");
         
         // Using method reference to call `toUpperCase` instance method
         strings.replaceAll(String::toUpperCase);
         System.out.println("\nUpdated list of strings in uppercase:");
         strings.forEach(System.out::println);
 
         // Example 4: Constructor Reference
         // Using method reference to create a new Employee using the constructor
         List<Employee> newEmployees = Arrays.asList("John", "Alice", "Bob", "Diana")
                                              .stream()
                                              .map(Employee::new) // Constructor reference to create Employee object
                                              .toList();
         System.out.println("\nNew Employees:");
         newEmployees.forEach(System.out::println);
     }
 
     // Static method to print the name
     public static void printName(String name) {
         System.out.println(name);
     }
 
 }
 
 // Employee class with name and salary attributes
 class Employee {
 
     private String name;
     private double salary;
 
     // Constructor with name and salary
     public Employee(String name) {
         this.name = name;
         this.salary = 40000;  // Default salary
     }
 
     // Instance method to print employee details
     public void printEmployee() {
         System.out.println(name + " - $" + salary);
     }
 
     // Override toString to display employee details
     @Override
     public String toString() {
         return name + " - $" + salary;
     }
 }

ArrayList Operations

File: _19_ArrayList.java

 import java.util.*;

 class Employee {
     private String name;
     private double salary;
 
     // Constructor
     public Employee(String name, double salary) {
         this.name = name;
         this.salary = salary;
     }
 
     // Getter for name
     public String getName() {
         return name;
     }
 
     // Getter for salary
     public double getSalary() {
         return salary;
     }
 
     // Override toString() for displaying employee details
     @Override
     public String toString() {
         return "Employee{name='" + name + "', salary=" + salary + "}";
     }
 }
 
 public class _19_ArrayList {
 
     public static void main(String[] args) {
         
         // Create an ArrayList of Employee objects
         ArrayList<Employee> employees = new ArrayList<>();
 
         // Add Employee objects to the ArrayList
         employees.add(new Employee("John", 50000));
         employees.add(new Employee("Alice", 60000));
         employees.add(new Employee("Bob", 45000));
         employees.add(new Employee("Diana", 55000));
 
         // Display the ArrayList of employees
         System.out.println("Employee List:");
         for (Employee emp : employees) {
             System.out.println(emp);
         }
 
         // Example 1: Iterating through the ArrayList using an Iterator
         System.out.println("\nIterating using Iterator:");
         Iterator<Employee> iterator = employees.iterator();
         while (iterator.hasNext()) {
             Employee emp = iterator.next();
             System.out.println(emp);
         }
 
         // Example 2: Iterating with Iterator and removing an element based on condition
         System.out.println("\nIterating and removing an employee with salary less than 50000:");
         iterator = employees.iterator(); // Resetting the iterator
         while (iterator.hasNext()) {
             Employee emp = iterator.next();
             if (emp.getSalary() < 50000) {
                 System.out.println("Removing: " + emp);
                 iterator.remove(); // Remove the element
             }
         }
 
         // Display the ArrayList after removal
         System.out.println("\nEmployee List after removal:");
         for (Employee emp : employees) {
             System.out.println(emp);
         }

         
        // Example 1: Creating an ArrayList and adding elements
        ArrayList<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");
        list.add("Date");
        
        System.out.println("Original List: " + list);
        
        // Example 2: Accessing elements using get()
        String element = list.get(1); // Get the element at index 1 (Banana)
        System.out.println("Element at index 1: " + element);
        
        // Example 3: Removing an element by index
        list.remove(2); // Remove the element at index 2 (Cherry)
        System.out.println("After removing element at index 2: " + list);
        
        // Example 4: Checking the size of the ArrayList
        System.out.println("Size of the list: " + list.size());
        
        // Example 5: Checking if a specific element exists
        boolean containsBanana = list.contains("Banana");
        System.out.println("Does the list contain Banana? " + containsBanana);
        
        // Example 6: Iterating through the ArrayList using for-each loop
        System.out.println("Iterating through the list:");
        for (String fruit : list) {
            System.out.println(fruit);
        }
        
        // Example 7: Replacing an element at a specific index
        list.set(1, "Elderberry"); // Replace "Date" with "Elderberry"
        System.out.println("After replacing element at index 1: " + list);
        
        // Example 8: Clearing the ArrayList
        list.clear();
        System.out.println("After clearing the list: " + list);
        
        // Example 9: Checking if the list is empty
        System.out.println("Is the list empty? " + list.isEmpty());
     }
 }

LinkedList Operations

File: _20_LinkedList.java

 import java.util.*;

 class Employee {
     private String name;
     private double salary;
 
     // Constructor
     public Employee(String name, double salary) {
         this.name = name;
         this.salary = salary;
     }
 
     // Getter for name
     public String getName() {
         return name;
     }
 
     // Getter for salary
     public double getSalary() {
         return salary;
     }
 
     // Setter for salary
     public void setSalary(double salary) {
         this.salary = salary;
     }
 
     // Override toString() for displaying employee details
     @Override
     public String toString() {
         return "Employee{name='" + name + "', salary=" + salary + "}";
     }
 }
 
 public class _20_LinkedList {
 
     public static void main(String[] args) {
         
         // Create a LinkedList of Employee objects
         LinkedList<Employee> employees = new LinkedList<>();
 
         // Add Employee objects to the LinkedList
         employees.add(new Employee("John", 50000));
         employees.add(new Employee("Alice", 60000));
         employees.add(new Employee("Bob", 45000));
         employees.add(new Employee("Diana", 55000));
 
         // Display the LinkedList of employees
         System.out.println("Employee List:");
         for (Employee emp : employees) {
             System.out.println(emp);
         }
 
         // Example 1: Iterating through the LinkedList using an Iterator
         System.out.println("\nIterating using Iterator:");
         Iterator<Employee> iterator = employees.iterator();
         while (iterator.hasNext()) {
             Employee emp = iterator.next();
             System.out.println(emp);
         }
 
         // Example 2: Removing an employee from the LinkedList
         System.out.println("\nRemoving employee with name 'Bob':");
         iterator = employees.iterator(); // Resetting the iterator
         while (iterator.hasNext()) {
             Employee emp = iterator.next();
             if ("Bob".equals(emp.getName())) {
                 System.out.println("Removing: " + emp);
                 iterator.remove(); // Remove the element
             }
         }
 
         // Display the LinkedList after removal
         System.out.println("\nEmployee List after removal:");
         for (Employee emp : employees) {
             System.out.println(emp);
         }
 
         // Example 3: Modifying an employee's salary
         System.out.println("\nModifying salary of 'Alice':");
         for (Employee emp : employees) {
             if ("Alice".equals(emp.getName())) {
                 emp.setSalary(65000); // Updating salary
                 System.out.println("Updated Salary: " + emp);
             }
         }
 
         // Display the LinkedList after salary update
         System.out.println("\nEmployee List after salary update:");
         for (Employee emp : employees) {
             System.out.println(emp);
         }
     }
 }

ArrayDeque Operations

File: _21_ArrayDeque.java


 import java.util.*;

 class Employee {
     private String name;
     private double salary;
 
     // Constructor
     public Employee(String name, double salary) {
         this.name = name;
         this.salary = salary;
     }
 
     // Getter for name
     public String getName() {
         return name;
     }
 
     // Getter for salary
     public double getSalary() {
         return salary;
     }
 
     // Override toString() for displaying employee details
     @Override
     public String toString() {
         return "Employee{name='" + name + "', salary=" + salary + "}";
     }
 }
 
 public class _21_ArrayDeque {
 
     public static void main(String[] args) {
         
         // Create an ArrayDeque of Employee objects
         ArrayDeque<Employee> employees = new ArrayDeque<>();
 
         // Add Employee objects to the back of the deque
         employees.addLast(new Employee("John", 50000));
         employees.addLast(new Employee("Alice", 60000));
         employees.addLast(new Employee("Bob", 45000));
         employees.addLast(new Employee("Diana", 55000));
 
         // Display the ArrayDeque of employees
         System.out.println("Employee List (after addLast):");
         for (Employee emp : employees) {
             System.out.println(emp);
         }
 
         // Example 1: Adding an element to the front using addFirst()
         System.out.println("\nAdding an employee to the front:");
         employees.addFirst(new Employee("Eve", 70000));
 
         // Display the ArrayDeque after adding an employee at the front
         System.out.println("Employee List (after addFirst):");
         for (Employee emp : employees) {
             System.out.println(emp);
         }
 
         // Example 2: Removing an element from the front using removeFirst()
         System.out.println("\nRemoving employee from the front:");
         Employee removedFirst = employees.removeFirst();
         System.out.println("Removed: " + removedFirst);
 
         // Display the ArrayDeque after removal from the front
         System.out.println("\nEmployee List (after removeFirst):");
         for (Employee emp : employees) {
             System.out.println(emp);
         }
 
         // Example 3: Removing an element from the back using removeLast()
         System.out.println("\nRemoving employee from the back:");
         Employee removedLast = employees.removeLast();
         System.out.println("Removed: " + removedLast);
 
         // Display the ArrayDeque after removal from the back
         System.out.println("\nEmployee List (after removeLast):");
         for (Employee emp : employees) {
             System.out.println(emp);
         }
 
         // Example 4: Peeking at the first and last elements
         System.out.println("\nPeeking at the first and last elements:");
         Employee first = employees.peekFirst();
         Employee last = employees.peekLast();
         System.out.println("First Employee: " + first);
         System.out.println("Last Employee: " + last);
     }
 }

HashSet Operations

File: _22_HashSet.java


 import java.util.*;

 class Employee {
     private String name;
     private double salary;
 
     // Constructor
     public Employee(String name, double salary) {
         this.name = name;
         this.salary = salary;
     }
 
     // Getter for name
     public String getName() {
         return name;
     }
 
     // Getter for salary
     public double getSalary() {
         return salary;
     }
 
     // Override equals() and hashCode() to ensure uniqueness in HashSet
     @Override
     public boolean equals(Object obj) {
         if (this == obj) return true;
         if (obj == null || getClass() != obj.getClass()) return false;
         Employee employee = (Employee) obj;
         return Double.compare(employee.salary, salary) == 0 && Objects.equals(name, employee.name);
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(name, salary);
     }
 
     // Override toString() for displaying employee details
     @Override
     public String toString() {
         return "Employee{name='" + name + "', salary=" + salary + "}";
     }
 }
 
 public class _22_HashSet {
 
     public static void main(String[] args) {
         
         // Create a HashSet of Employee objects
         HashSet<Employee> employees = new HashSet<>();
 
         // Add Employee objects to the HashSet
         employees.add(new Employee("John", 50000));
         employees.add(new Employee("Alice", 60000));
         employees.add(new Employee("Bob", 45000));
         employees.add(new Employee("Diana", 55000));
 
         // Display the HashSet of employees
         System.out.println("Employee List (after add):");
         for (Employee emp : employees) {
             System.out.println(emp);
         }
 
         // Example 1: Attempting to add a duplicate employee
         System.out.println("\nAttempting to add a duplicate employee:");
         boolean isAdded = employees.add(new Employee("John", 50000));
         System.out.println("Was the duplicate added? " + isAdded); // Should be false, as 'John' already exists
 
         // Example 2: Checking if an employee exists
         System.out.println("\nChecking if 'Alice' is in the HashSet:");
         boolean exists = employees.contains(new Employee("Alice", 60000));
         System.out.println("Does Alice exist? " + exists); // Should be true
 
         // Example 3: Removing an employee from the HashSet
         System.out.println("\nRemoving employee 'Bob':");
         boolean isRemoved = employees.remove(new Employee("Bob", 45000));
         System.out.println("Was Bob removed? " + isRemoved); // Should be true
 
         // Display the HashSet after removal
         System.out.println("\nEmployee List (after remove):");
         for (Employee emp : employees) {
             System.out.println(emp);
         }
 
         // Example 4: Displaying the size of the HashSet
         System.out.println("\nSize of the HashSet: " + employees.size()); // Should return the number of employees
 
         // Example 5: Clearing the HashSet
         System.out.println("\nClearing the HashSet...");
         employees.clear();
         System.out.println("Is the HashSet empty? " + employees.isEmpty()); // Should return true
     }
 }

TreeSet Operations

File: _23_TreeSet.java

 import java.util.*;

 class Employee implements Comparable<Employee> {
     private String name;
     private double salary;
 
     // Constructor
     public Employee(String name, double salary) {
         this.name = name;
         this.salary = salary;
     }
 
     // Getter for name
     public String getName() {
         return name;
     }
 
     // Getter for salary
     public double getSalary() {
         return salary;
     }
 
     // Override compareTo() to define natural ordering by salary
     @Override
     public int compareTo(Employee other) {
         return Double.compare(this.salary, other.salary); // Sort by salary in ascending order
     }
 
     // Override toString() for displaying employee details
     @Override
     public String toString() {
         return "Employee{name='" + name + "', salary=" + salary + "}";
     }
 }
 
 public class _23_TreeSet {
 
     public static void main(String[] args) {
         
         // Create a TreeSet of Employee objects
         TreeSet<Employee> employees = new TreeSet<>();
 
         // Add Employee objects to the TreeSet
         employees.add(new Employee("John", 50000));
         employees.add(new Employee("Alice", 60000));
         employees.add(new Employee("Bob", 45000));
         employees.add(new Employee("Diana", 55000));
 
         // Display the TreeSet of employees (sorted by salary)
         System.out.println("Employee List (after add):");
         for (Employee emp : employees) {
             System.out.println(emp);
         }
 
         // Example 1: Attempting to add a duplicate employee
         System.out.println("\nAttempting to add a duplicate employee:");
         boolean isAdded = employees.add(new Employee("John", 50000));
         System.out.println("Was the duplicate added? " + isAdded); // Should be false, as 'John' already exists
 
         // Example 2: Checking if an employee exists
         System.out.println("\nChecking if 'Alice' is in the TreeSet:");
         boolean exists = employees.contains(new Employee("Alice", 60000));
         System.out.println("Does Alice exist? " + exists); // Should be true
 
         // Example 3: Removing an employee from the TreeSet
         System.out.println("\nRemoving employee 'Bob':");
         boolean isRemoved = employees.remove(new Employee("Bob", 45000));
         System.out.println("Was Bob removed? " + isRemoved); // Should be true
 
         // Display the TreeSet after removal
         System.out.println("\nEmployee List (after remove):");
         for (Employee emp : employees) {
             System.out.println(emp);
         }
 
         // Example 4: Displaying the size of the TreeSet
         System.out.println("\nSize of the TreeSet: " + employees.size()); // Should return the number of employees
 
         // Example 5: Displaying the first and last elements in the TreeSet
         System.out.println("\nFirst Employee (lowest salary): " + employees.first()); // Should return employee with lowest salary
         System.out.println("Last Employee (highest salary): " + employees.last()); // Should return employee with highest salary
 
         // Example 6: Clearing the TreeSet
         System.out.println("\nClearing the TreeSet...");
         employees.clear();
         System.out.println("Is the TreeSet empty? " + employees.isEmpty()); // Should return true
     }
 }

EnumSet Operations

File: _24_EnumSet.java

 import java.util.EnumSet;

 enum Day {
     MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
 }
 
 public class _24_EnumSet {
 
     public static void main(String[] args) {
         
         // Create an EnumSet containing Monday, Wednesday, and Friday
         EnumSet<Day> weekendDays = EnumSet.of(Day.SATURDAY, Day.SUNDAY);
         EnumSet<Day> workDays = EnumSet.range(Day.MONDAY, Day.FRIDAY);
         
         // Display the contents of the EnumSet
         System.out.println("Weekend Days: " + weekendDays);
         System.out.println("Work Days: " + workDays);
 
         // Example 1: Adding elements to the EnumSet
         workDays.add(Day.TUESDAY); // Adding a day to workDays
         System.out.println("\nAfter adding Tuesday to workDays: " + workDays);
 
         // Example 2: Removing elements from the EnumSet
         workDays.remove(Day.MONDAY); // Removing Monday from workDays
         System.out.println("\nAfter removing Monday from workDays: " + workDays);
 
         // Example 3: Checking if an element exists in the EnumSet
         boolean isSaturdayWorkday = workDays.contains(Day.SATURDAY); // Check if Saturday is a workday
         System.out.println("\nIs Saturday a workday? " + isSaturdayWorkday); // Should be false
 
         // Example 4: Creating an EnumSet with all elements of the Day enum
         EnumSet<Day> allDays = EnumSet.allOf(Day.class);
         System.out.println("\nAll Days of the Week: " + allDays);
 
         // Example 5: Clearing the EnumSet
         workDays.clear();
         System.out.println("\nWorkDays after clearing: " + workDays); // Should be empty
     }
 }

LinkedHashSet Operations

File: _25_LinkedHashSet.java

import java.util.*;

class Employee {
   private String name;
   private double salary;

   // Constructor
   public Employee(String name, double salary) {
       this.name = name;
       this.salary = salary;
   }

   // Getter for name
   public String getName() {
       return name;
   }

   // Getter for salary
   public double getSalary() {
       return salary;
   }

   // Override toString() for displaying employee details
   @Override
   public String toString() {
       return "Employee{name='" + name + "', salary=" + salary + "}";
   }

   // Override equals() and hashCode() for comparing Employee objects
   @Override
   public boolean equals(Object obj) {
       if (this == obj) return true;
       if (obj == null || getClass() != obj.getClass()) return false;
       Employee employee = (Employee) obj;
       return Double.compare(employee.salary, salary) == 0 &&
               name.equals(employee.name);
   }

   @Override
   public int hashCode() {
       return Objects.hash(name, salary);
   }
}

public class _25_LinkedHashSet {

   public static void main(String[] args) {
       
       // Create a LinkedHashSet to store Employee objects
       LinkedHashSet<Employee> employees = new LinkedHashSet<>();

       // Add Employee objects to the LinkedHashSet
       employees.add(new Employee("John", 50000));
       employees.add(new Employee("Alice", 60000));
       employees.add(new Employee("Bob", 45000));
       employees.add(new Employee("Diana", 55000));

       // Display the LinkedHashSet (in insertion order)
       System.out.println("Employee List (after add):");
       for (Employee emp : employees) {
           System.out.println(emp);
       }

       // Example 1: Adding a duplicate employee
       System.out.println("\nAttempting to add a duplicate employee:");
       boolean isAdded = employees.add(new Employee("John", 50000));
       System.out.println("Was the duplicate added? " + isAdded); // Should be false as 'John' already exists

       // Example 2: Checking if an employee exists
       System.out.println("\nChecking if 'Alice' is in the LinkedHashSet:");
       boolean exists = employees.contains(new Employee("Alice", 60000));
       System.out.println("Does Alice exist? " + exists); // Should be true

       // Example 3: Removing an employee from the LinkedHashSet
       System.out.println("\nRemoving employee 'Bob':");
       boolean isRemoved = employees.remove(new Employee("Bob", 45000));
       System.out.println("Was Bob removed? " + isRemoved); // Should be true

       // Display the LinkedHashSet after removal
       System.out.println("\nEmployee List (after remove):");
       for (Employee emp : employees) {
           System.out.println(emp);
       }

       // Example 4: Displaying the size of the LinkedHashSet
       System.out.println("\nSize of the LinkedHashSet: " + employees.size()); // Should return the number of employees

       // Example 5: Clearing the LinkedHashSet
       System.out.println("\nClearing the LinkedHashSet...");
       employees.clear();
       System.out.println("Is the LinkedHashSet empty? " + employees.isEmpty()); // Should return true
   }
}

PriorityQueue Operations

File: _26_PriorityQueue.java


 import java.util.*;

 class Employee {
     private String name;
     private double salary;
 
     // Constructor
     public Employee(String name, double salary) {
         this.name = name;
         this.salary = salary;
     }
 
     // Getter for name
     public String getName() {
         return name;
     }
 
     // Getter for salary
     public double getSalary() {
         return salary;
     }
 
     // Override toString() for displaying employee details
     @Override
     public String toString() {
         return "Employee{name='" + name + "', salary=" + salary + "}";
     }
 }
 
 public class _26_PriorityQueue {
 
     public static void main(String[] args) {
 
         // PriorityQueue of integers using natural ordering (min-heap)
         PriorityQueue<Integer> pq = new PriorityQueue<>();
         pq.offer(10);
         pq.offer(30);
         pq.offer(20);
         pq.offer(50);
         pq.offer(40);
 
         // Display elements in the PriorityQueue
         System.out.println("PriorityQueue (min-heap) of integers:");
         while (!pq.isEmpty()) {
             System.out.println(pq.poll()); // Remove and print the top (min) element
         }
 
         // PriorityQueue of Employee objects using a custom comparator (sort by salary)
         PriorityQueue<Employee> employeeQueue = new PriorityQueue<>(new Comparator<Employee>() {
             @Override
             public int compare(Employee e1, Employee e2) {
                 return Double.compare(e1.getSalary(), e2.getSalary()); // Sort by salary
             }
         });
 
         employeeQueue.offer(new Employee("John", 50000));
         employeeQueue.offer(new Employee("Alice", 70000));
         employeeQueue.offer(new Employee("Bob", 45000));
         employeeQueue.offer(new Employee("Diana", 60000));
 
         // Display elements in the PriorityQueue (sorted by salary)
         System.out.println("\nPriorityQueue of employees (sorted by salary):");
         while (!employeeQueue.isEmpty()) {
             System.out.println(employeeQueue.poll()); // Remove and print the top element (lowest salary)
         }
 
         // PriorityQueue with natural ordering for Strings
         PriorityQueue<String> stringQueue = new PriorityQueue<>();
         stringQueue.offer("Apple");
         stringQueue.offer("Banana");
         stringQueue.offer("Cherry");
         stringQueue.offer("Date");
 
         // Display elements in the PriorityQueue (sorted alphabetically)
         System.out.println("\nPriorityQueue of strings (sorted alphabetically):");
         while (!stringQueue.isEmpty()) {
             System.out.println(stringQueue.poll()); // Remove and print the top element
         }
 
         // Peek the top element without removal
         System.out.println("\nPeeking the top element in the integer PriorityQueue:");
         pq.offer(10);
         pq.offer(30);
         pq.offer(20);
         pq.offer(50);
         pq.offer(40);
         System.out.println("Top element (without removal): " + pq.peek()); // Should return 10
     }
 }

HashMap Operations

File: _27_HashMap.java


 import java.util.*;

 public class _27_HashMap {
 
     public static void main(String[] args) {
         
         // Create a HashMap to store employee ID and employee name
         HashMap<Integer, String> employees = new HashMap<>();
 
         // Add some employee ID and name pairs to the HashMap
         employees.put(101, "John");
         employees.put(102, "Alice");
         employees.put(103, "Bob");
         employees.put(104, "Diana");
         
         // Display the HashMap
         System.out.println("Initial HashMap:");
         System.out.println(employees);
 
         // Example 1: Retrieve a value using its key
         String employeeName = employees.get(102); // Get the employee with ID 102
         System.out.println("\nEmployee with ID 102: " + employeeName);
 
         // Example 2: Check if a key exists in the HashMap
         boolean hasEmployee = employees.containsKey(105); // Check if ID 105 exists
         System.out.println("\nDoes employee with ID 105 exist? " + hasEmployee);
 
         // Example 3: Remove a key-value pair
         System.out.println("\nRemoving employee with ID 103...");
         employees.remove(103); // Remove the employee with ID 103
         System.out.println("Updated HashMap: " + employees);
 
         // Example 4: Get the size of the HashMap
         System.out.println("\nSize of the HashMap: " + employees.size());
 
         // Example 5: Iterating over the HashMap using keySet()
         System.out.println("\nIterating over the HashMap (using keySet()):");
         for (Integer id : employees.keySet()) {
             System.out.println("Employee ID: " + id + ", Name: " + employees.get(id));
         }
 
         // Example 6: Iterating over the HashMap using values()
         System.out.println("\nIterating over the HashMap (using values()):");
         for (String name : employees.values()) {
             System.out.println("Employee Name: " + name);
         }
 
         // Example 7: Iterating over the HashMap using entrySet()
         System.out.println("\nIterating over the HashMap (using entrySet()):");
         for (Map.Entry<Integer, String> entry : employees.entrySet()) {
             System.out.println("Employee ID: " + entry.getKey() + ", Name: " + entry.getValue());
         }
     }
 }

TreeMap Operations

File: _28_TreeMap.java


 import java.util.*;

 class Employee {
     private String name;
     private double salary;
 
     // Constructor
     public Employee(String name, double salary) {
         this.name = name;
         this.salary = salary;
     }
 
     // Getter for name
     public String getName() {
         return name;
     }
 
     // Getter for salary
     public double getSalary() {
         return salary;
     }
 
     // Override toString() for displaying employee details
     @Override
     public String toString() {
         return "Employee{name='" + name + "', salary=" + salary + "}";
     }
 }
 
 public class _28_TreeMap {
 
     public static void main(String[] args) {
         
         // Create a TreeMap to store employee ID and employee name (sorted by employee ID)
         TreeMap<Integer, String> employees = new TreeMap<>();
 
         // Add some employee ID and name pairs to the TreeMap
         employees.put(101, "John");
         employees.put(102, "Alice");
         employees.put(103, "Bob");
         employees.put(104, "Diana");
         
         // Display the TreeMap (sorted by key - employee ID)
         System.out.println("Initial TreeMap (sorted by employee ID):");
         System.out.println(employees);
 
         // Example 1: Retrieve a value using its key
         String employeeName = employees.get(102); // Get the employee with ID 102
         System.out.println("\nEmployee with ID 102: " + employeeName);
 
         // Example 2: Check if a key exists in the TreeMap
         boolean hasEmployee = employees.containsKey(105); // Check if ID 105 exists
         System.out.println("\nDoes employee with ID 105 exist? " + hasEmployee);
 
         // Example 3: Remove a key-value pair
         System.out.println("\nRemoving employee with ID 103...");
         employees.remove(103); // Remove the employee with ID 103
         System.out.println("Updated TreeMap: " + employees);
 
         // Example 4: Get the size of the TreeMap
         System.out.println("\nSize of the TreeMap: " + employees.size());
 
         // Example 5: Iterating over the TreeMap using keySet()
         System.out.println("\nIterating over the TreeMap (using keySet()):");
         for (Integer id : employees.keySet()) {
             System.out.println("Employee ID: " + id + ", Name: " + employees.get(id));
         }
 
         // Example 6: Iterating over the TreeMap using values()
         System.out.println("\nIterating over the TreeMap (using values()):");
         for (String name : employees.values()) {
             System.out.println("Employee Name: " + name);
         }
 
         // Example 7: Iterating over the TreeMap using entrySet()
         System.out.println("\nIterating over the TreeMap (using entrySet()):");
         for (Map.Entry<Integer, String> entry : employees.entrySet()) {
             System.out.println("Employee ID: " + entry.getKey() + ", Name: " + entry.getValue());
         }
 
         // Example 8: Custom Sorting with a Comparator
         TreeMap<Integer, Employee> employeeMap = new TreeMap<>(new Comparator<Integer>() {
             @Override
             public int compare(Integer id1, Integer id2) {
                 // Custom sorting logic: reversing the order of employee IDs
                 return id2.compareTo(id1); // Descending order of IDs
             }
         });
 
         // Adding employees with IDs
         employeeMap.put(101, new Employee("John", 50000));
         employeeMap.put(102, new Employee("Alice", 60000));
         employeeMap.put(103, new Employee("Bob", 45000));
 
         // Display the TreeMap (sorted by employee ID in descending order)
         System.out.println("\nTreeMap (sorted by employee ID in descending order):");
         for (Map.Entry<Integer, Employee> entry : employeeMap.entrySet()) {
             System.out.println("Employee ID: " + entry.getKey() + ", Name: " + entry.getValue().getName());
         }
     }
 }

EnumMap Operations

File: _29_EnumMap.java

import java.util.EnumMap;

// Enum for Days of the Week
enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

public class _29_EnumMap {

    public static void main(String[] args) {
        
        // Create an EnumMap to store working hours for each day of the week
        EnumMap<Day, String> workingHours = new EnumMap<>(Day.class);

        // Add key-value pairs (Day -> Working hours)
        workingHours.put(Day.MONDAY, "9 AM - 5 PM");
        workingHours.put(Day.TUESDAY, "9 AM - 5 PM");
        workingHours.put(Day.WEDNESDAY, "9 AM - 5 PM");
        workingHours.put(Day.THURSDAY, "9 AM - 5 PM");
        workingHours.put(Day.FRIDAY, "9 AM - 5 PM");
        workingHours.put(Day.SATURDAY, "10 AM - 2 PM");
        workingHours.put(Day.SUNDAY, "Closed");

        // Display the EnumMap
        System.out.println("Working hours for each day of the week:");
        System.out.println(workingHours);

        // Example 1: Retrieve working hours for a specific day
        String mondayHours = workingHours.get(Day.MONDAY); // Get working hours for Monday
        System.out.println("\nWorking hours for MONDAY: " + mondayHours);

        // Example 2: Remove working hours for Sunday
        workingHours.remove(Day.SUNDAY); // Remove the entry for Sunday
        System.out.println("\nUpdated working hours (after removing Sunday):");
        System.out.println(workingHours);

        // Example 3: Check if a specific day has working hours
        boolean isSundayWorking = workingHours.containsKey(Day.SUNDAY);
        System.out.println("\nIs Sunday in the EnumMap? " + isSundayWorking);

        // Example 4: Iterate over the EnumMap using entrySet()
        System.out.println("\nIterating over the EnumMap (using entrySet()):");
        for (var entry : workingHours.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }

        // Example 5: Get the size of the EnumMap
        System.out.println("\nSize of the EnumMap: " + workingHours.size());
    }
}

LinkedHashMap Operations

File: _30_LinkedHashMap.java

import java.util.*;

public class _30_LinkedHashMap {

    public static void main(String[] args) {
        
        // Create a LinkedHashMap to store employee name and their ID
        LinkedHashMap<Integer, String> employeeMap = new LinkedHashMap<>();
        
        // Add employee IDs and their names
        employeeMap.put(101, "Alice");
        employeeMap.put(102, "Bob");
        employeeMap.put(103, "Charlie");
        employeeMap.put(104, "David");

        // Display the LinkedHashMap
        System.out.println("Employee details (Insertion Order):");
        System.out.println(employeeMap);
        
        // Example 1: Retrieve the employee name for a specific ID
        String employeeName = employeeMap.get(102); // Get the employee with ID 102
        System.out.println("\nEmployee with ID 102: " + employeeName);
        
        // Example 2: Remove an entry from the map
        employeeMap.remove(103); // Remove the employee with ID 103
        System.out.println("\nEmployee details after removing ID 103:");
        System.out.println(employeeMap);
        
        // Example 3: Iterate over the LinkedHashMap and print each employee's details
        System.out.println("\nIterating over the LinkedHashMap:");
        for (Map.Entry<Integer, String> entry : employeeMap.entrySet()) {
            System.out.println("ID: " + entry.getKey() + ", Name: " + entry.getValue());
        }
        
        // Example 4: Demonstrate insertion order (LinkedHashMap maintains insertion order)
        System.out.println("\nEmployee details (Insertion Order Maintained):");
        System.out.println(employeeMap);
        
        // Example 5: Create LinkedHashMap with access order
        LinkedHashMap<Integer, String> accessOrderMap = new LinkedHashMap<>(16, 0.75f, true);
        accessOrderMap.put(201, "Eve");
        accessOrderMap.put(202, "Frank");
        accessOrderMap.put(203, "Grace");

        // Access some elements to change access order
        accessOrderMap.get(202); // Access Frank
        accessOrderMap.get(203); // Access Grace
        
        // Print the order after accessing
        System.out.println("\nEmployee details (Access Order Changed):");
        System.out.println(accessOrderMap);
    }
}

WeakHashMap Operations

File: _31_WeakHashMap.java

import java.util.*;

public class _31_WeakHashMap {

    public static void main(String[] args) throws InterruptedException {

        // Create a WeakHashMap to store weak references to objects
        WeakHashMap<SomeObject, String> weakMap = new WeakHashMap<>();
        
        // Create some objects (keys) to store in the map
        SomeObject key1 = new SomeObject("Object 1");
        SomeObject key2 = new SomeObject("Object 2");
        SomeObject key3 = new SomeObject("Object 3");

        // Add key-value pairs to the WeakHashMap
        weakMap.put(key1, "Data for Object 1");
        weakMap.put(key2, "Data for Object 2");
        weakMap.put(key3, "Data for Object 3");

        // Display the map before the keys are garbage collected
        System.out.println("WeakHashMap before GC:");
        System.out.println(weakMap);

        // Nullify the strong reference to key1 and key2
        key1 = null;
        key2 = null;

        // Suggest garbage collection (this is just a suggestion; actual GC happens at JVM's discretion)
        System.gc();
        
        // Wait for a brief moment to allow garbage collection to take place
        Thread.sleep(1000);

        // Display the map after garbage collection
        System.out.println("\nWeakHashMap after GC:");
        System.out.println(weakMap);
    }
}

// A simple class to use as a key in the WeakHashMap
class SomeObject {
    private String name;

    public SomeObject(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }

    // Override hashCode and equals to ensure correct behavior in collections
    @Override
    public int hashCode() {
        return name.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        SomeObject that = (SomeObject) obj;
        return name.equals(that.name);
    }
}

IdentityHashMap Operations

File: _32_IdentityHashMap.java

import java.util.*;

public class _32_IdentityHashMap {

    public static void main(String[] args) {
        
        // Create an IdentityHashMap to store keys based on reference equality
        IdentityHashMap<String, String> identityMap = new IdentityHashMap<>();
        
        // Create some objects (keys)
        String key1 = new String("Java");
        String key2 = new String("Java"); // Different object with same value
        String key3 = key1;  // Same object as key1
        
        // Add key-value pairs to the IdentityHashMap
        identityMap.put(key1, "Programming Language");
        identityMap.put(key2, "Programming Language");
        identityMap.put(key3, "Programming Language");
        
        // Display the IdentityHashMap
        System.out.println("IdentityHashMap entries:");
        System.out.println(identityMap);
        
        // Check if key1 and key2 are considered the same key by IdentityHashMap
        System.out.println("\nAre key1 and key2 considered the same key?");
        System.out.println(identityMap.get(key1) == identityMap.get(key2));  // false (because they are different objects)
        
        // Check if key1 and key3 are considered the same key by IdentityHashMap
        System.out.println("\nAre key1 and key3 considered the same key?");
        System.out.println(identityMap.get(key1) == identityMap.get(key3));  // true (because they refer to the same object)
        
        // Demonstrate IdentityHashMap behavior with keys having the same logical value but being different objects
        System.out.println("\nSize of the IdentityHashMap:");
        System.out.println(identityMap.size()); // 2, because key1 and key3 are the same object
        
        // Iterate over the map and print the entries
        System.out.println("\nIterating over the IdentityHashMap:");
        for (Map.Entry<String, String> entry : identityMap.entrySet()) {
            System.out.println(entry.getKey() + " => " + entry.getValue());
        }
    }
}

Thread Basic Concepts

File: _33_ThreadsBasic.java


 class MyThread extends Thread {
    @Override
    public void run() {
        // Task to be executed by the thread
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " is running - Count: " + i);
            try {
                Thread.sleep(1000); // Pauses the thread for 1 second
            } catch (InterruptedException e) {
                System.out.println(e);
            }
        }
    }
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // Task to be executed by the thread
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " is running - Count: " + i);
            try {
                Thread.sleep(1000); // Pauses the thread for 1 second
            } catch (InterruptedException e) {
                System.out.println(e);
            }
        }
    }
}

public class _33_ThreadsBasic{
    public static void main(String[] args) throws InterruptedException {

        // Creating and starting a thread by extending Thread class
        MyThread thread1 = new MyThread();
        thread1.setName("Thread-1");
        thread1.start(); // Start the thread

        // Creating and starting a thread by implementing Runnable interface
        MyRunnable runnable = new MyRunnable();
        Thread thread2 = new Thread(runnable);
        thread2.setName("Thread-2");
        thread2.start(); // Start the thread

        // Wait for both threads to finish
        thread1.join();
        thread2.join();

        System.out.println("Main thread finished.");
    }
}

Using Synchronization methods in threads

File: _34_ThreadSynchronization.java


class Counter {
    private int count = 0;

    // Synchronized method to ensure thread-safe operations
    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

public class _34_ThreadSynchronization {
    public static void main(String[] args) throws InterruptedException {

        Counter counter = new Counter();

        // Create two threads that will modify the counter
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        // Start the threads
        thread1.start();
        thread2.start();

        // Wait for both threads to finish
        thread1.join();
        thread2.join();

        // Print the final count value
        System.out.println("Final count: " + counter.getCount());
    }
}

Fixed Thread Pool

File: _35_FixedThreadPool.java

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


class Task implements Runnable {
    private final int taskId;

    public Task(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public void run() {
        System.out.println("Task " + taskId + " is being executed by " + Thread.currentThread().getName());
    }
}

public class _35_FixedThreadPool {
    public static void main(String[] args) {
        // Create a FixedThreadPool with 3 threads
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // Submit 5 tasks to the executor
        for (int i = 1; i <= 5; i++) {
            executorService.submit(new Task(i));
        }

        // Initiates an orderly shutdown of the executor
        executorService.shutdown();
    }
}

Cached Thread Pool

File: _36_CachedThreadPool.java

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Task implements Runnable {
    private final int taskId;

    public Task(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public void run() {
        System.out.println("Task " + taskId + " is being executed by " + Thread.currentThread().getName());
    }
}

public class _36_CachedThreadPool {
    public static void main(String[] args) {
        // Create a CachedThreadPool that creates new threads as needed
        ExecutorService executorService = Executors.newCachedThreadPool();

        // Submit 5 tasks
        for (int i = 1; i <= 5; i++) {
            executorService.submit(new Task(i));
        }

        // Gracefully shuts down the executor after completion of tasks
        executorService.shutdown();
    }
}

Single Thread Executor

File: _37_SingleThreadExecutor.java

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Task implements Runnable {
    private final int taskId;

    public Task(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public void run() {
        System.out.println("Task " + taskId + " is being executed by " + Thread.currentThread().getName());
    }
}

public class _37_SingleThreadExecutor {
    public static void main(String[] args) {
        // Create a SingleThreadExecutor to execute tasks sequentially
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        // Submit 5 tasks to the executor
        for (int i = 1; i <= 5; i++) {
            executorService.submit(new Task(i));
        }

        // Gracefully shut down the executor
        executorService.shutdown();
    }
}

Scheduled Thread Pool Executor

File: _38_ScheduledThreadPool.java

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

class Task implements Runnable {
    private final int taskId;

    public Task(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public void run() {
        System.out.println("Task " + taskId + " is being executed by " + Thread.currentThread().getName());
    }
}

public class _38_ScheduledThreadPool {
    public static void main(String[] args) {
        // Create a ScheduledThreadPool with 2 threads
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

        // Schedule tasks with a fixed delay
        scheduler.scheduleWithFixedDelay(new Task(1), 0, 2, TimeUnit.SECONDS);
        scheduler.scheduleWithFixedDelay(new Task(2), 0, 3, TimeUnit.SECONDS);
        scheduler.scheduleWithFixedDelay(new Task(3), 0, 1, TimeUnit.SECONDS);

        // Let the tasks run for some time before shutting down
        try {
            Thread.sleep(10000); // Let the tasks run for 10 seconds
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // Shut down the scheduler after tasks are completed
        scheduler.shutdown();
    }
}