JAVA Documentation

What is Java?

Java is a high-level, class-based, object-oriented programming language designed to have as few implementation dependencies as possible. It is a general-purpose programming language intended to let programmers write once, run anywhere (WORA), meaning that compiled Java code can run on all platforms that support Java without the need for recompilation.
Note: Java was developed by James Gosling at Sun Microsystems (later acquired by Oracle) and released in 1995. The language derives much of its syntax from C and C++ but has simpler object model and fewer low-level facilities. java ka purana name Oak tha java ko 2010 me oracle ne parcharge karliya tha current me java oracle ka product hai .
Note: java me yadi ap ko ye check karna ho ki predefine class ke under kitni method hai to cmd per javap pakeage-name.class-name ki commod se dekhte hai .
Note: Ide ka full form Integrated development enoarment hai.

Java is used for:

  1. Mobile Applications (especially Android apps)
  2. Desktop Applications
  3. Web Applications
  4. Web Servers and Application Servers
  5. Enterprise Applications
  6. Scientific Computing Applications
  7. Big Data Technologies (Hadoop, Spark)
  8. Embedded Systems
  9. Game Development

Why use Java?

  1. Platform Independent - Write Once Run Anywhere (WORA)
  2. Object-Oriented Programming Language
  3. Strong Memory Management
  4. High Performance with Just-In-Time (JIT) compiler
  5. Multithreaded
  6. Rich API and huge community support

Unit Of Data

Data Type Size Range/Description Storage Units
byte 8 bits -128 to 127 1 Byte
short 16 bits -32,768 to 32,767 2 Bytes
int 32 bits -231 to 231-1 4 Bytes
long 64 bits -263 to 263-1 8 Bytes
float 32 bits Single-precision floating point 4 Bytes
double 64 bits Double-precision floating point 8 Bytes
char 16 bits Single Unicode character ('\u0000' to '\uffff') 2 Bytes
boolean 1 bit true or false 1 bit (typically 1 Byte in memory)

Data Storage Units:

Unit Size Equivalent
Bit (b) 1 binary digit 0 or 1
Byte (B) 8 bits 1 character
Kilobyte (KB) 1024 Bytes ≈1,000 Bytes
Megabyte (MB) 1024 KB ≈1 million Bytes
Gigabyte (GB) 1024 MB ≈1 billion Bytes
Terabyte (TB) 1024 GB ≈1 trillion Bytes
Petabyte (PB) 1024 TB ≈1 quadrillion Bytes
Exabyte (EB) 1024 PB ≈1 quintillion Bytes
Zettabyte (ZB) 1024 EB ≈1 sextillion Bytes
Yottabyte (YB) 1024 ZB ≈1 septillion Bytes
Key Notes:
1. 1 Byte = 8 bits
2. Each higher unit is 1024 times the previous (binary system)
3. Boolean typically uses 1 byte in memory (not just 1 bit) due to memory addressing
4. Storage devices often use decimal prefixes (1KB = 1000B) while RAM uses binary (1KB = 1024B)
5. JVM ke dependent hone ke reason se hi java platfor independent hai . kyu ki har ak operating system ka apna khud ka JVM hota hai.

What is Token ?

A Token is the smallest unit of code that has meaning to the java compiler,such as keyword,identifire,literals,operators,or symbols.

