{"id":21607480,"url":"https://github.com/isurusankhajith/java-fundamentals","last_synced_at":"2026-05-20T09:07:16.682Z","repository":{"id":255804119,"uuid":"853387075","full_name":"IsuruSankhajith/Java-fundamentals","owner":"IsuruSankhajith","description":" This repository is designed to help beginners understand the core concepts of Java programming, starting from basic syntax to more advanced topics like Object-Oriented Programming (OOP), Exception Handling, and Multithreading.","archived":false,"fork":false,"pushed_at":"2024-09-07T06:07:58.000Z","size":15,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-18T15:21:44.020Z","etag":null,"topics":["java","java-fundamentals"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IsuruSankhajith.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-06T14:54:38.000Z","updated_at":"2024-09-07T06:08:01.000Z","dependencies_parsed_at":null,"dependency_job_id":"23e87c72-e0f3-453f-ae75-4353e676431e","html_url":"https://github.com/IsuruSankhajith/Java-fundamentals","commit_stats":null,"previous_names":["isurusankhajith/java-fundamentals"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/IsuruSankhajith/Java-fundamentals","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IsuruSankhajith%2FJava-fundamentals","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IsuruSankhajith%2FJava-fundamentals/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IsuruSankhajith%2FJava-fundamentals/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IsuruSankhajith%2FJava-fundamentals/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IsuruSankhajith","download_url":"https://codeload.github.com/IsuruSankhajith/Java-fundamentals/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IsuruSankhajith%2FJava-fundamentals/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33253108,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-20T04:48:54.280Z","status":"ssl_error","status_checked_at":"2026-05-20T04:48:10.851Z","response_time":356,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","java-fundamentals"],"created_at":"2024-11-24T20:31:15.031Z","updated_at":"2026-05-20T09:07:16.666Z","avatar_url":"https://github.com/IsuruSankhajith.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Java Fundamentals\n\nWelcome to the **Java Fundamentals** repository! This repository is designed to help beginners understand the core concepts of Java programming, starting from basic syntax to more advanced topics like Object-Oriented Programming (OOP), Exception Handling, and Multithreading.\n\n## Table of Contents\n\n1. [Introduction to Java](#introduction-to-java)\n2. [Basic Concepts](#basic-concepts)\n3. [Object-Oriented Programming (OOP)](#object-oriented-programming-oop)\n4. [Exception Handling](#exception-handling)\n5. [Collections Framework](#collections-framework)\n6. [Input/Output (I/O)](#inputoutput-io)\n7. [Multithreading](#multithreading)\n8. [Memory Management](#memory-management)\n9. [Advanced Java Topics](#advanced-java-topics)\n10. [Best Practices](#best-practices)\n\n### Introduction to Java\n\n#### **Brief History of Java**\n- **Origin:** Java was developed by Sun Microsystems in 1995. It was initiated as a project called \"Oak\" by James Gosling and his team, aiming to create a platform-independent language for embedded systems. \n- **Evolution:** After rebranding as Java, it quickly became popular due to its \"write once, run anywhere\" philosophy, which allows Java programs to run on any device with a compatible JVM.\n- **Acquisition by Oracle:** In 2010, Oracle Corporation acquired Sun Microsystems and continues to develop Java, ensuring its relevance in modern software development.\n\n#### **Features of Java**\n- **Platform Independence:** Java code is compiled into bytecode, which can run on any device with a JVM, making it platform-independent.\n- **Object-Oriented:** Java follows the principles of object-oriented programming (OOP), which include inheritance, polymorphism, encapsulation, and abstraction.\n- **Simple:** Java's syntax is similar to C++, but with more straightforward features and fewer complexities like pointers and operator overloading.\n- **Secure:** Java provides robust security features like bytecode verification, a secure runtime environment, and automatic memory management (garbage collection).\n- **Multi-threaded:** Java supports multi-threading, allowing multiple threads to run concurrently, making it efficient for multitasking.\n- **Robust:** Java emphasizes error checking during compile-time and runtime, reducing the chances of crashes and making it reliable.\n- **High Performance:** Java's Just-In-Time (JIT) compiler enables high performance by converting bytecode into native machine code at runtime.\n- **Dynamic:** Java is designed to adapt to an evolving environment, with runtime capabilities to load new classes and support dynamic linking.\n\n#### **Java Development Kit (JDK), Java Runtime Environment (JRE), and Java Virtual Machine (JVM)**\n- **JDK (Java Development Kit):**\n  - The JDK is a software development kit used to develop Java applications. It includes the JRE, an interpreter/loader (Java), a compiler (javac), an archiver (jar), a documentation generator (Javadoc), and other tools needed for Java development.\n  - The JDK is necessary for compiling Java source code into bytecode and for running Java programs.\n\n- **JRE (Java Runtime Environment):**\n  - The JRE is a subset of the JDK and provides the libraries, Java Virtual Machine (JVM), and other components to run applications written in Java.\n  - It does not include development tools like a compiler or debugger. The JRE is used primarily to run Java applications on your machine.\n\n- **JVM (Java Virtual Machine):**\n  - The JVM is the heart of the Java programming language. It is responsible for converting the bytecode into machine-specific code and executing it.\n  - The JVM provides platform independence, as the same bytecode can run on any operating system with a compatible JVM.\n  - JVM also manages system memory and provides garbage collection, ensuring efficient memory usage.\n\nThis section provides a foundational understanding of Java, covering its origins, key features, and the tools involved in Java development and execution.\n\n### Basic Syntax\n\n#### **Structure of a Java Program**\nA typical Java program consists of the following components:\n- **Package declaration** (optional)\n- **Import statements** (optional)\n- **Class declaration**\n- **Main method** (`public static void main(String[] args)`)\n- **Statements inside the main method**\n\nExample:\n```java\npublic class HelloWorld {\n    public static void main(String[] args) {\n        System.out.println(\"Hello, World!\");  // Prints message to console\n    }\n}\n```\n\n#### **Comments**\nJava supports three types of comments:\n1. **Single-line comment**: Begins with `//` and lasts for one line.\n   ```java\n   // This is a single-line comment\n   ```\n2. **Multi-line comment**: Starts with `/*` and ends with `*/`.\n   ```java\n   /* This is a multi-line comment.\n      It spans multiple lines. */\n   ```\n3. **Documentation comment**: Used for generating documentation and starts with `/**` and ends with `*/`.\n   ```java\n   /**\n    * This is a documentation comment.\n    * It is used to describe methods and classes.\n    */\n   ```\n\n#### **Data Types**\nJava data types are divided into two categories:\n\n1. **Primitive Data Types**: These are predefined by Java.\n   - **byte** (1 byte)\n   - **short** (2 bytes)\n   - **int** (4 bytes)\n   - **long** (8 bytes)\n   - **float** (4 bytes)\n   - **double** (8 bytes)\n   - **char** (2 bytes, Unicode character)\n   - **boolean** (`true` or `false`)\n\n2. **Non-Primitive Data Types**: These are created by the programmer (objects, arrays, etc.).\n   - Examples: String, Arrays, Classes, Interfaces\n\n#### **Variables and Constants**\n- **Variables**: Used to store data values. They must be declared before use.\n   ```java\n   int age = 25;\n   String name = \"Alice\";\n   ```\n- **Constants**: Variables whose value cannot be changed once assigned. Declared using the `final` keyword.\n   ```java\n   final double PI = 3.14159;\n   ```\n\n#### **Operators**\n1. **Arithmetic Operators**: Used to perform basic arithmetic operations.\n   - `+` (Addition), `-` (Subtraction), `*` (Multiplication), `/` (Division), `%` (Modulus)\n\n2. **Relational Operators**: Compare values and return a boolean result.\n   - `==` (Equal to), `!=` (Not equal to), `\u003e` (Greater than), `\u003c` (Less than), `\u003e=` (Greater than or equal to), `\u003c=` (Less than or equal to)\n\n3. **Logical Operators**: Perform logical operations and return boolean values.\n   - `\u0026\u0026` (Logical AND), `||` (Logical OR), `!` (Logical NOT)\n\n4. **Bitwise Operators**: Perform bit-level operations.\n   - `\u0026` (Bitwise AND), `|` (Bitwise OR), `^` (Bitwise XOR), `~` (Bitwise NOT), `\u003c\u003c` (Left shift), `\u003e\u003e` (Right shift)\n\n5. **Assignment Operators**: Used to assign values to variables.\n   - `=` (Simple assignment), `+=`, `-=`, `*=`, `/=`, `%=` (Compound assignment)\n\nCertainly! Below is a comprehensive set of notes for **Section 3: Control Flow Statements** in Java Fundamentals. This section covers Conditional Statements, Looping Statements, and Branching Statements, complete with explanations and code examples to help you understand and apply these concepts effectively.\n\n---\n\n## Control Flow Statements\n\nControl Flow Statements in Java determine the order in which statements are executed in a program. They allow you to control the flow of your program's execution based on certain conditions or repeatedly execute a block of code.\n\n### 3.1 **Conditional Statements**\n\nConditional statements execute different blocks of code based on whether a specified condition is true or false. They are fundamental for making decisions within your program.\n\n#### 3.1.1 `if` Statement\n\n- **Syntax:**\n  ```java\n  if (condition) {\n      // code to be executed if condition is true\n  }\n  ```\n- **Description:** Executes the block of code only if the specified condition is `true`.\n\n- **Example:**\n  ```java\n  int number = 10;\n  if (number \u003e 5) {\n      System.out.println(\"Number is greater than 5.\");\n  }\n  ```\n  \n#### 3.1.2 `if-else` Statement\n\n- **Syntax:**\n  ```java\n  if (condition) {\n      // code to be executed if condition is true\n  } else {\n      // code to be executed if condition is false\n  }\n  ```\n- **Description:** Provides an alternative block of code to execute when the condition is `false`.\n\n- **Example:**\n  ```java\n  int number = 3;\n  if (number \u003e 5) {\n      System.out.println(\"Number is greater than 5.\");\n  } else {\n      System.out.println(\"Number is 5 or less.\");\n  }\n  ```\n\n#### 3.1.3 `else-if` Ladder\n\n- **Syntax:**\n  ```java\n  if (condition1) {\n      // code\n  } else if (condition2) {\n      // code\n  } else if (condition3) {\n      // code\n  } else {\n      // default code\n  }\n  ```\n- **Description:** Allows multiple conditions to be checked in sequence. Executes the block of the first `true` condition.\n\n- **Example:**\n  ```java\n  int score = 85;\n  if (score \u003e= 90) {\n      System.out.println(\"Grade: A\");\n  } else if (score \u003e= 80) {\n      System.out.println(\"Grade: B\");\n  } else if (score \u003e= 70) {\n      System.out.println(\"Grade: C\");\n  } else {\n      System.out.println(\"Grade: F\");\n  }\n  ```\n\n#### 3.1.4 `switch` Statement\n\n- **Syntax:**\n  ```java\n  switch (expression) {\n      case value1:\n          // code\n          break;\n      case value2:\n          // code\n          break;\n      // more cases\n      default:\n          // default code\n  }\n  ```\n- **Description:** Selects one of many code blocks to execute based on the value of an expression. Efficient for handling multiple discrete values.\n\n- **Example:**\n  ```java\n  int day = 3;\n  switch (day) {\n      case 1:\n          System.out.println(\"Monday\");\n          break;\n      case 2:\n          System.out.println(\"Tuesday\");\n          break;\n      case 3:\n          System.out.println(\"Wednesday\");\n          break;\n      default:\n          System.out.println(\"Invalid day\");\n  }\n  ```\n\n### 3.2 **Looping Statements**\n\nLooping statements are used to execute a block of code repeatedly as long as a specified condition is met. They are essential for tasks that require repetition.\n\n#### 3.2.1 `for` Loop\n\n- **Syntax:**\n  ```java\n  for (initialization; condition; update) {\n      // code to be executed\n  }\n  ```\n- **Description:** Ideal for situations where the number of iterations is known beforehand.\n\n- **Example:**\n  ```java\n  for (int i = 1; i \u003c= 5; i++) {\n      System.out.println(\"Iteration: \" + i);\n  }\n  ```\n\n#### 3.2.2 `while` Loop\n\n- **Syntax:**\n  ```java\n  while (condition) {\n      // code to be executed\n  }\n  ```\n- **Description:** Continues to execute the block of code as long as the condition remains `true`. Best used when the number of iterations is not known.\n\n- **Example:**\n  ```java\n  int i = 1;\n  while (i \u003c= 5) {\n      System.out.println(\"Iteration: \" + i);\n      i++;\n  }\n  ```\n\n#### 3.2.3 `do-while` Loop\n\n- **Syntax:**\n  ```java\n  do {\n      // code to be executed\n  } while (condition);\n  ```\n- **Description:** Similar to the `while` loop, but guarantees that the block of code is executed at least once before the condition is tested.\n\n- **Example:**\n  ```java\n  int i = 1;\n  do {\n      System.out.println(\"Iteration: \" + i);\n      i++;\n  } while (i \u003c= 5);\n  ```\n\n### 3.3 **Branching Statements**\n\nBranching statements alter the flow of control by transferring execution to different parts of the program. They are used to exit loops or methods prematurely.\n\n#### 3.3.1 `break` Statement\n\n- **Description:** Terminates the nearest enclosing loop (`for`, `while`, or `do-while`) or `switch` statement and transfers control to the statement immediately following the loop or `switch`.\n\n- **Example in a Loop:**\n  ```java\n  for (int i = 1; i \u003c= 10; i++) {\n      if (i == 5) {\n          break; // Exit the loop when i is 5\n      }\n      System.out.println(\"i = \" + i);\n  }\n  // Output: i = 1, i = 2, i = 3, i = 4\n  ```\n\n- **Example in a `switch`:**\n  ```java\n  char grade = 'B';\n  switch (grade) {\n      case 'A':\n          System.out.println(\"Excellent!\");\n          break;\n      case 'B':\n          System.out.println(\"Good!\");\n          break;\n      default:\n          System.out.println(\"Invalid grade\");\n  }\n  // Output: Good!\n  ```\n\n#### 3.3.2 `continue` Statement\n\n- **Description:** Skips the current iteration of the nearest enclosing loop and proceeds with the next iteration.\n\n- **Example:**\n  ```java\n  for (int i = 1; i \u003c= 5; i++) {\n      if (i == 3) {\n          continue; // Skip the rest of the loop when i is 3\n      }\n      System.out.println(\"i = \" + i);\n  }\n  // Output: i = 1, i = 2, i = 4, i = 5\n  ```\n\n#### 3.3.3 `return` Statement\n\n- **Description:** Exits from the current method and optionally returns a value to the caller. It can be used to terminate the execution of a method at any point.\n\n- **Example in a Method:**\n  ```java\n  public static int findFirstPositive(int[] numbers) {\n      for (int num : numbers) {\n          if (num \u003e 0) {\n              return num; // Exit the method and return the first positive number\n          }\n      }\n      return -1; // Return -1 if no positive number is found\n  }\n\n  // Usage\n  int[] nums = {-3, -2, 0, 4, 5};\n  int firstPositive = findFirstPositive(nums);\n  System.out.println(\"First positive number: \" + firstPositive);\n  // Output: First positive number: 4\n  ```\n\n---\n\n## **Key Points to Remember**\n\n1. **Conditional Statements:**\n   - Use `if` when a single condition needs to be checked.\n   - Use `if-else` when you have two possible paths.\n   - Use `else-if` for multiple conditions.\n   - Use `switch` for selecting among multiple discrete values, especially when dealing with enumerated types or constants.\n\n2. **Looping Statements:**\n   - Use `for` loops when the number of iterations is known.\n   - Use `while` loops when the number of iterations is not known and depends on a condition.\n   - Use `do-while` loops when the code block needs to execute at least once regardless of the condition.\n\n3. **Branching Statements:**\n   - Use `break` to exit loops or `switch` statements prematurely.\n   - Use `continue` to skip the current iteration and proceed with the next one.\n   - Use `return` to exit from methods, optionally returning a value.\n\n4. **Best Practices:**\n   - Ensure loop conditions eventually become `false` to avoid infinite loops.\n   - Use `switch` statements for better readability when dealing with multiple discrete values.\n   - Avoid excessive use of `break` and `continue` as they can make the code harder to follow.\n   - Use meaningful conditions and ensure they are clear and maintainable.\n\n---\n\n## **Additional Examples**\n\n### Example 1: Nested `if-else` Statements\n```java\nint age = 25;\ndouble income = 50000.0;\n\nif (age \u003e 18) {\n    if (income \u003e 30000) {\n        System.out.println(\"Eligible for loan.\");\n    } else {\n        System.out.println(\"Income too low for loan.\");\n    }\n} else {\n    System.out.println(\"Not eligible due to age.\");\n}\n```\n\n### Example 2: Enhanced `for` Loop with `continue`\n```java\nint[] numbers = {1, 2, 3, 4, 5};\nfor (int num : numbers) {\n    if (num % 2 == 0) {\n        continue; // Skip even numbers\n    }\n    System.out.println(\"Odd number: \" + num);\n}\n// Output: Odd number: 1, Odd number: 3, Odd number: 5\n```\n\n### Example 3: `switch` Statement with `enum`\n```java\nenum Day {\n    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY\n}\n\npublic static void printDayType(Day day) {\n    switch (day) {\n        case SATURDAY:\n        case SUNDAY:\n            System.out.println(day + \" is a weekend.\");\n            break;\n        default:\n            System.out.println(day + \" is a weekday.\");\n    }\n}\n\n// Usage\nprintDayType(Day.MONDAY); // Output: MONDAY is a weekday.\nprintDayType(Day.SUNDAY); // Output: SUNDAY is a weekend.\n```\n\n---\n\n### Methods\n\n#### 4.1 **Defining Methods**\n- **Syntax:**\n  ```java\n  returnType methodName(parameters) {\n      // method body\n  }\n  ```\n- Example:\n  ```java\n  public int add(int a, int b) {\n      return a + b;\n  }\n  ```\n  - `returnType`: The type of value the method returns (e.g., `int`, `void`).\n  - `methodName`: Name of the method, following Java naming conventions.\n  - `parameters`: Variables passed to the method (optional).\n  - `method body`: Code block executed when the method is called.\n\n#### 4.2 **Method Parameters and Return Types**\n- **Parameters:**\n  - Methods can accept input values called parameters.\n  - Example:\n    ```java\n    public void greet(String name) {\n        System.out.println(\"Hello, \" + name);\n    }\n    ```\n    - `String name`: A parameter of type `String`.\n\n- **Return Types:**\n  - The return type defines what data type the method will return.\n  - If a method doesn't return anything, use `void`.\n  - Example:\n    ```java\n    public int multiply(int x, int y) {\n        return x * y;\n    }\n    ```\n    - Return type: `int`, meaning the method returns an integer.\n\n#### 4.3 **Method Overloading**\n- Method overloading allows multiple methods to have the same name but different parameters (number, type, or both).\n- **Key Points:**\n  - Overloaded methods must differ in parameter list.\n  - Return type alone cannot differentiate overloaded methods.\n  \n- Example:\n  ```java\n  public int add(int a, int b) {\n      return a + b;\n  }\n\n  public double add(double a, double b) {\n      return a + b;\n  }\n\n  public int add(int a, int b, int c) {\n      return a + b + c;\n  }\n  ```\n  - Here, the method `add()` is overloaded with different parameter types and counts.\n\n#### 4.4 **Recursion**\n- Recursion occurs when a method calls itself to solve a problem.\n- **Key Points:**\n  - Must have a base condition to avoid infinite recursion.\n  - Useful for problems that can be divided into similar sub-problems (e.g., factorial, Fibonacci sequence).\n\n- Example:\n  ```java\n  public int factorial(int n) {\n      if (n == 0) {\n          return 1; // Base condition\n      } else {\n          return n * factorial(n - 1); // Recursive call\n      }\n  }\n  ```\n  - In this example, the method calls itself to compute the factorial of `n`.\n\n### Object-Oriented Programming (OOP) Concepts\n\n#### 5.1 **Classes and Objects**\n   - **Class**: A blueprint or template for creating objects. It defines attributes (fields) and behaviors (methods).\n   - **Object**: An instance of a class. Objects hold the actual data and can perform actions defined by methods.\n\n   ```java\n   class Car {\n       String model;\n       int year;\n\n       void displayInfo() {\n           System.out.println(\"Model: \" + model + \", Year: \" + year);\n       }\n   }\n\n   public class Main {\n       public static void main(String[] args) {\n           Car myCar = new Car();  // Creating an object\n           myCar.model = \"Toyota\";\n           myCar.year = 2020;\n           myCar.displayInfo();\n       }\n   }\n   ```\n\n#### 5.2 **Constructors**\n   - A special method that initializes objects of a class.\n   - It has the same name as the class and no return type.\n   - Can be **parameterized** or **non-parameterized**.\n   \n   ```java\n   class Car {\n       String model;\n       int year;\n\n       // Constructor\n       Car(String m, int y) {\n           model = m;\n           year = y;\n       }\n   }\n   ```\n\n#### 5.3 **`this` Keyword**\n   - Refers to the current instance of the class.\n   - Used to avoid ambiguity between class attributes and method parameters.\n\n   ```java\n   class Car {\n       String model;\n       int year;\n\n       Car(String model, int year) {\n           this.model = model;  // Referring to instance variables\n           this.year = year;\n       }\n   }\n   ```\n\n#### 5.4 **Inheritance**\n   - Allows one class to inherit the properties and methods of another class.\n   - Promotes code reuse and establishes a parent-child relationship.\n\n   ```java\n   class Vehicle {\n       String fuelType;\n   }\n\n   class Car extends Vehicle {\n       String model;\n   }\n   ```\n\n#### 5.5 **`super` Keyword**\n   - Refers to the parent class’s instance.\n   - Used to call parent class constructors or methods.\n\n   ```java\n   class Vehicle {\n       Vehicle() {\n           System.out.println(\"Vehicle Constructor\");\n       }\n   }\n\n   class Car extends Vehicle {\n       Car() {\n           super();  // Calls parent class constructor\n           System.out.println(\"Car Constructor\");\n       }\n   }\n   ```\n\n#### 5.6 **Method Overriding**\n   - Redefining a method in a child class that already exists in the parent class.\n   - The overridden method should have the same name, parameters, and return type.\n\n   ```java\n   class Vehicle {\n       void start() {\n           System.out.println(\"Vehicle is starting\");\n       }\n   }\n\n   class Car extends Vehicle {\n       @Override\n       void start() {\n           System.out.println(\"Car is starting\");\n       }\n   }\n   ```\n\n#### 5.7 **Polymorphism**\n   - The ability of an object to take many forms.\n   - **Compile-time polymorphism** (Method Overloading) and **Runtime polymorphism** (Method Overriding).\n\n#### 5.8 **Compile-time Polymorphism (Method Overloading)**\n   - Method overloading happens when multiple methods have the same name but different parameters (type, number, or both).\n   \n   ```java\n   class MathOperations {\n       int add(int a, int b) {\n           return a + b;\n       }\n\n       int add(int a, int b, int c) {\n           return a + b + c;\n       }\n   }\n   ```\n\n#### 5.9 **Runtime Polymorphism (Method Overriding)**\n   - Achieved through method overriding, where the method to be executed is determined at runtime based on the object type.\n\n   ```java\n   Vehicle myVehicle = new Car();\n   myVehicle.start();  // Calls Car's start() method\n   ```\n\n#### 5.10 **Encapsulation**\n   - The practice of bundling data (fields) and methods that operate on the data within a class and restricting access to them.\n   - Achieved using **private** access modifiers and providing **getter** and **setter** methods.\n\n   ```java\n   class Car {\n       private String model;\n       \n       public String getModel() {\n           return model;\n       }\n       \n       public void setModel(String model) {\n           this.model = model;\n       }\n   }\n   ```\n\n#### 5.11 **Abstraction**\n   - Hiding the implementation details and showing only essential information.\n   - Achieved using **abstract classes** and **interfaces**.\n\n   ```java\n   abstract class Vehicle {\n       abstract void start();\n   }\n\n   class Car extends Vehicle {\n       void start() {\n           System.out.println(\"Car is starting\");\n       }\n   }\n   ```\n\n#### 5.12 **Interfaces vs Abstract Classes**\n   - **Interface**: A contract that a class can implement. It only contains abstract methods (Java 8 allows default methods).\n   - **Abstract Class**: Can have both abstract and concrete methods. Cannot be instantiated.\n\n   ```java\n   interface Drivable {\n       void drive();\n   }\n\n   class Car implements Drivable {\n       public void drive() {\n           System.out.println(\"Driving a car\");\n       }\n   }\n   ```\n\n### Exception Handling\n\nException handling in Java is a mechanism used to handle runtime errors, ensuring the normal flow of the program isn't disrupted. Java uses `try`, `catch`, `finally`, `throw`, and `throws` keywords to handle exceptions.\n\n#### 6.1 **Types of Exceptions**\n\n- **Checked Exceptions**: \n  - These are exceptions that are checked at compile-time. If a method throws a checked exception, it must either handle the exception using a `try-catch` block or declare it using the `throws` keyword.\n  - Examples: `IOException`, `SQLException`\n\n- **Unchecked Exceptions**: \n  - These are exceptions that occur at runtime and are not checked during compilation. They are subclasses of `RuntimeException`. These don't need to be explicitly caught or declared.\n  - Examples: `NullPointerException`, `ArrayIndexOutOfBoundsException`, `ArithmeticException`\n\n#### 6.2 **try, catch, finally Blocks**\n\n- **try block**: This block contains code that might throw an exception. The code within the `try` block is executed, and if an exception occurs, the control is passed to the `catch` block.\n\n  ```java\n  try {\n      // Code that may throw an exception\n  }\n  ```\n\n- **catch block**: This block catches the exception thrown by the `try` block and handles it.\n\n  ```java\n  catch (ExceptionType e) {\n      // Handle the exception\n  }\n  ```\n\n- **finally block**: This block is always executed, regardless of whether an exception is thrown or not. It's typically used for cleanup operations like closing a file or database connection.\n\n  ```java\n  finally {\n      // Code that will always execute\n  }\n  ```\n\n##### Example:\n\n```java\ntry {\n    int data = 50 / 0;  // This will throw ArithmeticException\n} catch (ArithmeticException e) {\n    System.out.println(\"Exception caught: \" + e);\n} finally {\n    System.out.println(\"Finally block executed\");\n}\n```\n\n#### 6.3 **Throwing and Catching Exceptions**\n\n- **throw keyword**: The `throw` keyword is used to explicitly throw an exception from a method or any block of code.\n\n  ```java\n  throw new ArithmeticException(\"Division by zero\");\n  ```\n\n- **throws keyword**: When a method is capable of throwing an exception that it does not handle, it must declare it using the `throws` keyword in the method signature.\n\n  ```java\n  public void myMethod() throws IOException {\n      // Code that may throw IOException\n  }\n  ```\n\n#### 6.4 **Custom Exceptions**\n\nJava allows you to create your own exceptions by extending the `Exception` class (for checked exceptions) or the `RuntimeException` class (for unchecked exceptions).\n\n##### Example of a Custom Exception:\n\n```java\nclass CustomException extends Exception {\n    public CustomException(String message) {\n        super(message);\n    }\n}\n\npublic class TestCustomException {\n    public static void main(String[] args) {\n        try {\n            throw new CustomException(\"This is a custom exception\");\n        } catch (CustomException e) {\n            System.out.println(\"Caught: \" + e.getMessage());\n        }\n    }\n}\n```\n\nIn this example, `CustomException` is a user-defined exception that can be thrown and caught just like built-in exceptions.\n\n### Java Collections Framework\n\n#### **Overview of Collections**\nThe **Java Collections Framework (JCF)** provides a unified architecture for storing and manipulating groups of objects. It includes interfaces, classes, and algorithms to work with different types of collections such as lists, sets, and maps.\n\n- **Collection**: The root interface for all the collections. It provides methods for adding, removing, and querying elements.\n- **Collections Class**: A utility class that provides static methods to operate on collections (like sorting, searching).\n\n#### **Key Interfaces in the Java Collections Framework**\n\n1. **List Interface**  \n   A **List** is an ordered collection that allows duplicate elements. It maintains insertion order and can be accessed by index.\n\n   - **Implementations**: `ArrayList`, `LinkedList`, `Vector`\n   - **Common Methods**:\n     - `add(E element)`: Adds an element to the list.\n     - `get(int index)`: Retrieves an element at the specified index.\n     - `remove(int index)`: Removes an element at the specified index.\n     - `size()`: Returns the number of elements in the list.\n\n2. **Set Interface**  \n   A **Set** is a collection that doesn't allow duplicate elements. It does not maintain the order of insertion (except for LinkedHashSet).\n\n   - **Implementations**: `HashSet`, `TreeSet`, `LinkedHashSet`\n   - **Common Methods**:\n     - `add(E element)`: Adds an element if it is not already present.\n     - `remove(Object o)`: Removes the specified element.\n     - `size()`: Returns the size of the set.\n\n3. **Map Interface**  \n   A **Map** is a collection of key-value pairs. Each key is unique, and it maps to a single value. It does not inherit from `Collection`.\n\n   - **Implementations**: `HashMap`, `TreeMap`, `LinkedHashMap`\n   - **Common Methods**:\n     - `put(K key, V value)`: Associates the specified value with the specified key.\n     - `get(Object key)`: Retrieves the value for the given key.\n     - `remove(Object key)`: Removes the key-value pair for the specified key.\n     - `size()`: Returns the number of key-value mappings.\n\n#### **Implementations of Collection Interfaces**\n\n1. **ArrayList**  \n   A resizable array implementation of the `List` interface. Provides fast random access but slow insertions and deletions in the middle.\n\n   - Backed by an array.\n   - Allows duplicates.\n   - Dynamic resizing.\n\n2. **LinkedList**  \n   A doubly linked list implementation of `List`. It allows for faster insertions and deletions compared to `ArrayList` but slower random access.\n\n   - Implements both `List` and `Deque` (supports FIFO and LIFO operations).\n   - Allows duplicates.\n\n3. **HashSet**  \n   Implements the `Set` interface, backed by a hash table. It doesn't maintain the order of elements and allows `null` values.\n\n   - Fast lookup and insertion.\n   - Does not allow duplicates.\n\n4. **TreeSet**  \n   Implements `Set`, but maintains a sorted order of elements. It's backed by a Red-Black Tree.\n\n   - Sorted order (natural or custom comparator).\n   - Does not allow duplicates.\n\n5. **HashMap**  \n   An implementation of the `Map` interface, backed by a hash table. Provides fast access to key-value pairs but doesn't guarantee order.\n\n   - Allows `null` keys and values.\n   - Unordered.\n\n6. **TreeMap**  \n   Implements `Map` and maintains the keys in sorted order. Backed by a Red-Black Tree.\n\n   - Keys are sorted.\n   - Does not allow `null` keys.\n\n#### **Iterators and Loops with Collections**\n\n- **Iterator**: An object that allows traversal over elements in a collection one by one. It supports methods like `hasNext()`, `next()`, and `remove()`.\n  - Example:\n    ```java\n    Iterator\u003cString\u003e iterator = list.iterator();\n    while(iterator.hasNext()) {\n        String element = iterator.next();\n        // Process element\n    }\n    ```\n\n- **Enhanced for Loop**: A simplified loop to iterate over collections or arrays.\n  - Example:\n    ```java\n    for (String element : list) {\n        // Process element\n    }\n    ```\n\n- **ListIterator**: A specialized iterator for lists that allows bidirectional traversal.\n  - Methods: `hasPrevious()`, `previous()`\n\nThis section will help in understanding how Java collections work and how to use them efficiently in Java programs.\n\nHere’s a more detailed breakdown for your notes on **File Handling**, **Multithreading**, and **Java Input/Output (I/O)**:\n\n---\n\n### 8. **File Handling**\nJava provides a robust way to handle files through classes in the `java.io` package.\n\n#### a. **Reading and Writing Files**\n   - **Reading Files**\n     - `FileReader`: Used for reading character files.\n     - `BufferedReader`: Wraps `FileReader` for efficient reading of large files or multiple lines.\n     - Example: \n       ```java\n       BufferedReader br = new BufferedReader(new FileReader(\"file.txt\"));\n       String line;\n       while ((line = br.readLine()) != null) {\n           System.out.println(line);\n       }\n       br.close();\n       ```\n\n   - **Writing Files**\n     - `FileWriter`: Used for writing to character files.\n     - `BufferedWriter`: Provides efficient writing by buffering output.\n     - Example:\n       ```java\n       BufferedWriter bw = new BufferedWriter(new FileWriter(\"output.txt\"));\n       bw.write(\"Hello, World!\");\n       bw.close();\n       ```\n\n#### b. **Handling Input and Output (I/O) Streams**\n   - **Byte Streams**: Handle I/O of raw binary data.\n     - `FileInputStream` and `FileOutputStream`: Used to read and write raw bytes.\n     - Example:\n       ```java\n       FileInputStream fis = new FileInputStream(\"input.bin\");\n       int data;\n       while ((data = fis.read()) != -1) {\n           System.out.print((char) data);\n       }\n       fis.close();\n       ```\n\n   - **Character Streams**: Handle I/O of characters (text).\n     - `FileReader` and `FileWriter`: For character file I/O.\n\n#### c. **Serialization and Deserialization**\n   - **Serialization**: The process of converting an object into a byte stream to save to a file or transfer over a network.\n     - Implement `Serializable` interface to allow a class to be serialized.\n     - Example:\n       ```java\n       ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(\"object.ser\"));\n       oos.writeObject(myObject);\n       oos.close();\n       ```\n\n   - **Deserialization**: The process of converting the byte stream back into an object.\n     - Example:\n       ```java\n       ObjectInputStream ois = new ObjectInputStream(new FileInputStream(\"object.ser\"));\n       MyClass obj = (MyClass) ois.readObject();\n       ois.close();\n       ```\n\n---\n\n### 9. **Multithreading**\nMultithreading allows concurrent execution of two or more threads for maximum utilization of CPU.\n\n#### a. **Creating Threads**\n   - **Extending `Thread` Class**: Create a thread by extending the `Thread` class and overriding the `run()` method.\n     - Example:\n       ```java\n       class MyThread extends Thread {\n           public void run() {\n               System.out.println(\"Thread is running\");\n           }\n       }\n       MyThread t1 = new MyThread();\n       t1.start();\n       ```\n\n   - **Implementing `Runnable` Interface**: Another way to create a thread by implementing the `Runnable` interface.\n     - Example:\n       ```java\n       class MyRunnable implements Runnable {\n           public void run() {\n               System.out.println(\"Thread is running\");\n           }\n       }\n       Thread t1 = new Thread(new MyRunnable());\n       t1.start();\n       ```\n\n#### b. **Thread Lifecycle**\n   - **New**: Thread is created but not yet started.\n   - **Runnable**: After `start()` is called, the thread is ready to run.\n   - **Running**: When the thread is actively executing.\n   - **Blocked/Waiting**: When the thread is waiting for some condition or resources.\n   - **Terminated**: When the thread completes execution.\n\n#### c. **Synchronization**\n   - Used to prevent thread interference and consistency problems when multiple threads try to access shared resources.\n   - **Synchronized block/method**:\n     ```java\n     synchronized(this) {\n         // critical section\n     }\n     ```\n\n#### d. **Inter-thread Communication**\n   - Threads can communicate using methods like `wait()`, `notify()`, and `notifyAll()`.\n   - Example:\n     ```java\n     synchronized(obj) {\n         obj.wait();   // thread waits\n         obj.notify(); // wakes up waiting thread\n     }\n     ```\n\n---\n\n### 10. **Java Input/Output (I/O)**\nJava provides powerful I/O classes in the `java.io` package for handling input and output operations.\n\n#### a. **Streams (Byte Streams, Character Streams)**\n   - **Byte Streams**: Handle binary data (e.g., images, files).\n     - `InputStream` and `OutputStream`: Parent classes for byte-based I/O.\n     - Example:\n       ```java\n       FileInputStream fis = new FileInputStream(\"input.txt\");\n       FileOutputStream fos = new FileOutputStream(\"output.txt\");\n       int data;\n       while ((data = fis.read()) != -1) {\n           fos.write(data);\n       }\n       fis.close();\n       fos.close();\n       ```\n\n   - **Character Streams**: Handle character data (text).\n     - `Reader` and `Writer`: Parent classes for character-based I/O.\n\n#### b. **Reading and Writing Files**\n   - Reading and writing character-based files using `FileReader` and `FileWriter`.\n   - Buffered reading and writing using `BufferedReader` and `BufferedWriter`.\n\n#### c. **Buffering**\n   - **Buffered Streams**: Improve performance by reducing the number of I/O operations.\n   - Example of buffered input:\n     ```java\n     BufferedReader br = new BufferedReader(new FileReader(\"file.txt\"));\n     String line;\n     while ((line = br.readLine()) != null) {\n         System.out.println(line);\n     }\n     br.close();\n     ```\n\n  Sure! Here's an explanation for each of the Java 8 features and best practices:\n\n### **11. Java 8 Features**\n\n**Lambda Expressions:**\n- **Definition:** Lambda expressions provide a clear and concise way to represent one method interface using an expression. They are often used to implement functional interfaces.\n- **Syntax:** `(parameters) -\u003e expression` or `(parameters) -\u003e { statements }`\n- **Example:** `(a, b) -\u003e a + b` defines a lambda expression that takes two parameters and returns their sum.\n\n**Functional Interfaces:**\n- **Definition:** An interface with exactly one abstract method. They can have multiple default or static methods.\n- **Usage:** Functional interfaces are used as the basis for lambda expressions.\n- **Example:** `@FunctionalInterface` annotation can be used to indicate that an interface is intended to be functional.\n  ```java\n  @FunctionalInterface\n  public interface MyFunctionalInterface {\n      void singleAbstractMethod();\n  }\n  ```\n\n**Streams API:**\n- **Definition:** The Streams API allows you to process sequences of elements (e.g., collections) in a functional style.\n- **Key Methods:**\n  - `filter()`: Filters elements based on a predicate.\n  - `map()`: Transforms elements using a function.\n  - `reduce()`: Aggregates elements using a binary operator.\n  - `collect()`: Collects results into a collection.\n- **Example:**\n  ```java\n  List\u003cString\u003e names = Arrays.asList(\"Alice\", \"Bob\", \"Charlie\");\n  List\u003cString\u003e filteredNames = names.stream()\n                                    .filter(name -\u003e name.startsWith(\"A\"))\n                                    .collect(Collectors.toList());\n  ```\n\n**Optional Class:**\n- **Definition:** A container object which may or may not contain a value. It's used to avoid `null` checks and `NullPointerException`.\n- **Key Methods:**\n  - `of()`: Creates an Optional with a non-null value.\n  - `empty()`: Creates an empty Optional.\n  - `isPresent()`: Checks if a value is present.\n  - `ifPresent()`: Executes a block of code if a value is present.\n  - `orElse()`: Provides a default value if no value is present.\n- **Example:**\n  ```java\n  Optional\u003cString\u003e optionalName = Optional.of(\"Alice\");\n  String name = optionalName.orElse(\"Default Name\");\n  ```\n\n**Method References:**\n- **Definition:** A shorthand notation of a lambda expression to call a method. It allows for cleaner and more readable code.\n- **Syntax:** `ClassName::methodName` or `instance::methodName`\n- **Example:**\n  ```java\n  List\u003cString\u003e names = Arrays.asList(\"Alice\", \"Bob\", \"Charlie\");\n  names.forEach(System.out::println);\n  ```\n\n**Default Methods:**\n- **Definition:** Methods in interfaces that have a body. They provide default implementations that can be overridden by implementing classes.\n- **Usage:** Allows you to add new methods to interfaces without breaking existing implementations.\n- **Example:**\n  ```java\n  public interface MyInterface {\n      default void defaultMethod() {\n          System.out.println(\"This is a default method.\");\n      }\n  }\n  ```\n\n### **12. Java Best Practices**\n\n**Code Conventions:**\n- **Definition:** Guidelines and rules for writing code to ensure readability and consistency.\n- **Key Points:**\n  - Follow naming conventions (e.g., camelCase for variables, PascalCase for classes).\n  - Use proper indentation and spacing.\n  - Keep methods short and focused on a single task.\n  - Comment code where necessary to explain complex logic.\n\n**Exception Handling Best Practices:**\n- **Definition:** Guidelines for effectively handling exceptions to ensure robustness and maintainability.\n- **Key Points:**\n  - Use specific exceptions rather than generic ones.\n  - Avoid catching `Throwable` or `Exception` unless absolutely necessary.\n  - Always provide meaningful messages in exceptions.\n  - Don’t swallow exceptions; always handle them appropriately or log them.\n  - Use `try-with-resources` for automatic resource management.\n\n**Effective Use of Collections:**\n- **Definition:** Best practices for using Java Collections Framework efficiently.\n- **Key Points:**\n  - Choose the right collection type for your needs (e.g., `ArrayList` for fast access, `LinkedList` for frequent insertions/removals).\n  - Use generics to ensure type safety.\n  - Understand and use the differences between `List`, `Set`, and `Map`.\n  - Use immutable collections where applicable.\n\n**Writing Clean and Maintainable Code:**\n- **Definition:** Practices for writing code that is easy to read, understand, and maintain.\n- **Key Points:**\n  - Follow Single Responsibility Principle (SRP) to ensure classes and methods have one reason to change.\n  - Write self-explanatory code by using descriptive names and breaking down complex logic into smaller methods.\n  - Refactor code regularly to improve readability and remove redundancy.\n  - Use unit tests to ensure code correctness and facilitate refactoring.\n\nThis structure should give you a solid foundation for understanding and applying Java 8 features and best practices effectively.\n\n1. Clone the repository:\n    ```bash\n    git clone https://github.com/your-username/java-fundamentals.git\n    ```\n2. Explore the `src/` folder for code examples on each topic.\n\n## Contributing\n\nFeel free to fork this repository and contribute by submitting pull requests. Please ensure that your code follows standard Java best practices.\n\n## License\n\nThis repository is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisurusankhajith%2Fjava-fundamentals","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fisurusankhajith%2Fjava-fundamentals","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisurusankhajith%2Fjava-fundamentals/lists"}