Types of Tokens in Java:

  1. Keywords
    These are reserved words that have special meaning.
    Examples: class, public, static, void, if, else
  2. Identifiers
    Whatever the name we are using in java program is called as identifire . Names given to classes, methods, variables etc.
    Examples: MyClass, main, age
  3. Literals
    A literal is a constant value written directly in the source code ,such as a number,character,string, or boolean..
    Examples: 100, 3.14, 'A', "Hello", true
  4. Operators
    Operators are used to perform operations Between variables and values.
    Examples: +, -, *, /, %, =, ==
  5. Separators
    Symbols used to separate code elements.
    Examples: ; (semicolon), {} (curly braces), [] (square brackets)
  6. Comments
    Comments can be used to explain Java code, and to make it more readable. It can also be used to prevent execution when testing alternative code.
    Examples: // single-line, /* multi-line */
    Single-line Comments
    Single-line comments start with two forward slashes (//).

    Example:

                    System.out.println("Hello World"); // This is a comment
                  
    Multi-line Comments
    Multi-line comments start with /* and ends with */.

    Example:

                   /* The code below will print the words Hello World
    to the screen, and it is amazing */
    System.out.println("Hello World");
                  
Note:
Total Reserved Words in Java: 53
➤ Used Keywords: 48
➤ Reserved but Not Used Keywords: const, goto
➤ Reserved Literals: true, false, null

List of 48 Used Keywords:
abstract, assert, boolean, break, byte, case, catch, char, class, continue,
default, do, double, else, enum, extends, final, finally, float, for,
if, implements, import, instanceof, int, interface, long, native, new,
package, private, protected, public, return, short, static, strictfp, super,
switch, synchronized, this, throw, throws, transient, try, var, void, volatile, while, record, sealed, non-sealed, permits

Cookies in Java Web Applications

Definition: Cookies are small pieces of data stored on the client's browser. They are sent with each request to the server.

Example:

// Creating a cookie in Servlet
Cookie userCookie = new Cookie("user", "JohnDoe");
userCookie.setMaxAge(60*60*24*30); // 30 days
response.addCookie(userCookie);

// Reading cookies
Cookie[] cookies = request.getCookies();
if(cookies != null) {
    for(Cookie cookie : cookies) {
        if(cookie.getName().equals("user")) {
            String value = cookie.getValue();
        }
    }
}

Session in Java

Definition: Session is a server-side state management technique that stores user-specific data on the server.

Example:

// Storing data in session (Servlet)
HttpSession session = request.getSession();
session.setAttribute("username", "JohnDoe");
session.setAttribute("cartItems", cartItems);

// Retrieving data from session
String username = (String) session.getAttribute("username");
List<CartItem> items = (List<CartItem>) session.getAttribute("cartItems");

// Invalidating session (logging out)
session.invalidate();

Key Differences:

  1. Storage Location: Cookies are client-side, Sessions are server-side
  2. Capacity: Cookies have size limits (~4KB), Sessions can store more data
  3. Security: Session is more secure as data stays on server
  4. Persistence: Cookies can persist beyond session, Session ends when browser closes (by default)

Key Features of Java

  1. Simple:

    Java is designed to be easy to learn with clear syntax (similar to C/C++) but without complex features like pointers.

  2. Object-Oriented:

    Java follows Object-Oriented principles like Encapsulation, Inheritance, Polymorphism, and Abstraction.

  3. Platform Independent:

    Java code is compiled to bytecode that runs on JVM, making it platform independent ("Write Once Run Anywhere").

  4. Secure:

    Java provides features like no explicit pointers, bytecode verification, and security manager for safe execution.

  5. Multithreaded:

    Java supports multithreaded programming for developing concurrent applications.

Variables in Java

Variables are used to store different type data but it depends upon data types.whenever an object of class is created memory is allocated for non-static data members of class.

There are 3 types of variables in Java:

  1. Local variables:

    If Variables are define with in the methods, constructors or blocks is called as local variables. They must be initialized before use.

    Note: Local variabls are maintan at stack area. program me sabse pahle local variable distroy hota hai fir instance variable tatha badme statick variable distroy hote hai.
  2. Instance variables:

    Instance variables are non-static variables and are declared in a class but outside any method, constructor or block.

    Whenever an object is created space or memory is allocated for non-static variables in heap area every time.

    Note: non-static variables me value store karne keliye object banana padta hai bina object create kiye value store nahi kar sakte hai.non-static variable ko memory me space tabtak nahi milta hai jabtak oject create nahi hota hai isiliye object create karna padta hai.
  3. Static variables:

    It data member of a class is declared as static keyword then one memory address of that member will be created method area.

    Note: static variables ko memory me space keval ak bar milta hai.

Data Types in Java

A data type specifies the kind of value a variable can store and how much memory will be allocated for that variable.

Primitive Data Types

Primitive data types are the basic data types that are directly handled by the processor. Their size and range are predefined, and they are the most commonly used data types in java.

Java has 8 primitive data types that are predefined by the language:

Data Type Size (Bits) Range/Description
byte 8 -128 to 127
short 16 -32,768 to 32,767
int 32 -231 to 231-1
long 64 -263 to 263-1
float 32 Single-precision floating point
double 64 Double-precision floating point
char 16 Single Unicode character ('\u0000' to '\uffff')
boolean 1 (bit) true or false

Example:

int age = 30;          // Integer
double price = 19.99;  // Floating point
char grade = 'A';      // Character
boolean isJavaFun = true; // Boolean

Non-Primitive Data Types

Non-primitive data types are reference types created by the programmer, such as classes, arrays, strings, and interfaces. They store references to memory and can hold multiple or complex values.

Type Inference in Java (var)

var is a feature introduced in Java 10 that allows the compiler to infer the type of a local variable from the initializer expression.

Key Points:

Syntax:

var variableName = expression;

Example 1: Using var with String

Example:

var greeting = "Hello, Java!";
System.out.println(greeting.toUpperCase()); // HELLO, JAVA!
    

Example 2: Using var with List

Example:

var names = new ArrayList<String>();
names.add("Alice");
names.add("Bob");
System.out.println(names.get(0)); // Alice
    

Example 3: Using var in For-Each Loop

Example:

var numbers = List.of(10, 20, 30);
for (var num : numbers) {
    System.out.println(num);
}
    

Rules and Limitations:

When was var introduced?

Java 10, released in March 2018, introduced var as part of JEP 286 - Local-Variable Type Inference.

Access Modifiers in Java

Access modifiers are used to define the visibility/accessibility level members of a class . Basically security point of view we are using this concept.

Types of Access Modifiers:

  1. public:

    public member can be access with in the class as well as outside the class and out side the package.

    Note: Gernally method,constructor,class are kept public.
  2. private:

    private member can be access with in class only ,not out side the class.

    Note: Gernally Data members are kept private.
  3. protected:

    Accessible within the same package and subclasses.

    protected member can be access with in the class as well as out side the class as well as out side package also but that class should be child class of it.

  4. default (no modifier):

    Accessible only within the same package.

    Note: jab hum koi asscess modifire use nahi karte tab defaul work karta hai.

Example:

public class MyClass {
    public int publicVar;
    private int privateVar;
    protected int protectedVar;
    int defaultVar;  // default access
    
    public void publicMethod() { }
    private void privateMethod() { }
    protected void protectedMethod() { }
    void defaultMethod() { }  // default access
}
Note:
Total Modifiers in Java: 11
➤ Access Modifiers: 4 (public, protected, default, private)
➤ Non-Access Modifiers: 7 (final, static, abstract, synchronized, volatile, transient, strictfp)

List of Access Modifiers with Scope:
public: Accessible from anywhere.
protected: Accessible within the same package and subclasses in other packages.
default (no modifier): Accessible only within the same package.
private: Accessible only within the same class.

List of Non-Access Modifiers with Purpose:
final: Prevents modification (variable value, method overriding, class inheritance).
static: Belongs to the class instead of instances.
abstract: Used for abstraction (classes and methods).
synchronized: Controls thread access to methods or blocks.
volatile: Variable value is always read from main memory.
transient: Prevents serialization of variables.
strictfp: Enforces floating-point precision rules.

Type Casting

Type casting is when you assign a value of one primitive data type to another type.
In Java, there are two types of casting:

Widening Casting(automatically)

Widening casting is done automatically when passing a smaller size type to a larger size type
byte -> short -> char -> int -> long -> float -> double

Example:

   public class Main {
  public static void main(String[] args) {
    int myInt = 9;
    double myDouble = myInt; // Automatic casting: int to double

    System.out.println(myInt);      // Outputs 9
    System.out.println(myDouble);   // Outputs 9.0
  }
}
  

Narrowing Casting (manually)

Narrowing casting must be done manually by placing the type in parentheses () in front of the value double -> float -> long -> int -> char -> short -> byte

Example:

  public class Main {
  public static void main(String[] args) {
    double myDouble = 9.78d;
    int myInt = (int) myDouble; // Manual casting: double to int

    System.out.println(myDouble);   // Outputs 9.78
    System.out.println(myInt);      // Outputs 9
  }
}
  

Operators in Java

Operators are symbols that perform operations on variables and values.

Arithmetic Operators

Used for mathematical operations:

Example:

int a = 10, b = 3;
int sum = a + b;      // 13
int remainder = a % b; // 1
a++;                   // a becomes 11

Relational Operators

Used for comparisons (return boolean):

Example:

int x = 5, y = 10;
boolean result = x < y;  // true

Logical Operators

Used for logical operations (return boolean):

Example:

boolean a = true, b = false;
boolean andResult = a && b;  // false
boolean orResult = a || b;   // true
boolean notResult = !a;      // false

Assignment Operators

Used to assign values to variables:

Example:

int x = 5;
x += 3;  // equivalent to x = x + 3; x becomes 8

Bitwise Operators

Used to perform operations on individual bits:

Example:

int a = 5;    // 0101 in binary
int b = 3;    // 0011 in binary
int result = a & b;  // 0001 (1 in decimal)

Ternary Operator

Ternary operator is a short form if-else statement. Its syntax is: condition ? value_if_true : value_if_false

Example:

int a = 10, b = 5;
int max = (a > b) ? a : b;  // max = 10

Conditional Statements(Control Flow Statements)

control flow statements are used to control program execution. There are 3 types:

Decision Making Statements

  1. if statement:

    Use the if statement to specify a block of Java code to be executed if a condition is true.

                          if (20 > 18) {
                          System.out.println("20 is greater than 18");
                        }
                    
  2. else statement:

    Use the else statement to specify a block of code to be executed if the condition is false.

                        int time = 20;
                       if (time < 18) {
                         System.out.println("Good day.");
                       } else {
                         System.out.println("Good evening.");
                       }
                       // Outputs "Good evening."
                   
  3. else if statement:

    Use the else if statement to specify a new condition if the first condition is false.

                        int time = 22;
                        if (time < 10) {
                          System.out.println("Good morning.");
                        } else if (time < 18) {
                          System.out.println("Good day.");
                        } else {
                          System.out.println("Good evening.");
                        }
                        // Outputs "Good evening."
                   
  4. if-else-if ladder:
                     if (condition1) {
                         // code if condition1 is true
                     } else if (condition2) {
                         // code if condition2 is true
                     } else {
                         // code if all conditions are false
                     }
                 
  5. Ternary(Short Hand if...else)

    There is also a short-hand if else, which is known as the ternary operator because it consists of three operands.

                        int time = 20;
                        String result = (time < 18) ? "Good day." : "Good evening.";
                        System.out.println(result);
                    
  6. switch statement:

    A switch statement allows you to execute different blocks of code based on the value of a variable. It compares the variable with multiple possible values (cases) and runs the code corresponding to the first match. If no match is found, the default block is executed.

    switch (expression) {
        case value1:
            // code
            break;
        case value2:
            // code
            break;
        default:
            // default code
    }
Note: If break is not given, control will execute next case (fall-through behavior, which is not allowed in C#).

Looping Statements

Loop execute a block of code repeatedly while a condition is true.

  1. for loop:

    A for loop is a control flow statement used when you know exactly how many times you want to repeat a block of code.

    for (initialization; condition; update) {
        // code to repeat
    }
  2. while loop:

    while loop executes as long as condition is true. It checks condition first.

    while (condition) {
        // code to repeat
    }
  3. do-while loop:

    do-while loop is similar to while loop, but condition is checked at the end, so loop body executes at least once.

    do {
        // code to repeat
    } while (condition);

4. forEach Loop in Java

Modern Iteration: Introduced in Java 8 to simplify collection and array traversal

1. Basic forEach Syntax

// List example List names = Arrays.asList("John", "Jane", "Doe"); // Method reference style names.forEach(System.out::println); // Lambda expression style names.forEach(name -> System.out.println(name.toUpperCase()));

2. forEach with Different Collections

With Lists

List numbers = List.of(1, 2, 3); numbers.forEach(n -> System.out.println(n * 2));

With Maps

Map ages = Map.of("Alice", 25, "Bob", 30); ages.forEach((name, age) -> System.out.println(name + " is " + age + " years old"));

With Arrays

String[] colors = {"Red", "Green", "Blue"}; Arrays.stream(colors).forEach(System.out::println);

3. Key Features

4. Comparison: Traditional vs forEach

Feature Traditional for-loop forEach
Syntax Verbose Concise
Control Supports break/continue No control statements
Readability Explicit iteration Declarative style

5. Practical Examples

// Example 1: Filtering with Stream + forEach List nums = List.of(1, 2, 3, 4, 5); nums.stream() .filter(n -> n % 2 == 0) .forEach(System.out::println); // Example 2: Modifying elements List words = new ArrayList<>(List.of("hello", "world")); words.forEach(word -> { if(word.equals("hello")) { words.set(words.indexOf(word), "hi"); } });
Important: Avoid modifying collections during forEach iteration to prevent ConcurrentModificationException

6. When to Use forEach?

Jump Statements

  1. break:

    break statement is used to immediately exit a loop or switch statement.

  2. continue:

    continue statement is used to skip current iteration and jump to next iteration.

  3. return:

    Purpose:

    1. Stops the execution of the method.
    2. If method returns a value (non-void), return sends back that value.
    3. If method is void type, return; just stops execution.
    4. When we want to stop method execution based on some condition, we use return.

Methods in Java

A method is a block of code that performs a specific task and can be called when needed. Methods help in organizing code, improving reusability, and making the code more modular.

Method Syntax

access_modifier return_type method_name(parameter_list) {
    // method body
    return value; // if return_type is not void
}

Example:

public int addNumbers(int a, int b) {
    int sum = a + b;
    return sum;
}
We use methods in programming for:

1. Reusability: Avoid repeating the same code. Call a method whenever needed.
2. Modularity: Break down complex tasks into smaller, manageable pieces.
3. Maintainability: Easily update and maintain code in one place.
4. Abstraction: Hide complex details, making the code simpler to use.
5. Organization: Keep code structured and clean.
6. Testing: Easier to test individual parts of the code.
7. Reusability Across Programs: Methods can be reused in different programs. Methods help keep code clean, efficient, and manageable.

Note: yadi kisi method ka return type void hai to use kisi temprary variable me assign nahi kar sakte hai tatha void type ki method ko kisi method kender likh kar call nahi kar sakte hai void type ki method per return keyword use nahi karte hai kyu ki ya koi bhi value return nahi karti hai.

Method Overloading

Defining multiple method in a class having same name is called as method overloading but Number of arguments or types of arguments must be different. The correct method is called based on the number and type of arguments passed.

why use method Overloading:

1. To perform similar actions in different ways.
2. Improves readability and code reuse.
3. Reduce the complexity .
4. Developer can easily remember that overloaded method by passing different number or different types of arguments.

Example:

class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
    
    public double add(double a, double b) {
        return a + b;
    }
    
    public int add(int a, int b, int c) {
        return a + b + c;
    }
}

Java Scope

In Java, variables are only accessible inside the region they are created. This is called scope.

Method Scope

Variables declared directly inside a method are available anywhere in the method following the line of code in which they were declared

Example

        public class Main {
          public static void main(String[] args) {
        
            // Code here CANNOT use x
        
            int x = 100;
        
            // Code here can use x
            System.out.println(x);
          }
        }
        

Block Scope

A block of code refers to all of the code between curly braces {}.
Variables declared inside blocks of code are only accessible by the code between the curly braces, which follows the line in which the variable was declared

Example

   public class Main {
  public static void main(String[] args) {

    // Code here CANNOT use x

    { // This is a block

      // Code here CANNOT use x

      int x = 100;

      // Code here CAN use x
      System.out.println(x);

    } // The block ends here

  // Code here CANNOT use x

  }
}

    

Recursion

Recursion is a method calling itself to solve a problem. It helps break down complex problems into smaller sub-problems. A recursive method typically has a base case to stop the recursion and prevent an infinite loop.

Example: Recursive Factorial Calculation

class MathOperations {
    public int Factorial(int n) {
        if (n < 0) {
            throw new ArgumentException("Negative numbers not allowed.");
        }
        
        if (n == 0)
            return 1;  // Base case
        else
            return n * Factorial(n - 1);  // Recursive call
    }
}

// Usage:
MathOperations math = new MathOperations();
int result = math.Factorial(5);  // Returns 120

new keyword

new keyword allocates memory in the heap and invokes the constructor to initialize the object.

this keyword

The this keyword refers to the current object of the class — it is used to access the current instance’s fields, properties, or methods.

Example:

public class Student {
    String name; // Instance variable
    
    public void setName(String name) {
        this.name = name; // 'this.name' refers to the instance variable
    }
}

Classes

1. A class is a blueprint of an objects.
2. Class is a collection of similar type of object means we can create many number of object any class.
3. Class is a user define datatype.

Objects

1. An object is real implimentation of a class.
2. object is a run time entity.
3. An object is an instance of a class.

Example:

// Class definition
class Car {
    // Fields (instance variables)
    String color;
    int maxSpeed;
    
    // Method
    void displayInfo() {
        System.out.println("Color: " + color + ", Max Speed: " + maxSpeed);
    }
}

public class Main {
    public static void main(String[] args) {
        // Creating objects
        Car car1 = new Car();
        car1.color = "Red";
        car1.maxSpeed = 200;
        
        Car car2 = new Car();
        car2.color = "Blue";
        car2.maxSpeed = 180;
        
        // Calling methods
        car1.displayInfo();
        car2.displayInfo();
    }
}
Note: First letter of class should be capital letter.
Note: jab kisi class ka object banate hai to class ke data members (variables) ke liye memory allocat hoti hai.

Static Class in Java

In Java, a static class can only be a nested class — that is, a class defined inside another class. It is called a static nested class.

Unlike non-static nested classes (inner classes), a static nested class does not have access to the instance members of the outer class. It can only access static members of the outer class.

Use Cases:

Example:

class OuterClass {
    static int outerValue = 100;

    // Static nested class
    static class NestedClass {
        void display() {
            System.out.println("Outer value: " + outerValue);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        OuterClass.NestedClass obj = new OuterClass.NestedClass();
        obj.display(); // Output: Outer value: 100
    }
}
    

Key Points:

Sealed Classes in Java

Java introduced sealed classes in Java 15 as a preview feature and finalized it in Java 17. A sealed class restricts which classes can extend or implement it using the permits clause.

Purpose

Keywords Used

Example:

public sealed class Vehicle permits Car, Bike { }

public final class Car extends Vehicle { }

public final class Bike extends Vehicle { }
    

Another Example Using non-sealed

If you want a subclass to allow further inheritance, use non-sealed:

Example:

public sealed class Animal permits Dog, Cat { }

public non-sealed class Dog extends Animal {
    // other classes can still extend Dog
}

public final class Cat extends Animal { }
    

Note:

All subclasses listed in permits must be in the same package or module and must be declared as either sealed, non-sealed, or final.

Sealed classes were introduced in Java 15 (as a preview) and finalized in Java 17. They are used to control inheritance by restricting which classes can extend or implement them.

new keyword

new keyword allocates memory in the heap and invokes the constructor to initialize the object.

Constructors in Java

A constructor is a special method that is automatically called when an object is created.

Note:
why they are spacial ?
➤ 1. they have same name as class name .
➤ 2. they does not have any return type even void .
➤ 3. they are autometically executed whenever an object of its class is created .

Note:
why we use constructor in java ?
➤ constructor are used to initialization of an object means to assign some default value an object is created .

Note: hum apni class ka object usi prakar ka create kar sakte hai jis prakar ka constructor hamari class me hoga.

Types of Constructors

  1. Default Constructor:

    Default constructor is a constructor that does not take any parameters. There are 2 types

    User Define Defaul Constructor

    When a user creates a zero-parameter constructor manually in a program, it is called a user-defined default constructor.

    System Define Defaul Constructor

    When your java class does not have any constructor then compiler internaly adds a default constructor in your class at the time of compilation.and such type of constructor is called as system define default constuctor. There are two types of Dedault constructor.

    Note:
    What values are set by system-defined default constructor for different data types?
    System define deault constructor final variable per value assign karta hai

    int → 0
    float → 0.0f
    double → 0.0d
    decimal → 0.0m
    bool → false
    char → '\0' (null character)
    string → null
    object → null
    long → 0L
    short → 0
    byte → 0
    sbyte → 0
    uint → 0
    ulong → 0
    ushort → 0
    nint / nuint → 0 (C# 9+)
    enum → first defined value (default is 0)
    arrays → null (reference type)
    class objects → null
    structs → all fields set to their respective default values

    These default values are automatically assigned by the system-defined default constructor when a class or struct object is created without parameters.
    class MyClass {
        // Default constructor (created by compiler if not defined)
        MyClass() {
        }
    }
  2. Parameterized Constructor:

    Constructor with parameters.

    class Student {
        String name;
        int age;
        
        // Parameterized constructor
        Student(String n, int a) {
            name = n;
            age = a;
        }
    }
  3. Copy Constructor:

    Copy Constructor is used to copy the data of an existing objet to a newly created object.

    class Circle {
        
        int r;
        
        // Copy constructor
        Circle(int x)       // normal parametrized 
       {
           
            r = x;
        }
     Circle(Circle k)       // copy constructor
    {
        
        this.r=k.r;
     }
     void area()      
    {
        
        double a=3.14*r*r; 
       System.out.println("area of circle is ="+a)
     }
    public static void main(String[] args)       // normal parametrized 
    {
        Circle r1=new Circle(5);
        Circle r2=new Circle(10);
        Circle r3=new Circle(r1);
        //both area is same r1.area(),r2.area();
        r1.area();      
        r2.area();
        
        
     }
    }

Instance Initialization Block in Java

If a block is defined as does not have any name ,return type ,arguments list is called as instace block. instance block is automatically executed whenever an object of its class is created but before constructor calling. and execution flow is top to bottom.

Instance Initialization Block (IIB) is used to initialize instance variables. It runs every time an object of the class is created, before the constructor.

Example:

class MyClass {

    // Instance Initialization Block

    {
        System.out.println("Instance Initialization Block executed");
    }
    
    MyClass() {
        System.out.println("Constructor executed");
    }
    
    public static void main(String[] args) {
        MyClass obj = new MyClass();
    }
}

Output:

Instance Initialization Block executed
Constructor executed
Key Points about IIB:
  1. Runs every time an object is created
  2. Executes before the constructor
  3. Can have multiple IIBs in a class - they execute in the order they appear
  4. Used to share common code between constructors
Why we use instace block ?
➤ Whenever you want to execute your logic or code irrespective of constructor then compaulsory you write your logic or code inside the instance block.

Static Block in Java

If a block is defined by using statick keyword is called as static block.

Key Points:
➤ Static block will executed only once before the main() method calling.
➤ In java a class can contain many number of statick block and execution flow is top to bottom .
➤ In static block we can access only static member .
➤ It runs only once when the class is loaded by the JVM.
➤ It can be used to initialize static data members or perform setup operations.
➤ Static block does not require object creation.
Can we execute our java program without main method ?
➤ yes we can run java program without main method is also with the help of static block but this feature is applicable for version 1.6 but now in java 8 main is compulsary.

Example (Static Block):

public class Demo {

    static int x;

    // Static block
    static {
        System.out.println("Static block executed");
        x = 10;
    }

    public static void main(String[] args) {
        System.out.println("Main method executed");
        System.out.println("Value of x = " + x);
    }
}
    

Output:

Static block executed
Main method executed
Value of x = 10

Final Keyword in Java

The final keyword in Java is used to restrict the user. It can be applied to variables, methods, and classes.

1. Final Variable

If a variable declared as a final than its become as a constant means its value can not change.

Example:

class FinalExample {
    final int MAX_VALUE = 100; // final variable
    
    void changeValue() {
        // MAX_VALUE = 200; // Compile-time error
    }
}

2. Final Method

If member function of class is declared as final then it cannot be overridden in chield class .

Example:

class Parent {
    final void display() {
        System.out.println("This is a final method");
    }
}

class Child extends Parent {
    // void display() { } // Compile-time error - cannot override
}

3. Final Class

If class is declare as a final then it cannot be extends mens we can not create chield class from it .it is jut opposite to an abstract class . it is bottom class in inheritance herirchy.

Example:

final class FinalClass {
    // class content
}

// class ChildClass extends FinalClass { } // Compile-time error
When to use final:
  1. Final variables: When you want to create constants
  2. Final methods: When you want to prevent method overriding
  3. Final classes: When you want to prevent inheritance (e.g., String class is final)

Java Packages

A package in Java is used to group related classes. Think of it as a folder in a file directory. We use packages to avoid name conflicts, and to write a better maintainable code. Packages are divided into two categories:
1. Built-in Packages (packages from the Java API)
2. User-defined Packages (create your own packages)

Built-in Packages

Built-in Packages vo package hote hai jo java me pahle se bane hai .

Example:

           import java.util.Scanner;

class MyClass {
  public static void main(String[] args) {
    Scanner myObj = new Scanner(System.in);
    System.out.println("Enter username");

    String userName = myObj.nextLine();
    System.out.println("Username is: " + userName);
  }
}
        

User-defined Packages

To create your own package, you need to understand that Java uses a file system directory to store them. Just like folders on your computer

Example:

            package mypack;
      class MyPackageClass {
        public static void main(String[] args) {
          System.out.println("This is my package!");
        }
      }
   

Example:

          Save the file as MyPackageClass.java, and compile it:
C:\Users\Your Name>javac MyPackageClass.java
Then compile the package:
C:\Users\Your Name>javac -d . MyPackageClass.java

Object-Oriented Programming (OOP) Concepts

Java is an object-oriented language that supports four main OOP concepts:

1. Encapsulation

Encapsulation is tha process of Binding data member (variables) and Member Function (methods) together in a single unit and restricting direct access to some components is called as Encapsulation.

Example:

class BankAccount {
    private double balance;  // private variable
    
    // public methods to access balance
    public void deposit(double amount) {
        if(amount > 0) balance += amount;
    }
    
    public double getBalance() {
        return balance;
    }
}

2. Inheritance

Parent class properties and method inherited by child class is called as inheritance.it is technique of creating new classes from existing one the main purpose of inheritance is reusing code .

Example:

class Vehicle {  // Superclass
    void run() {
        System.out.println("Vehicle is running");
    }
}

class Car extends Vehicle {  // Subclass
    void accelerate() {
        System.out.println("Car is accelerating");
    }
}

3. Polymorphism

Polymorphism is a concept by which we can perform a single task in different ways overloading and overriding helps to achive polymorphism. Polymorphism allows methods to do different things based on the object calling them. There are two types of polymorphism:

➤ Method Overloading (Compile-Time Polymorphism)

Defining multiple method in a class having same name is called as method overloading but Number of arguments or types of arguments must be. The correct method is called based on the number and type of arguments passed.

Why we use Method Overloading?
➤ Reduce the complexity.
➤ Developer can easily remember that overloaded method by passing diffrent number or types of arguments.
➤ To increase code readability and reusability.
➤ To avoid creating multiple method names for similar operations.
➤ To handle different types of input with the same method name.
➤ Method selection happens at compile time, making the code more efficient.
method overloading is usefull for programer or not?
➤ yes.
Can we overload main() method? or can we defined multiple main method in our class?
➤ yes.

Example (Method Overloading):

class Calculator {
    int add(int a, int b) {
        return a + b;
    }

    int add(int a, int b, int c) {
        return a + b + c;
    }

    double add(double a, double b) {
        return a + b;
    }

    public static void main(String[] args) {
        Calculator calc = new Calculator();
        System.out.println("add(2, 3) = " + calc.add(2, 3));
        System.out.println("add(1, 2, 3) = " + calc.add(1, 2, 3));
        System.out.println("add(2.5, 3.5) = " + calc.add(2.5, 3.5));
    }
}
    

➤ Method Overriding (Runtime Polymorphism)

Redefining base class method in derived class having same name ,same return type, same number of or of arguments is called as method overriding.

Example (Method Overriding):

class Animal {
    void sound() {
        System.out.println("Animal makes sound");
    }
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("Dog barks");
    }
}

class Cat extends Animal {
    @Override
    void sound() {
        System.out.println("Cat meows");
    }
}

class Main {
    public static void main(String[] args) {
        Animal a1 = new Dog();
        Animal a2 = new Cat();

        a1.sound();  // Output: Dog barks
        a2.sound();  // Output: Cat meows
    }
}
    
Why we use Method Overriding?
➤ To provide specific implementation of a method already defined in the parent class.
➤ Enables run-time polymorphism (dynamic method dispatch).
➤ Increases flexibility and extendability in code.
➤ Helps to achieve loose coupling using inheritance and method overriding.
Rules of Method Overriding in Java:
➤ The method must have the same name, return type, and parameters as in the parent class.
➤ The method must be inherited from the superclass.
➤ In overriding access modifier of the overrided method should be equal or greater than access modifire of base class method.
➤ Only inherited methods can be overridden; constructors and private methods cannot be overridden.
➤ The overriding method can throw fewer or no checked exceptions.
➤ The method must not be declared as final or static.
➤ Use @Override annotation to ensure proper overriding.
Without inheritance method overriding is not possible .

Difference Between Method Overloading and Method Overriding:

Feature Method Overloading Method Overriding
Definition Same method name with different parameters Same method name and parameters in parent and child class
Polymorphism Type Compile-time Runtime
Class Relation Same class Subclass and superclass
Return Type Can be same or different Must be same or covariant
Inheritance Required No Yes

➤ super Keyword in Java

1. Super keyword is used to represent parent class member , it can be data members,member functions and constructors.
2. Super keyword always use in child class.
3. Super keyword always used in inheritance concept.
4. Super keyword is used always chield class.

Uses of super keyword:
➤ To call parent class constructor.
➤ To call parent class method.
➤ To access parent class data members (fields) when they are hidden by child class.

Example 1: Calling Parent Class Constructor

class Animal {
    Animal() {
        System.out.println("Animal constructor called");
    }
}

class Dog extends Animal {
    Dog() {
        super();  // Calls parent class constructor
        System.out.println("Dog constructor called");
    }

    public static void main(String[] args) {
        Dog d = new Dog();
    }
}
    

Output:

Animal constructor called
Dog constructor called

Example 2: Accessing Parent Class Method and Variable

class Animal {
    String type = "Animal";

    void show() {
        System.out.println("Animal sound");
    }
}

class Dog extends Animal {
    String type = "Dog";

    void display() {
        System.out.println("Type: " + super.type);  // Access parent variable
        super.show(); // Call parent method
    }

    public static void main(String[] args) {
        Dog d = new Dog();
        d.display();
    }
}
    

Output:

Type: Animal
Animal sound
Notes:
➤ When ever we create object of parent class then only parent class constructor will executed.
➤ When ever we create object of chield class then first parent class default constructor will executed and after that chield class constructor will execute.
Why parent constructor is executed first?
➤ To ensure that all inherited fields and methods from the parent class are properly initialized before the child class adds its own features.
➤ Java maintains a top-down initialization order to avoid uninitialized or broken inheritance chains.
➤ This ensures program stability and logical object construction.

Example:

class Parent {
    Parent() {
        System.out.println("Parent constructor called");
    }
}

class Child extends Parent {
   
    Child() 
    {
        super();  // ye enternaly laga hota hai jiki vjah se parent class ka default constructor  execute hojata hai.
        System.out.println("Child constructor called");
    }

    public static void main(String[] args) {
        Child c = new Child();
    }
}
    

Output:

Parent constructor called
Child constructor called

4. Abstraction

Abstraction is the process of hiding internal implementation but providing services is called as abstraction.

Example (Abstract Class):

abstract class Shape {
    abstract void draw();  // abstract method
    
    void display() {
        System.out.println("Displaying shape");
    }
}

class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing circle");
    }
}

Advanced OOP Concepts in Java

Abstract Class

An abstract class in Java is a class that:

  1. Cannot be instantiated directly (cannot create objects)
  2. May contain both abstract methods (without implementation) and concrete methods (with implementation)
  3. Serves as a base template for subclasses to extend
  4. Is declared using the abstract keyword

Rules of Abstract Class

  1. By using abstract keyword we can define method and abstract class .
  2. An abstrct class can contain all members of class means it contain data-members regular method(non-abstract method),constructor,abstract method.
  3. Abstract class is incomplete class .
  4. Abstract class is jus opposite final class.
  5. An Abstract class can contain zero number of abstract method.
  6. Lf a class contain atleast one bstract method then compulsary class should be declare as abstract otherwise will get compile time error.

Key Characteristics:

Syntax Example:

abstract class Animal {
    // Abstract method (no implementation)
    public abstract void makeSound();
    
    // Concrete method
    public void eat() {
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Bark bark");
    }
}

When to Use Abstract Classes:

Interview Tip:

Contrast with interfaces: "Abstract classes are used when we need to provide common base functionality, while interfaces are better for defining contracts that can be implemented by unrelated classes."

Abstract Method

If a method just declare note a define is called as abstract method.
A method which does not have any body (implementation part ) is called as abstract method and class containing such type of method is called as abstract class

Interface

Interfaces are just like a abstract class but in abstract class can contain abstract method(without body) as well as concreat methods (with body) both, but in interface we just declare only abstract methods not concreat methods before java 8 .

java 8 se pahle interface ke under concreate method aur statick method nahi bana sakte hai lekin java 8 kebad concreate method aur static method bana sakte hai . tatha java 9 se private method bhi interface ke under banane ka concept agaya hai.

why we use interface

Rules for define by using interface

Abstract Classes vs Interfaces

Feature Abstract Class Interface
Keyword abstract interface
Methods Can have both abstract and concrete methods Can have abstract methods (Java 7), default and static methods (Java 8+)
Fields Can have instance variables Fields are public static final only
Inheritance Supports single inheritance Supports multiple inheritance
Constructor Can have a constructor Cannot have a constructor
When to Use When classes share common behavior When unrelated classes need to follow a contract

Example:

// Abstract Class Example
abstract class Animal {
    abstract void sound();
    void eat() {
        System.out.println("Eating...");
    }
}

class Dog extends Animal {
    void sound() {
        System.out.println("Barks");
    }
}

// Interface Example
interface Flyable {
    void fly();
}

class Bird implements Flyable {
    public void fly() {
        System.out.println("Flying...");
    }
}
    

Marker Interfaces

A marker interface is an interface with no methods or fields. It provides metadata to the JVM or other code. Common marker interfaces include:

Example:

import java.io.Serializable;

class Employee implements Serializable {
    int id;
    String name;
}
    

Java Enums

An enum is a special "class" that represents a group of constants (unchangeable variables, like final variables).
To create an enum, use the enum keyword (instead of class or interface), and separate the constants with a comma. Note that they should be in uppercase letters

Example:

          enum Level {
               LOW,
               MEDIUM,
               HIGH
             }
          You can access enum constants with the dot syntax:

          Level myVar = Level.MEDIUM;
          Enum is short for "enumerations", which means "specifically listed".

Difference between Enums and Classes

              An enum can, just like a class, have attributes and methods. The only difference is that enum constants are public, static and final (unchangeable - cannot be overridden).
              
              An enum cannot be used to create objects, and it cannot extend other classes (but it can implement interfaces).
              
              Why And When To Use Enums?
              Use enums when you have values that you know aren't going to change, like month days, days, colors, deck of cards, etc.
        

Example:

            public class Main {
              enum Level {
                LOW,
                MEDIUM,
                HIGH
              }
            
              public static void main(String[] args) {
                Level myVar = Level.MEDIUM; 
                System.out.println(myVar);
              }
            }
    

Java User Input (Scanner)

        The Scanner class is used to get user input, and it is found in the java.util package.

        To use the Scanner class, create an object of the class and use any of the available methods found in the Scanner class documentation. In our example, we will use the nextLine() method, which is used to read Strings
    

Example:

             import java.util.Scanner;  // Import the Scanner class

             class Main {
               public static void main(String[] args) {
                 Scanner myObj = new Scanner(System.in);  // Create a Scanner object
                 System.out.println("Enter username");
             
                 String userName = myObj.nextLine();  // Read user input
                 System.out.println("Username is: " + userName);  // Output user input
               }
             }
       

Input Types

    In the example above, we used the nextLine() method, which is used to read Strings. To read other types, look at the table below
   
Method Description
nextBoolean() Reads a boolean value from the user
nextByte() Reads a byte value from the user
nextDouble() Reads a double value from the user
nextFloat() Reads a float value from the user
nextInt() Reads a int value from the user
nextLine() Reads a String value from the user
nextLong() Reads a long value from the user
nextShort() Reads a short value from the user

Example:

              import java.util.Scanner;

              class Main {
                public static void main(String[] args) {
                  Scanner myObj = new Scanner(System.in);
              
                  System.out.println("Enter name, age and salary:");
              
                  // String input
                  String name = myObj.nextLine();
              
                  // Numerical input
                  int age = myObj.nextInt();
                  double salary = myObj.nextDouble();
              
                  // Output input by user
                  System.out.println("Name: " + name);
                  System.out.println("Age: " + age);
                  System.out.println("Salary: " + salary);
                }
              }
   
Note:
If you enter wrong input (e.g. text in a numerical input), you will get an exception/error message (like "InputMismatchException").

Java Date and Time

 Java does not have a built-in Date class, but we can import the java.time package to work with the date and time API. The package includes many date and time classes.
 For example
class Description
LocalDate Represents a date (year, month, day (yyyy-MM-dd))
LocalTime Represents a time (hour, minute, second and nanoseconds (HH-mm-ss-ns))
LocalDateTime Represents both a date and a time (yyyy-MM-dd-HH-mm-ss-ns)
DateTimeFormatter Formatter for displaying and parsing date-time objects
   Display Current Date
   To display the current date, import the java.time.LocalDate class, and use its now() method:
   

Example:

           import java.time.LocalDate; // import the LocalDate class

public class Main {
  public static void main(String[] args) {
    LocalDate myObj = LocalDate.now(); // Create a date object
    System.out.println(myObj); // Display the current date
  }
}
Display Current Time
To display the current time (hour, minute, second, and nanoseconds), import the java.time.LocalTime class, and use its now() method:

Example:

          import java.time.LocalTime; // import the LocalTime class

public class Main {
  public static void main(String[] args) {
    LocalTime myObj = LocalTime.now();
    System.out.println(myObj);
  }
}
Display Current Date and Time
To display the current date and time, import the java.time.LocalDateTime class, and use its now() method:

Example:

         import java.time.LocalDateTime; // import the LocalDateTime class

public class Main {
  public static void main(String[] args) {
    LocalDateTime myObj = LocalDateTime.now();
    System.out.println(myObj);
  }
}

What is Debugging?

Debugging is the process of identifying and fixing errors or bugs in your code.

What is a Regular Expression(RegEx)?

      
A regular expression is a sequence of characters that forms a search pattern. When you search for data in a text, you can use this search pattern to describe what you are searching for.

A regular expression can be a single character, or a more complicated pattern.

Regular expressions can be used to perform all types of text search and text replace operations.

Java does not have a built-in Regular Expression class, but we can import the java.util.regex package to work with regular expressions. The package includes the following classes:

Pattern Class - Defines a pattern (to be used in a search)
Matcher Class - Used to search for the pattern
PatternSyntaxException Class - Indicates syntax error in a regular expression pattern

Example:

        import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
  public static void main(String[] args) {
    Pattern pattern = Pattern.compile("w3schools", Pattern.CASE_INSENSITIVE);
    Matcher matcher = pattern.matcher("Visit W3Schools!");
    boolean matchFound = matcher.find();
    if(matchFound) {
      System.out.println("Match found");
    } else {
      System.out.println("Match not found");
    }
  }
}
// Outputs Match found


Composition vs Aggregation

Both composition and aggregation represent "has-a" relationships in OOP but differ in ownership and lifecycle.

Aspect Composition Aggregation
Relationship Strong Weak
Object Lifecycle Child object cannot exist without parent Child object can exist independently
Example House has-a Room (Room doesn't exist without House) Department has-a Teacher (Teacher exists without Department)

Composition Example:

class Engine {
    void start() {
        System.out.println("Engine started");
    }
}

class Car {
    private Engine engine = new Engine(); // composition

    void drive() {
        engine.start();
        System.out.println("Car is moving");
    }
}
    

Aggregation Example:

class Teacher {
    String name;
    Teacher(String name) {
        this.name = name;
    }
}

class Department {
    Teacher teacher; // aggregation
    Department(Teacher teacher) {
        this.teacher = teacher;
    }
}
    

Exception Handling in Java

Exception is an event that disrupts the normal flow of the program.

Common Exception Types in Java

  • Exception: Base class for all checked exceptions
  • NullPointerException: Thrown when trying to access a method or property on a null object
  • ArrayIndexOutOfBoundsException: Thrown when accessing an array element with an invalid index
  • ArithmeticException: Thrown when an illegal arithmetic operation like division by zero is performed
  • IOException: Thrown during input/output operations
  • NumberFormatException: Thrown when a string cannot be converted to a valid number format

Exception Handling Keywords in Java

  1. try: The try block contains the code that may throw an exception
  2. catch: The catch block is used to handle the exception
  3. finally: The finally block always executes, regardless of whether an exception occurred or not
  4. throw: The throw keyword is used to explicitly throw an exception

Example:

public class ExceptionExample {
    public static void main(String[] args) {
        try {
            int a = 10;
            int b = 0;
            int result = a / b; // This will throw ArithmeticException
        } catch (ArithmeticException ex) {
            System.out.println("Cannot divide by zero");
            System.out.println(ex.getMessage());
        } catch (Exception ex) {
            System.out.println("An error occurred");
            System.out.println(ex.getMessage());
        } finally {
            System.out.println("This block always executes");
        }
    }
}
    

Lambda Expression in Java

Lambda expressions were introduced in Java 8. They provide a clear and concise way to represent an anonymous function (a function without a name).

Syntax:

(parameters) -> { expression or block of code }

Use Cases:

Functional Interface:

Lambda expressions can only be used with functional interfaces (interfaces with only one abstract method), like: Runnable, Comparator, ActionListener, or custom interfaces.

Example 1: Runnable using Lambda

Runnable r = () -> System.out.println("Running via Lambda");
new Thread(r).start();
    

Example 2: Custom Functional Interface

@FunctionalInterface
interface MyFunction {
    void sayHello();
}

public class Main {
    public static void main(String[] args) {
        MyFunction mf = () -> System.out.println("Hello from Lambda!");
        mf.sayHello();
    }
}
    

Key Points:

1. String (Immutable)

A String is an immutable group of characters represented in double quotes.
string class is available in java.lang package .it is final class means we can not extends this class.

Key Points:
➤ String is stored in the **String Constant Pool**.
➤ Every operation like concat(), replace() returns a new String.
➤ It is **thread-safe** because it's immutable.
➤ Good for fixed and read-only values. ➤ string data store in array form in this reason string is immutable .
string mainipulation classes:
➤ java.lang.String(final class).
➤ java.lang.StringBuffer(final class).
➤ java.lang.StringBuilder.
➤ java.util.StringTokenizer.

Example:

String s1 = "Hello";
String s2 = s1.concat(" World");
System.out.println(s1); // Hello
System.out.println(s2); // Hello World
    

2. StringBuilder (Mutable, Not Thread-Safe)

StringBuilder is a mutable class used to modify strings without creating new objects. It is not synchronized, so it is not thread-safe but faster.

Key Points:
➤ Can change content using append(), insert(), delete(), etc.
➤ High performance for single-threaded environments.
➤ Not thread-safe.

Example:

StringBuilder sb = new StringBuilder("Hello");
sb.append(" Java");
System.out.println(sb); // Hello Java
    

3. StringBuffer (Mutable, Thread-Safe)

StringBuffer is similar to StringBuilder, but it is synchronized. It is thread-safe and used in multi-threaded environments where string content is frequently modified.

Key Points:
➤ Methods like append() and insert() are synchronized.
➤ Suitable for multi-threaded applications.
➤ Slightly slower than StringBuilder due to synchronization.

Example:

StringBuffer sbf = new StringBuffer("Hello");
sbf.append(" Java");
System.out.println(sbf); // Hello Java
    

Difference Between String and StringBuffer:

Feature String StringBuffer
Mutability Immutable Mutable
Thread Safety Thread-safe by immutability Thread-safe (synchronized)
Performance Slower (for changes) Faster than String (for changes)
Memory Usage More (creates new objects) Less (same object is modified)
Use Case Fixed or constant text Text modified by multiple threads

Difference Between String and StringBuffer:

Feature String StringBuffer
Mutability Immutable (value can't be changed once created) Mutable (value can be changed)
Thread Safety Thread-safe due to immutability Thread-safe (methods are synchronized)
Performance Slower for modifications (creates new object) Faster than String for modifications
Memory Usage Consumes more memory (new object for every change) Efficient memory usage (modifies existing object)
Use Case When text doesn't change often When string needs to be modified by multiple threads
Method Support Uses + operator or concat() method Provides append(), insert(), delete() etc.

Difference Between StringBuilder and StringBuffer:

Feature StringBuilder StringBuffer
Mutability Mutable Mutable
Thread Safety Not thread-safe Thread-safe (synchronized methods)
Performance Faster (no overhead of synchronization) Slower than StringBuilder (due to synchronization)
Usage Used in single-threaded environments Used in multi-threaded environments
Introduced in Java 1.5 Java 1.0
Package java.lang java.lang

Java Math Class

The Java Math class has many methods that allows you to perform mathematical tasks on numbers.

Math.max(x,y)

The Math.max(x,y) method can be used to find the highest value of x and y

Example:

            Math.max(5, 10);
           

Math.min(x,y)

The Math.min(x,y) method can be used to find the lowest value of x and y

Example:

     Math.min(5, 10);
    

Math.sqrt(x)

The Math.sqrt(x) method returns the square root of x:

Example:

     Math.sqrt(64);
    

Math.abs(x)

The Math.abs(x) method returns the absolute (positive) value of x

Example:

     Math.abs(-4.7);
    

Random Numbers

Math.random() returns a random number between 0.0 (inclusive), and 1.0 (exclusive)

Example:

 Math.random();

Java Booleans

Very often, in programming, you will need a data type that can only have one of two values, like:
1. YES / NO
2. ON / OFF
3. TRUE / FALSE
For this, Java has a boolean data type, which can store true or false values.

Boolean Values

A boolean type is declared with the boolean keyword and can only take the values true or false

Example:

                boolean isJavaFun = true;
                boolean isFishTasty = false;
                System.out.println(isJavaFun);     // Outputs true
                System.out.println(isFishTasty);   // Outputs false
           

Multithreading

If multiple Threads are running simultaneously in the same program, it is called Multi Threading.

Thread

A thread is a class that present in java.lang package . it is predefine class in java .

  • Lightweight sub-process that runs independently
  • Shares the same memory space as other threads in the same process
  • Enables concurrent execution of tasks
  • Managed by the JVM and OS scheduler

Notes

  • thread ka main kam execution time ko kam karna hai aur performance ko fast karna hai.
  • is per jo code run karana hota hai use run method per rakhte hai tatha class ka object create karke thread class ki start method ko call karte hai kyu ki start method internally thread class ki run method ko call karti hai .yaha per run method ko direct call nahi karte hai kyu ki thread create karne ka kam start method ka hota hai . yadi direct run method ko call karenge to thread create nahi hoga esiliye start method ko call karte hai.
  • jab hum apne program me koi thread create nahi karte hai . tab JVM internally ak thread hamare program me create karta hai jise main thread kahte hai.
  • thread ka name changekarne keliye setName() ka use karte hai thread ka name pata karne ke liye getName() ka use hota hai. isi tarh id set karnekeliye setID() aur get keliye getId() ka use hota hai ham jo thread banate hai uska name zero se start hota hai.

Main Uses of Threads

  1. Improving application performance through parallel execution
  2. Responsive UI (keeping interface active during background tasks)
  3. Asynchronous operations (network calls, file I/O)
  4. Server applications (handling multiple clients simultaneously)
  5. Scheduled tasks (timers, periodic operations)

Thread.sleep() Method

The Thread.sleep() method:

  • Pauses the current thread's execution for a specified time
  • Static method - affects only the current thread
  • Throws InterruptedException (checked exception)
  • Used for delays, polling, or simulating processing time

Thread.sleep() Example

public class SleepExample {
    public static void main(String[] args) {
        System.out.println("Starting countdown...");
        
        try {
            for (int i = 5; i > 0; i--) {
                System.out.println(i);
                // Pause for 1 second (1000 milliseconds)
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            System.err.println("Thread was interrupted");
        }
        
        System.out.println("Liftoff!");
    }
}

Output:

Starting countdown...
5
4
3
2
1
Liftoff!

Important Notes

  • sleep() doesn't release locks it holds
  • Actual sleep duration depends on system timers and schedulers
  • Always handle InterruptedException properly
  • For precise timing, consider java.util.concurrent classes

Alternative to Thread.sleep()

// Using TimeUnit (more readable)
TimeUnit.SECONDS.sleep(1);

// Using ScheduledExecutorService (better for production)
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.schedule(() -> {
    System.out.println("Delayed task");
}, 2, TimeUnit.SECONDS);

Creating Threads

  1. Extending Thread class:
    class MyThread extends Thread {
        public void run() {
            System.out.println("Thread is running");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            MyThread t1 = new MyThread();
            t1.start();
        }
    }
  2. Implementing Runnable interface:
    class MyRunnable implements Runnable {
        public void run() {
            System.out.println("Thread is running");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Thread t1 = new Thread(new MyRunnable());
            t1.start();
        }
    }

File Handling in Java

File handling in Java is done using classes from the java.io and java.nio.file packages. It allows you to create, read, write, and delete files and directories.

Common Classes Used:

1. Creating a File

Example:

import java.io.File;
import java.io.IOException;

public class CreateFileExample {
    public static void main(String[] args) {
        try {
            File file = new File("example.txt");
            if (file.createNewFile()) {
                System.out.println("File created: " + file.getName());
            } else {
                System.out.println("File already exists.");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
    

2. Writing to a File

Example:

import java.io.FileWriter;
import java.io.IOException;

public class WriteFileExample {
    public static void main(String[] args) {
        try {
            FileWriter writer = new FileWriter("example.txt");
            writer.write("Hello, Java File Handling!");
            writer.close();
            System.out.println("Successfully written to the file.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
    

3. Reading from a File

Example using BufferedReader:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ReadFileExample {
    public static void main(String[] args) {
        try {
            BufferedReader reader = new BufferedReader(new FileReader("example.txt"));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
    

4. Deleting a File

Example:

import java.io.File;

public class DeleteFileExample {
    public static void main(String[] args) {
        File file = new File("example.txt");
        if (file.delete()) {
            System.out.println("Deleted the file: " + file.getName());
        } else {
            System.out.println("Failed to delete the file.");
        }
    }
}
    

5. Reading File with Scanner

Example:

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class ScannerReadFile {
    public static void main(String[] args) {
        try {
            File file = new File("example.txt");
            Scanner scanner = new Scanner(file);
            while (scanner.hasNextLine()) {
                String data = scanner.nextLine();
                System.out.println(data);
            }
            scanner.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}
    

6. Using Files (java.nio.file)

Example: Reading all lines

import java.nio.file.*;
import java.io.IOException;
import java.util.List;

public class NioReadExample {
    public static void main(String[] args) {
        try {
            List<String> lines = Files.readAllLines(Paths.get("example.txt"));
            for (String line : lines) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
    

Arrays in Java

An array is a linear data structure that stores elements of the same data type in contiguous memory locations under a single variable name, with each element accessible via an index.

// Syntax
dataType[] arrayName = new dataType[size];

Advantages of Arrays

Disadvantages of Arrays

Two-Dimensional Arrays

Definition

A two-dimensional array is an array of arrays that represents a table/matrix with rows and columns.

// Declaration
int[][] matrix = new int[3][4]; // 3 rows, 4 columns

// Literal initialization
int[][] chessBoard = {
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1}
};

Common Operations

// Accessing elements
int value = matrix[1][2]; // 2nd row, 3rd column

// Traversing
for(int i=0; i
    

Multi-Dimensional Arrays

Definition

Arrays with more than two dimensions (3D, 4D etc.) used for complex data structures like tensors or spatial data.

// 3D Array
int[][][] cube = new int[3][3][3]; // 3x3x3 cube

// Initialization
int[][][] rgbImage = {
    {{255,0,0}, {0,255,0}, {0,0,255}}, // Red, Green, Blue
    {{255,255,0}, {255,0,255}, {0,255,255}}, // Yellow, Magenta, Cyan
    {{255,255,255}, {0,0,0}, {128,128,128}}  // White, Black, Gray
};

Practical Example

// Accessing 3D array
int pixel = rgbImage[0][1][2]; // First layer, second row, third column

// Traversing 3D array
for(int i=0; i
    

When to Use Multi-Dimensional Arrays

Performance Considerations

Wrapper Classes in Java

What are Wrapper Classes?

Wrapper classes are object representations of primitive data types in Java. They "wrap" primitive values into objects.

Primitive Type Wrapper Class
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

Boxing and Unboxing

Boxing (Autoboxing)

Automatic conversion of primitive types to their corresponding wrapper class objects.

// Manual boxing (pre-Java 5)
Integer num = Integer.valueOf(10);

// Automatic boxing (Java 5+)
Integer num = 10;  // primitive int automatically converted to Integer object

Unboxing

Automatic conversion of wrapper class objects back to primitive types.

// Manual unboxing (pre-Java 5)
int n = num.intValue();

// Automatic unboxing (Java 5+)
int n = num;  // Integer object automatically converted to primitive int

Boxing vs Unboxing

Operation Direction Example
Boxing Primitive → Wrapper Integer x = 5;
Unboxing Wrapper → Primitive int y = x;

When to Use Wrapper Classes

Practical Example

import java.util.ArrayList;

public class WrapperExample {
    public static void main(String[] args) {
        // Boxing
        ArrayList<Integer> numbers = new ArrayList<>();
        numbers.add(10);  // Autoboxing
        
        // Unboxing
        int first = numbers.get(0);  // Autounboxing
        
        // Using wrapper class methods
        String binary = Integer.toBinaryString(10);
        System.out.println("Binary: " + binary);
    }
}

Performance Considerations

Data Structures in Java

Core Java Data Structures

Java provides a comprehensive collections framework in the java.util package for storing and manipulating groups of objects.

1. Primitive Data Types

Type Size Range Wrapper Class Example
byte 1 byte -128 to 127 Byte byte b = 100;
short 2 bytes -32,768 to 32,767 Short short s = 5000;
int 4 bytes -2³¹ to 2³¹-1 Integer int i = 100000;
long 8 bytes -2⁶³ to 2⁶³-1 Long long l = 15000000000L;
float 4 bytes ±1.4E-45 to ±3.4E+38 Float float f = 5.75f;
double 8 bytes ±4.9E-324 to ±1.7E+308 Double double d = 19.99d;
boolean 1 bit true/false Boolean boolean flag = true;
char 2 bytes '\u0000' to '\uffff' Character char c = 'A';

2. Linear Data Structures

a. Arrays

Fixed-size sequential collection of elements of the same type

Single-dimensional Array:
// Declaration and initialization
int[] numbers = new int[5]; 
int[] numbers = {1, 2, 3, 4, 5};

// Accessing elements
int first = numbers[0]; // 1
numbers[1] = 10; // Modify second element

// Length property
int size = numbers.length; // 5
        
Multi-dimensional Array:
// 2D array
int[][] matrix = new int[3][3];
int[][] matrix = {{1,2,3}, {4,5,6}, {7,8,9}};

// Accessing elements
int value = matrix[1][2]; // 6
        

b. ArrayList

Resizable array implementation of the List interface

  • Dynamic resizing
  • Permits duplicate elements
  • Maintains insertion order
  • Random access in O(1) time
  • Insertion/deletion at end is O(1)
  • Insertion/deletion in middle is O(n)
import java.util.ArrayList;

ArrayList fruits = new ArrayList<>();

// Adding elements
fruits.add("Apple");
fruits.add("Banana");
fruits.add(1, "Orange"); // Insert at index 1

// Accessing elements
String first = fruits.get(0); // "Apple"

// Removing elements
fruits.remove(2); // Remove by index
fruits.remove("Banana"); // Remove by value

// Size
int count = fruits.size();

// Iteration
for (String fruit : fruits) {
    System.out.println(fruit);
}
        

c. LinkedList

Doubly-linked list implementation of List and Deque interfaces

  • Elements are linked using pointers
  • Faster insertions/deletions than ArrayList
  • Slower random access than ArrayList
  • Extra memory for pointers
  • Can be used as stack, queue, or deque
import java.util.LinkedList;

LinkedList numbers = new LinkedList<>();

// Adding elements
numbers.add(10);
numbers.addFirst(5); // Add to beginning
numbers.addLast(20); // Add to end

// Accessing elements
int first = numbers.getFirst(); // 5
int last = numbers.getLast(); // 20

// Removing elements
numbers.removeFirst(); // Remove first
numbers.removeLast(); // Remove last

// Size
int size = numbers.size();

// As Queue
numbers.offer(30); // Add to end
int head = numbers.poll(); // Remove from head
        

d. Stack

LIFO (Last-In-First-Out) structure extending Vector

  • Legacy class (new code should use Deque)
  • Synchronized (thread-safe)
  • Common operations: push, pop, peek
import java.util.Stack;

Stack stack = new Stack<>();

// Pushing elements
stack.push(10);
stack.push(20);
stack.push(30);

// Popping elements
int top = stack.pop(); // 30

// Peeking
int next = stack.peek(); // 20

// Checking empty
boolean isEmpty = stack.empty();

// Searching
int position = stack.search(10); // 1-based position
        

e. Queue (Interface)

FIFO (First-In-First-Out) collection

  • Implemented by LinkedList, PriorityQueue
  • Common operations: add, offer, remove, poll, peek
import java.util.Queue;
import java.util.LinkedList;

Queue queue = new LinkedList<>();

// Adding elements
queue.add("First");
queue.offer("Second"); // Alternative to add

// Removing elements
String head = queue.remove(); // "First"
String next = queue.poll(); // "Second"

// Inspecting
String peek = queue.peek(); // null if empty
        

3. Non-linear Data Structures

a. HashMap

Hash table based implementation of Map interface

  • Stores key-value pairs
  • No duplicate keys
  • Permits one null key and multiple null values
  • Average O(1) time for basic operations
  • Unordered collection
import java.util.HashMap;

HashMap ageMap = new HashMap<>();

// Adding entries
ageMap.put("Alice", 25);
ageMap.put("Bob", 30);
ageMap.put(null, 0); // Null key

// Accessing values
int aliceAge = ageMap.get("Alice"); // 25
int unknownAge = ageMap.getOrDefault("Charlie", -1); // -1

// Checking existence
boolean hasAlice = ageMap.containsKey("Alice"); // true

// Removing entries
ageMap.remove("Bob");

// Iterating
for (Map.Entry entry : ageMap.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

// Size
int size = ageMap.size();
        

b. TreeMap

Red-Black tree based NavigableMap implementation

  • Maintains keys in sorted order
  • O(log n) time for basic operations
  • No null keys if natural ordering used
  • Implements SortedMap and NavigableMap
import java.util.TreeMap;

TreeMap sortedMap = new TreeMap<>();

// Adding entries
sortedMap.put("Orange", 2);
sortedMap.put("Apple", 5);
sortedMap.put("Banana", 3);

// Entries are stored in sorted order
System.out.println(sortedMap); // {Apple=5, Banana=3, Orange=2}

// First and last entries
String firstKey = sortedMap.firstKey(); // "Apple"
String lastKey = sortedMap.lastKey(); // "Orange"

// Range views
SortedMap subMap = sortedMap.subMap("Apple", "Orange");
        

c. HashSet

Hash table based Set implementation

  • No duplicate elements
  • Permits one null element
  • Unordered collection
  • Average O(1) time for basic operations
  • Backed by HashMap
import java.util.HashSet;

Set uniqueNames = new HashSet<>();

// Adding elements
uniqueNames.add("Alice");
uniqueNames.add("Bob");
uniqueNames.add("Alice"); // Duplicate ignored

// Checking membership
boolean hasAlice = uniqueNames.contains("Alice"); // true

// Size
int size = uniqueNames.size(); // 2

// Iterating
for (String name : uniqueNames) {
    System.out.println(name);
}

// Removing elements
uniqueNames.remove("Bob");
        

d. TreeSet

Red-Black tree based NavigableSet implementation

  • Elements stored in sorted order
  • O(log n) time for basic operations
  • No duplicate elements
  • No null elements if natural ordering used
import java.util.TreeSet;

Set sortedNumbers = new TreeSet<>();

// Adding elements
sortedNumbers.add(5);
sortedNumbers.add(2);
sortedNumbers.add(8);

// Elements are stored sorted
System.out.println(sortedNumbers); // [2, 5, 8]

// First and last elements
int first = ((TreeSet) sortedNumbers).first(); // 2
int last = ((TreeSet) sortedNumbers).last(); // 8

// Range views
Set subset = ((TreeSet) sortedNumbers).headSet(5);
        

e. PriorityQueue

Heap-based priority queue

  • Elements ordered according to natural ordering or Comparator
  • Head is least element (min-heap)
  • O(log n) time for enqueue/dequeue
  • O(1) time for peek
  • Not thread-safe
import java.util.PriorityQueue;

PriorityQueue minHeap = new PriorityQueue<>();

// Adding elements
minHeap.add(10);
minHeap.add(5);
minHeap.add(20);

// Removing elements (always removes smallest)
int min = minHeap.poll(); // 5
int next = minHeap.peek(); // 10

// Custom ordering
PriorityQueue maxHeap = new PriorityQueue<>(Collections.reverseOrder());
maxHeap.add(10);
maxHeap.add(5);
maxHeap.add(20);
int max = maxHeap.poll(); // 20
        

4. Legacy Collections

a. Vector

Synchronized dynamic array

  • Similar to ArrayList but synchronized
  • Thread-safe
  • Slower than ArrayList
  • Legacy class (new code should use ArrayList)
import java.util.Vector;

Vector vec = new Vector<>();

// Adding elements
vec.add("Element1");
vec.addElement("Element2"); // Legacy method

// Accessing elements
String first = vec.get(0);
String last = vec.lastElement();

// Size
int size = vec.size();
int capacity = vec.capacity(); // Current capacity
        

b. Hashtable

Synchronized hash table

  • Similar to HashMap but synchronized
  • Thread-safe
  • No null keys or values
  • Legacy class (new code should use HashMap or ConcurrentHashMap)
import java.util.Hashtable;

Hashtable table = new Hashtable<>();

// Adding entries
table.put("One", 1);
table.put("Two", 2);

// Accessing values
int value = table.get("One");

// Enumeration (legacy iteration)
Enumeration keys = table.keys();
while (keys.hasMoreElements()) {
    String key = keys.nextElement();
    System.out.println(key + ": " + table.get(key));
}
        

5. Concurrent Collections

a. ConcurrentHashMap

Thread-safe hash table with high concurrency

  • Thread-safe alternative to HashMap
  • Better performance than Hashtable
  • Allows concurrent read and limited concurrent writes
  • No lock on entire table
import java.util.concurrent.ConcurrentHashMap;

ConcurrentHashMap concurrentMap = new ConcurrentHashMap<>();

// Atomic operations
concurrentMap.putIfAbsent("Key", 1);
concurrentMap.computeIfPresent("Key", (k, v) -> v + 1);

// Safe iteration
for (Map.Entry entry : concurrentMap.entrySet()) {
    // Iteration is thread-safe
}
        

b. CopyOnWriteArrayList

Thread-safe variant of ArrayList

  • All mutative operations create new copy of array
  • Thread-safe for iteration
  • Useful when traversals vastly outnumber mutations
  • Expensive modification operations
import java.util.concurrent.CopyOnWriteArrayList;

CopyOnWriteArrayList safeList = new CopyOnWriteArrayList<>();

// Thread-safe operations
safeList.add("Item1");
safeList.addIfAbsent("Item2");

// Thread-safe iteration
for (String item : safeList) {
    // No ConcurrentModificationException
}
        

6. Performance Comparison

Data Structure Access Search Insertion Deletion Notes
Array O(1) O(n) O(n) O(n) Fixed size
ArrayList O(1) O(n) O(1) amortized (end)
O(n) (middle)
O(n) Dynamic resizing
LinkedList O(n) O(n) O(1) O(1) Good for frequent insertions/deletions
HashSet/HashMap O(1) O(1) O(1) O(1) Average case, depends on hash function
TreeSet/TreeMap O(log n) O(log n) O(log n) O(log n) Elements stored in sorted order
PriorityQueue O(1) peek O(n) O(log n) O(log n) Heap implementation

7. Choosing the Right Data Structure

a. Based on Access Patterns

b. Based on Ordering Needs

c. Based on Thread Safety

8. Java Collections Framework Hierarchy

Iterable (Interface)
        Collection (Interface)
        List (Interface)
            ArrayList (Class)
            LinkedList (Class)
            Vector (Class) [Legacy]
                Stack (Class) [Legacy]
        Set (Interface)
            HashSet (Class)
            LinkedHashSet (Class)
            TreeSet (Class)
        Queue (Interface)
            PriorityQueue (Class)
            LinkedList (Class)
            ArrayDeque (Class)
        Map (Interface)
        HashMap (Class)
        LinkedHashMap (Class)
        TreeMap (Class)
        Hashtable (Class) [Legacy]
    

9. Best Practices

10. Common Utility Methods

Collections Class Methods

// Sorting
Collections.sort(list);
Collections.sort(list, comparator);

// Searching
int index = Collections.binarySearch(sortedList, key);

// Synchronization
List syncList = Collections.synchronizedList(list);

// Immutable views
List unmodifiable = Collections.unmodifiableList(list);

// Empty collections
List empty = Collections.emptyList();

// Singleton
Set single = Collections.singleton("Item");

// Frequency
int count = Collections.frequency(list, "Item");
    

Arrays Class Methods

// Sorting
Arrays.sort(array);
Arrays.sort(array, comparator);

// Searching
int index = Arrays.binarySearch(sortedArray, key);

// Filling
Arrays.fill(array, value);

// Copying
String[] copy = Arrays.copyOf(original, newLength);

// Comparison
boolean equal = Arrays.equals(array1, array2);

// String representation
String str = Arrays.toString(array);
    

Authentication

Definition: Authentication is the process of verifying a user's identity to confirm they are who they claim to be.

Authorization

Definition: Authorization determines what resources an authenticated user can access and what actions they can perform.

1. Authentication Methods

Basic Authentication

Simple username/password verification:

// Spring Security Configuration @Configuration @EnableWebSecurity public class BasicAuthConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .httpBasic(); // Enables Basic Auth } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user") .password("{noop}password") // {noop} for plain text (not recommended for production) .roles("USER"); } }

Form-Based Authentication

Traditional web login forms:

@Configuration public class FormLoginConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/login", "/public/**").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") // Custom login page .defaultSuccessUrl("/dashboard") .permitAll() .and() .logout() .logoutSuccessUrl("/login?logout") .permitAll(); } }

JWT Authentication

Token-based authentication for APIs:

// JWT Utility Class public class JwtUtil { private String secret = "your-256-bit-secret"; private long expirationMs = 86400000; // 24 hours public String generateToken(UserDetails userDetails) { return Jwts.builder() .setSubject(userDetails.getUsername()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + expirationMs)) .signWith(SignatureAlgorithm.HS256, secret) .compact(); } public boolean validateToken(String token, UserDetails userDetails) { final String username = extractUsername(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } private boolean isTokenExpired(String token) { return extractExpiration(token).before(new Date()); } }

2. Authorization Methods

Role-Based Access Control (RBAC)

@Configuration public class RbacConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasAnyRole("USER", "ADMIN") .antMatchers("/public/**").permitAll() .anyRequest().authenticated(); } }

Method-Level Security

@Service public class ProductService { @PreAuthorize("hasRole('ADMIN') or #product.owner == authentication.name") public void updateProduct(Product product) { // Update logic } @PostFilter("filterObject.owner == authentication.name") public List<Product> getUserProducts() { return productRepository.findAll(); } }

3. Complete Spring Security Example

@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; @Autowired private UserDetailsService jwtUserDetailsService; @Autowired private JwtRequestFilter jwtRequestFilter; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(jwtUserDetailsService) .passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/authenticate", "/register").permitAll() .anyRequest().authenticated() .and() .exceptionHandling() .authenticationEntryPoint(jwtAuthenticationEntryPoint) .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); } }

4. Password Security

// Always hash passwords with strong algorithms BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(12); // Hashing a password String rawPassword = "user123"; String encodedPassword = passwordEncoder.encode(rawPassword); // Verifying a password boolean matches = passwordEncoder.matches(rawPassword, encodedPassword);

5. Security Best Practices

Practice Implementation
Password Hashing Use BCrypt with strength 10-12
Session Management Use STATELESS for APIs, secure cookies for web
CSRF Protection Enable for stateful apps, disable for APIs
CORS Configuration Restrict origins, headers, and methods
Security Headers Add CSP, XSS protection, HSTS

Filters in Java

Definition: Filter is a server-side component that intercepts and processes HTTP requests and responses before they reach the servlet or after they leave it.

Basic Filter Structure

import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter("/*") // Applies to all requests public class BasicFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // Initialization code } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // Pre-processing code (before the servlet) chain.doFilter(request, response); // Pass to next filter or servlet // Post-processing code (after the servlet) } @Override public void destroy() { // Cleanup code } }

Common Filter Use Cases

1. Logging Filter

@WebFilter("/*") public class LoggingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { long startTime = System.currentTimeMillis(); HttpServletRequest httpRequest = (HttpServletRequest) request; System.out.println("Request received for: " + httpRequest.getRequestURI()); chain.doFilter(request, response); long duration = System.currentTimeMillis() - startTime; System.out.println("Request processed in " + duration + "ms"); } }

2. Authentication Filter

@WebFilter("/secure/*") public class AuthFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpSession session = httpRequest.getSession(false); if (session == null || session.getAttribute("user") == null) { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.sendRedirect(httpRequest.getContextPath() + "/login"); return; } chain.doFilter(request, response); } }

3. Character Encoding Filter

@WebFilter("/*") public class EncodingFilter implements Filter { private String encoding = "UTF-8"; @Override public void init(FilterConfig filterConfig) throws ServletException { String configEncoding = filterConfig.getInitParameter("encoding"); if (configEncoding != null) { encoding = configEncoding; } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(encoding); response.setCharacterEncoding(encoding); chain.doFilter(request, response); } }

Filter Configuration Methods

Annotation-based Configuration

@WebFilter( urlPatterns = { "/secure/*"}, initParams = { @WebInitParam(name = "param1", value = "value1"), @WebInitParam(name = "param2", value = "value2") }, dispatcherTypes = { DispatcherType.REQUEST, DispatcherType.FORWARD} ) public class MyFilter implements Filter { // Filter implementation }

XML-based Configuration (web.xml)

<filter> <filter-name>MyFilter</filter-name> <filter-class>com.example.MyFilter</filter-class> <init-param> <param-name>param1</param-name> <param-value>value1</param-value> </init-param> </filter> <filter-mapping> <filter-name>MyFilter</filter-name> <url-pattern>/secure/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping>

Filter Ordering

Filters execute in the following order:

  1. Filters declared in web.xml (in the order they appear)
  2. Filters declared with @WebFilter (order not guaranteed)
Note: To control order of @WebFilter annotated filters, implement the javax.servlet.annotation.ServletFilter interface and use the @ServletFilter annotation's filterName and ordering attributes.

Filter Lifecycle

Method Description When Called
init() Initialization method When the filter is first loaded
doFilter() Processes requests/responses For each request
destroy() Cleanup method When the filter is unloaded

Dependency Injection (DI)

Definition

Dependency Injection is a design pattern where objects receive their dependencies from an external source rather than creating them internally.

Real-world Analogy:

Imagine a car (your class) that needs an engine (dependency). Instead of building its own engine, it receives a ready-to-use engine from a factory.

Types of Dependency Injection

  1. Constructor Injection
    public class Car {
        private Engine engine;
        
        // Dependency injected via constructor
        public Car(Engine engine) {
            this.engine = engine;
        }
    }
  2. Setter Injection
    public class Car {
        private Engine engine;
        
        // Dependency injected via setter
        public void setEngine(Engine engine) {
            this.engine = engine;
        }
    }
  3. Field/Property Injection
    public class Car {
        @Inject  // Annotation-based (Framework specific)
        private Engine engine;
    }

Benefits of Dependency Injection

DI Containers (Frameworks)

Frameworks that manage dependency injection:

Practical Example (Spring)

// Service interface
public interface MessageService {
    String getMessage();
}

// Implementation
@Service
public class EmailService implements MessageService {
    public String getMessage() {
        return "Email message";
    }
}

// Client class
@Controller
public class NotificationController {
    private final MessageService service;
    
    // Constructor injection
    @Autowired
    public NotificationController(MessageService service) {
        this.service = service;
    }
    
    public void sendNotification() {
        String message = service.getMessage();
        // Send notification
    }
}

DI vs Traditional Approach

Dependency Injection Traditional
Dependencies provided externally Dependencies created internally
Easier to test (can inject mocks) Harder to test (real dependencies)
More flexible configuration Rigid implementation

Best Practices

Java Streams API

The Streams API was introduced in Java 8. It provides a functional-style way to process collections of data without modifying the original data. Streams allow operations like filtering, mapping, and reducing in a clean, declarative manner.

Key Features:

Common Stream Methods:

Example 1: Filtering and Collecting

List<Integer> numbers = Arrays.asList(10, 15, 20, 25, 30);

List<Integer> filtered = numbers.stream()
                                 .filter(n -> n > 20)
                                 .collect(Collectors.toList());

System.out.println(filtered); // Output: [25, 30]
    

Example 2: Mapping and Printing

List<String> names = Arrays.asList("john", "jane", "jack");

names.stream()
     .map(String::toUpperCase)
     .forEach(System.out::println);
// Output:
// JOHN
// JANE
// JACK
    

Types of Streams:

Example 3: Parallel Stream

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

numbers.parallelStream()
       .forEach(n -> System.out.println(n));
    

Advantages:

Generics in Java

Generics in Java allow you to define classes, interfaces, and methods with a placeholder for the data type. This enables code reusability and type safety by ensuring that you work with the intended data types at compile time.

Why Use Generics?

Generic Class

Example:

class Box<T> {
    private T value;
    
    public void set(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        Box<String> stringBox = new Box<>();
        stringBox.set("Hello Generics");
        System.out.println(stringBox.get());

        Box<Integer> intBox = new Box<>();
        intBox.set(123);
        System.out.println(intBox.get());
    }
}
    

Generic Method

Example:

public class Main {
    public static <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.println(element);
        }
    }

    public static void main(String[] args) {
        Integer[] numbers = {1, 2, 3};
        String[] names = {"Java", "Python"};

        printArray(numbers);
        printArray(names);
    }
}
    

Generic Interface

Example:

interface Printer<T> {
    void print(T value);
}

class StringPrinter implements Printer<String> {
    public void print(String value) {
        System.out.println("Printing String: " + value);
    }
}
    

Bounded Type Parameters

You can restrict the types that can be used with generics using extends.

Example:

class Calculator<T extends Number> {
    public double square(T number) {
        return number.doubleValue() * number.doubleValue();
    }
}
    

Wildcard in Generics

Example:

public void printList(List<?> list) {
    for (Object obj : list) {
        System.out.println(obj);
    }
}
    

API in Java

API stands for Application Programming Interface. In Java, an API is a collection of predefined classes, interfaces, and methods that provide functionality to perform various programming tasks.

Purpose of Java API

Common Java API Packages

Example: Using Java API

Example:

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Java");
        list.add("API");
        list.add("Example");

        for (String item : list) {
            System.out.println(item);
        }
    }
}
    

Types of Java APIs

Creating a Simple API in Java (Using Spring Boot)

You can create a RESTful API in Java using the Spring Boot framework. It allows clients to make HTTP requests and receive data (like JSON).

API Controller Example:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    
    @GetMapping("/hello")
    public String sayHello() {
        return "Hello from Java API!";
    }
}
    

Spring Boot Main Application Class:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ApiApp {
    public static void main(String[] args) {
        SpringApplication.run(ApiApp.class, args);
    }
}
    

Run & Test

Java Annotations

Java Annotations are metadata that provide additional information to the compiler or runtime environment. They do not change the actual logic of the program but can be used to instruct the compiler, generate code, or configure frameworks like Spring and Hibernate.

Uses of Annotations

Built-in Annotations in Java

Example:

class Animal {
    void sound() {
        System.out.println("Animal sound");
    }
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("Bark");
    }
}
    

Custom Annotations

You can also create your own annotations using the @interface keyword.

Example: Creating and Using Custom Annotation

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface MyAnnotation {
    String value();
}

public class Test {
    @MyAnnotation(value = "Hello Annotation")
    public void show() {
        System.out.println("Using custom annotation");
    }
}
    

Annotation Meta-Annotations

Conclusion

Java Annotations help add behavior and configuration to your code without cluttering logic. They are essential for modern Java frameworks and clean application development.

Java Memory Management

Java Memory Management is the process of allocating and deallocating memory automatically. It helps in efficiently using memory and avoiding memory leaks or overuse. Java uses an automatic garbage collector to manage memory.

Memory Areas in JVM

Phases of Memory Management

  1. Allocation: Memory is allocated to variables and objects using the new keyword.
  2. Use: Program uses that memory for operations.
  3. Garbage Collection: Unused memory (unreferenced objects) is automatically cleaned up.

Garbage Collection

Java uses automatic garbage collection to reclaim memory. When an object is no longer reachable, the Garbage Collector frees its memory.

Garbage Collector Types:

Example: Object Allocation and Garbage Collection

Example:

public class MemoryDemo {
    public static void main(String[] args) {
        MemoryDemo obj = new MemoryDemo(); // allocated in heap
        obj = null; // eligible for garbage collection
        System.gc(); // request GC
    }

    @Override
    protected void finalize() {
        System.out.println("Object is garbage collected");
    }
}
    

Best Practices for Memory Management

Conclusion

Java Memory Management automates the process of memory allocation and garbage collection. Understanding how memory works helps in writing optimized and efficient Java applications.

Networking in Java

Socket and ServerSocket

// Client Socket Example
Socket clientSocket = new Socket("localhost", 8080);
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
out.println("Hello Server");
clientSocket.close();

// ServerSocket Example
ServerSocket serverSocket = new ServerSocket(8080);
Socket client = serverSocket.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
String message = in.readLine();
System.out.println("Received: " + message);
serverSocket.close();

HTTP requests using HttpURLConnection

URL url = new URL("https://api.example.com/data");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");

int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String inputLine;
    StringBuilder response = new StringBuilder();
    
    while ((inputLine = in.readLine()) != null) {
        response.append(inputLine);
    }
    in.close();
    System.out.println(response.toString());
}
conn.disconnect();

Java NIO (Non-blocking I/O)

// Server Example
Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress("localhost", 8080));
serverSocket.configureBlocking(false);
serverSocket.register(selector, SelectionKey.OP_ACCEPT);

while (true) {
    selector.select();
    Set<SelectionKey> selectedKeys = selector.selectedKeys();
    Iterator<SelectionKey> iter = selectedKeys.iterator();
    
    while (iter.hasNext()) {
        SelectionKey key = iter.next();
        
        if (key.isAcceptable()) {
            SocketChannel client = serverSocket.accept();
            client.configureBlocking(false);
            client.register(selector, SelectionKey.OP_READ);
        }
        
        if (key.isReadable()) {
            SocketChannel client = (SocketChannel) key.channel();
            ByteBuffer buffer = ByteBuffer.allocate(256);
            client.read(buffer);
            String result = new String(buffer.array()).trim();
            System.out.println("Message: " + result);
            client.close();
        }
        iter.remove();
    }
}

Java Database Connectivity (JDBC)

Connecting to databases

// MySQL connection example
String url = "jdbc:mysql://localhost:3306/mydb";
String username = "root";
String password = "password";

try (Connection conn = DriverManager.getConnection(url, username, password)) {
    System.out.println("Connected to database!");
} catch (SQLException e) {
    e.printStackTrace();
}

Statement, PreparedStatement, CallableStatement

// Statement
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users");

// PreparedStatement
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO users VALUES (?, ?)");
pstmt.setInt(1, 101);
pstmt.setString(2, "John");
pstmt.executeUpdate();

// CallableStatement (for stored procedures)
CallableStatement cstmt = conn.prepareCall("{call get_user_details(?)}");
cstmt.setInt(1, 101);
ResultSet rs = cstmt.executeQuery();

Connection pooling (HikariCP, C3P0)

// HikariCP example
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("root");
config.setPassword("password");
config.setMaximumPoolSize(10);

try (HikariDataSource ds = new HikariDataSource(config);
     Connection conn = ds.getConnection()) {
    // Use connection
}

Java 8+ Features

Optional Class

Optional<String> optional = Optional.ofNullable(getName());
String name = optional.orElse("default");

optional.ifPresent(n -> System.out.println("Name: " + n));

String value = optional.orElseThrow(() -> new RuntimeException("Value not present"));

CompletableFuture (async programming)

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // Long running task
    return "Result";
});

future.thenAccept(result -> System.out.println("Got: " + result))
      .exceptionally(ex -> {
          System.out.println("Error: " + ex.getMessage());
          return null;
      });

// Chaining
CompletableFuture<Integer> result = CompletableFuture.supplyAsync(() -> 10)
    .thenApply(x -> x * 2)
    .thenApply(x -> x + 5);

New Date & Time API

LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);

LocalTime now = LocalTime.now();
LocalTime later = now.plusHours(2);

ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Europe/Paris"));

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
String formatted = zdt.format(formatter);

Records (Java 16)

public record Person(String name, int age) {}

Person p = new Person("John", 30);
System.out.println(p.name());  // Accessor
System.out.println(p);         // toString()

Pattern Matching (Java 17+)

// Pattern matching for instanceof
if (obj instanceof String s) {
    System.out.println(s.length());
}

// Switch pattern matching
return switch (shape) {
    case Circle c -> Math.PI * c.radius() * c.radius();
    case Rectangle r -> r.length() * r.width();
    default -> 0;
};

Design Patterns in Java

Singleton

public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Factory

interface Shape {
    void draw();
}

class Circle implements Shape {
    public void draw() { System.out.println("Drawing circle"); }
}

class ShapeFactory {
    public Shape getShape(String type) {
        if (type.equalsIgnoreCase("CIRCLE")) {
            return new Circle();
        }
        return null;
    }
}

Observer

interface Observer {
    void update(String message);
}

class ConcreteObserver implements Observer {
    public void update(String message) {
        System.out.println("Received: " + message);
    }
}

class Subject {
    private List<Observer> observers = new ArrayList<>();
    
    public void addObserver(Observer o) {
        observers.add(o);
    }
    
    public void notifyObservers(String message) {
        for (Observer o : observers) {
            o.update(message);
        }
    }
}

Builder

public class User {
    private final String firstName;
    private final String lastName;
    
    private User(Builder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
    }
    
    public static class Builder {
        private String firstName;
        private String lastName;
        
        public Builder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }
        
        public Builder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }
        
        public User build() {
            return new User(this);
        }
    }
}

// Usage:
User user = new User.Builder()
    .firstName("John")
    .lastName("Doe")
    .build();

Strategy

interface PaymentStrategy {
    void pay(int amount);
}

class CreditCardPayment implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println("Paid " + amount + " via credit card");
    }
}

class ShoppingCart {
    private PaymentStrategy strategy;
    
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void checkout(int amount) {
        strategy.pay(amount);
    }
}

Java Reflection

Class class

Class<?> clazz = Class.forName("java.lang.String");
System.out.println("Class name: " + clazz.getName());

Method[] methods = clazz.getDeclaredMethods();
for (Method m : methods) {
    System.out.println(m.getName());
}

Accessing private fields/methods

Class<?> clazz = MyClass.class;
Field privateField = clazz.getDeclaredField("secret");
privateField.setAccessible(true);

MyClass obj = new MyClass();
String value = (String) privateField.get(obj);
System.out.println("Private value: " + value);

Dynamic object creation

Class<?> clazz = Class.forName("com.example.MyClass");
Constructor<?> constructor = clazz.getConstructor(String.class);
Object instance = constructor.newInstance("test");

Method method = clazz.getMethod("doSomething");
method.invoke(instance);

Java Security

SecurityManager

SecurityManager sm = System.getSecurityManager();
if (sm != null) {
    sm.checkPermission(new FilePermission("/tmp/test.txt", "read"));
}

Cryptography (MessageDigest, Cipher)

// Hashing with MessageDigest
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest("password".getBytes());

// Encryption with Cipher
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey key = new SecretKeySpec("0123456789ABCDEF".getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal("secret".getBytes());

JCA (Java Cryptography Architecture)

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.generateKeyPair();

Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(kp.getPrivate());
sig.update("data".getBytes());
byte[] signature = sig.sign();

Java Native Interface (JNI)

Calling C/C++ from Java

// Java code
public class NativeDemo {
    public native void sayHello();
    
    static {
        System.loadLibrary("NativeDemo");
    }
    
    public static void main(String[] args) {
        new NativeDemo().sayHello();
    }
}

// C implementation
#include <jni.h>
#include <stdio.h>
#include "NativeDemo.h"

JNIEXPORT void JNICALL Java_NativeDemo_sayHello(JNIEnv *env, jobject obj) {
    printf("Hello from C!\n");
}

Java Modules (Java 9+)

module-info.java

module com.example.myapp {
    requires java.base;
    requires java.sql;
    requires transitive com.example.mylib;
    
    exports com.example.myapp.api;
    opens com.example.myapp.internal to com.example.test;
}

Modular JARs

// Compile with modules
javac --module-path lib -d mods/com.example.myapp \
    src/com.example.myapp/module-info.java \
    src/com.example.myapp/com/example/myapp/*.java

// Create modular JAR
jar --create --file=mlib/com.example.myapp.jar \
    --main-class=com.example.myapp.Main \
    -C mods/com.example.myapp .

Java Microbenchmarking (JMH)

Performance testing

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MyBenchmark {

    @Benchmark
    public void testMethod(Blackhole bh) {
        int result = doCalculation();
        bh.consume(result);
    }
    
    private int doCalculation() {
        // Complex calculation
        return 42;
    }
}

Java Agents & Instrumentation

Bytecode manipulation (ASM, Javassist)

// Javassist example
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.example.MyClass");
CtMethod m = cc.getDeclaredMethod("doSomething");
m.insertBefore("{ System.out.println(\"Before method\"); }");
cc.writeFile();

// ASM example
ClassReader cr = new ClassReader("com/example/MyClass");
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = new MyClassVisitor(cw);
cr.accept(cv, 0);
byte[] modifiedClass = cw.toByteArray();

Java Web Technologies

Servlets & JSP

// Servlet example
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        resp.getWriter().println("Hello World");
    }
}

// JSP example
<%@ page contentType="text/html" %>
<html>
<body>
  <% String name = request.getParameter("name"); %>
  <h1>Hello <%= name %>!</h1>
</body>
</html>

JavaServer Faces (JSF)

// Managed Bean
@ManagedBean
@RequestScoped
public class UserBean {
    private String name;
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public String submit() {
        return "result";
    }
}

// Facelet page
<h:form>
    <h:inputText value="#{userBean.name}"/>
    <h:commandButton value="Submit" action="#{userBean.submit}"/>
</h:form>

Spring Framework

// Spring Boot Controller
@RestController
@RequestMapping("/api")
public class MyController {
    
    @GetMapping("/hello")
    public String sayHello() {
        return "Hello from Spring!";
    }
}

// Spring Configuration
@Configuration
@ComponentScan("com.example")
public class AppConfig {
    @Bean
    public DataSource dataSource() {
        return new DriverManagerDataSource("jdbc:h2:mem:test");
    }
}

Java Testing Frameworks

JUnit 5

@Test
void standardAssertions() {
    assertEquals(2, calculator.add(1, 1));
    assertTrue('a' < 'b', "Assertion message");
}

@ParameterizedTest
@ValueSource(ints = {1, 3, 5})
void isOdd(int number) {
    assertTrue(number % 2 != 0);
}

Mockito

@Test
void testWithMock() {
    // Create mock
    List<String> mockedList = mock(List.class);
    
    // Set up mock behavior
    when(mockedList.get(0)).thenReturn("first");
    
    // Use mock
    assertEquals("first", mockedList.get(0));
    
    // Verify interactions
    verify(mockedList).get(0);
}

TestNG

@Test
public void testAdd() {
    Assert.assertEquals(calculator.add(1, 1), 2);
}

@Test(dependsOnMethods = {"testAdd"})
public void testMultiply() {
    Assert.assertEquals(calculator.multiply(2, 3), 6);
}

@DataProvider(name = "testData")
public Object[][] createData() {
    return new Object[][]{{1, 1, 2}, {2, 3, 5}};
}

@Test(dataProvider = "testData")
public void testAddWithData(int a, int b, int expected) {
    Assert.assertEquals(calculator.add(a, b), expected);
}

Java Concurrency (Advanced)

ForkJoinPool

class FibonacciTask extends RecursiveTask<Integer> {
    final int n;
    FibonacciTask(int n) { this.n = n; }
    
    protected Integer compute() {
        if (n <= 1) return n;
        FibonacciTask f1 = new FibonacciTask(n - 1);
        f1.fork();
        FibonacciTask f2 = new FibonacciTask(n - 2);
        return f2.compute() + f1.join();
    }
}

// Usage
ForkJoinPool pool = new ForkJoinPool();
int result = pool.invoke(new FibonacciTask(10));

Phaser

Phaser phaser = new Phaser(3); // 3 parties

new Thread(() -> {
    phaser.arriveAndAwaitAdvance(); // Phase 1
    System.out.println("Thread 1 phase 1 done");
    phaser.arriveAndDeregister(); // Done
}).start();

new Thread(() -> {
    phaser.arriveAndAwaitAdvance(); // Phase 1
    System.out.println("Thread 2 phase 1 done");
    phaser.arriveAndDeregister(); // Done
}).start();

phaser.arriveAndAwaitAdvance(); // Main thread waits
System.out.println("All threads completed phase 1");

StampedLock

class Point {
    private double x, y;
    private final StampedLock sl = new StampedLock();
    
    void move(double deltaX, double deltaY) {
        long stamp = sl.writeLock();
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            sl.unlockWrite(stamp);
        }
    }
    
    double distanceFromOrigin() {
        long stamp = sl.tryOptimisticRead();
        double currentX = x, currentY = y;
        if (!sl.validate(stamp)) {
            stamp = sl.readLock();
            try {
                currentX = x;
                currentY = y;
            } finally {
                sl.unlockRead(stamp);
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }
}

Java GUI Programming

Swing

JFrame frame = new JFrame("My App");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JButton button = new JButton("Click Me");
button.addActionListener(e -> {
    JOptionPane.showMessageDialog(frame, "Button clicked!");
});

frame.getContentPane().add(button);
frame.pack();
frame.setVisible(true);

JavaFX

public class MyApp extends Application {
    @Override
    public void start(Stage stage) {
        Button btn = new Button("Click Me");
        btn.setOnAction(e -> {
            System.out.println("Button clicked!");
        });
        
        StackPane root = new StackPane();
        root.getChildren().add(btn);
        
        Scene scene = new Scene(root, 300, 250);
        stage.setTitle("My JavaFX App");
        stage.setScene(scene);
        stage.show();
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}

Java & Big Data

Apache Hadoop

public class WordCount extends Configured implements Tool {
    
    public static class TokenizerMapper 
        extends Mapper<Object, Text, Text, IntWritable> {
        
        public void map(Object key, Text value, Context context) {
            // Map logic
        }
    }
    
    public static class IntSumReducer
        extends Reducer<Text, IntWritable, Text, IntWritable> {
        
        public void reduce(Text key, Iterable<IntWritable> values, Context context) {
            // Reduce logic
        }
    }
    
    public int run(String[] args) throws Exception {
        Job job = Job.getInstance(getConf(), "word count");
        job.setJarByClass(WordCount.class);
        job.setMapperClass(TokenizerMapper.class);
        job.setReducerClass(IntSumReducer.class);
        // Other job configuration
        return job.waitForCompletion(true) ? 0 : 1;
    }
    
    public static void main(String[] args) throws Exception {
        int res = ToolRunner.run(new Configuration(), new WordCount(), args);
        System.exit(res);
    }
}

Apache Spark

SparkConf conf = new SparkConf().setAppName("WordCount").setMaster("local");
JavaSparkContext sc = new JavaSparkContext(conf);

JavaRDD<String> textFile = sc.textFile("hdfs://...");
JavaRDD<String> words = textFile.flatMap(line -> Arrays.asList(line.split(" ")).iterator());
JavaPairRDD<String, Integer> pairs = words.mapToPair(word -> new Tuple2<>(word, 1));
JavaPairRDD<String, Integer> counts = pairs.reduceByKey((a, b) -> a + b);

counts.saveAsTextFile("hdfs://...");

Java & Cloud

AWS SDK for Java

// Create S3 client
AmazonS3 s3 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_EAST_1)
    .build();

// List buckets
for (Bucket bucket : s3.listBuckets()) {
    System.out.println(bucket.getName());
}

// Upload file
s3.putObject("my-bucket", "key", new File("file.txt"));

Spring Cloud

// Eureka Client
@SpringBootApplication
@EnableDiscoveryClient
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

// Feign Client
@FeignClient(name = "service-name")
public interface MyFeignClient {
    @GetMapping("/api/resource")
    String getResource();
}

// Config Client
@RestController
@RefreshScope
public class ConfigController {
    @Value("${my.property}")
    private String myProperty;
    
    @GetMapping("/property")
    public String getProperty() {
        return myProperty;
    }
}

Java vs C# Comparison

Feature Java C#
Platform Write Once, Run Anywhere (JVM) Primarily Windows (.NET), now cross-platform with .NET Core
Checked Exceptions Supported (must be caught or declared) Not supported
Properties Need to write getter/setter methods Built-in property syntax
Delegates/Events Uses interfaces or functional interfaces Has delegates and events
LINQ Uses Stream API (Java 8+) Has LINQ (Language Integrated Query)
Multiple Inheritance Through interfaces only Through interfaces only