JAVA

1. Introduction to Java

History of JAVA

  • Developed by James Gosling and his team in 1990s at Sun Microsystems.
  • Initial Release was in 1995.
  • Platform Independent
  • Now owned by Oracle which acquired Sun Microsystems in 2010.

history of java in short

Java, developed by James Gosling and his team at Sun Microsystems, has a history dating back to the early 1990s. Here's a brief overview of the key milestones in Java's history:

  1. Inception (1991-1995): Java's development began in 1991 as a project called "Oak" by James Gosling, Mike Sheridan, and Patrick Naughton at Sun Microsystems. The goal was to create a programming language for embedded systems. In 1995, the language was officially released as Java.
  2. Public Debut (1995): Java 1.0 was publicly released in January 1996. It gained attention for its "Write Once, Run Anywhere" (WORA) principle, allowing developers to create platform-independent applications.
  3. Applets and Web Revolution (mid-1990s): Java applets, small applications designed to run within web browsers, became popular in the mid-1990s. This contributed to the early growth of interactive and dynamic content on the World Wide Web.
  4. Introduction of Java 2 (J2SE 1.2, 1998): Java 2, released in 1998, brought significant enhancements to the language and introduced the Java Naming and Directory Interface (JNDI), the Swing GUI toolkit, and the Collections Framework.
  5. Enterprise Java (J2EE, 1999): Java 2 Platform, Enterprise Edition (J2EE) was introduced in 1999, focusing on enterprise-level applications. It included technologies like Servlets, JSP (JavaServer Pages), and EJB (Enterprise JavaBeans).
  6. Acquisition by Oracle (2010): Oracle Corporation acquired Sun Microsystems in 2010, becoming the new steward of the Java platform.
  7. Java SE 7 and 8 (2011, 2014): Java SE 7, released in 2011, introduced several language enhancements and the Fork/Join framework for parallel programming. Java SE 8, released in 2014, brought significant changes with the introduction of lambda expressions and the Stream API.
  8. Modularization with Java SE 9 (2017): Java SE 9 introduced the Java Platform Module System (JPMS), enabling better modularity in Java applications.
  9. Java SE 10 and Beyond (2018-2022): Subsequent releases introduced features like local-variable type inference (var) in Java SE 10, and ongoing releases have continued to bring improvements and new features to the language.
Version Release Date Code Name
JDK 1.0 1996-01-23 Oak (changed to Java)
JDK 1.1 1997-02-19 Sparkler
JDK 1.2 1998-12-08 Playground
JDK 1.3 2000-05-08 Kestrel
JDK 1.4 2002-02-06 Merlin
JDK 5.0 2004-09-30 Tiger
JDK 6 2006-12-11 Mustang
JDK 7 2011-07-28 Dolphin
JDK 8 2014-03-18 Spider
JDK 9 2017-09-21 Project Jigsaw
JDK 10 2018-03-20 18.3 (No Code Name)
JDK 11 2018-09-25 18.9 (No Code Name)

Pasted image 20231219224505.png
Pasted image 20231219224609.png
Pasted image 20231219224953.png
Pasted image 20231219225056.png
Pasted image 20231219225205.png
Pasted image 20231221181655.png

Java Virtual Machine (JVM)

  • Provides execution environment for Java Bytecode.
  • Manages memory allocation, garbage collection, bytecode execution.
  • Enables JAVA's Write once, run anywhere philosophy.

Java Development Kit (JDK)

  • Software Development Kit for developing Java Applications
  • Includes tools for compiling, debugging and Running Java Code.

3. Object-Oriented Programming (OOP)

Classes and objects

A class is a blueprint for creating objects. It defines the properties and behaviors common to all objects of a certain type. In other words, a class describes the attributes and methods that an object will have, but it doesn't actually create the objects themselves. Classes are often compared to templates or molds from which objects are created.

An object is an instance of a class. It represents a real-world entity and encapsulates both data (attributes) and behaviors (methods) defined by its class.

Java Concepts :

Java Concepts :

Pasted image 20240216232825.png

Inheritance :

  • Basically classes ko extend karna

Polymorphism :

https://www.geeksforgeeks.org/difference-between-compile-time-and-run-time-polymorphism-in-java/
Function having same name, but it performs different operations.
For example : If we use print operation then, method for printing an image and document will be different.

  • It is of two types : Compile Time Polymorphism and Runtime Polymorphism :
    • Compile Time : Method Overloading
    • Runtime : Method Overriding (Class extend karke parent class ke method ko @Override use karke uska method ko override karna (@Override use karna is not necessary))

Encapsulation :

It refers to the bundling of data (attributes or variables) and methods (functions or procedures) that operate on the data into a single unit known as a class. Encapsulation helps in hiding the internal implementation details of an object and protecting its state from external interference.

In Java, encapsulation is achieved by declaring the fields of a class as private and providing public getter and setter methods to access and modify the values of these fields.

Abstraction :

In this lecture we will learn:
- What is Abstraction?
- Abstract method in Java
- Abstract class in Java
- Abstract vs Concrete classes

#1
Abstraction is a process of hiding the implementation details and showing only functionality to the user.

#2
Abstract method:-
- Instead of defining the method, we can declare the method.
- If we put a semicolon at the end of a method, it means that you only declare the method like:
 public void drive();
- This method does not contain any features and you will not be able to create an object of it.
- You need to add an abstract keyword to only declare a method.

#3
Abstract class:-
- Abstract methods can only be defined in an abstract class.
- We need to add an abstract keyword before a class to make it an abstract class.
- Objects of an abstract class can not be created.
- If you are extending an abstract class, then it is compulsory to define all abstract methods.
- It is not necessary that an abstract class should have an abstract method.
- Abstract class can have an abstract or a normal method or both.
- An abstract class can have more than one abstract method.

#4
Concrete class: A class other than an abstract class is known as a concrete class.
- An object of a concrete class can be created.

  • Interface can also be used for defining abstract methods.
Difference b/w abstraction and encapsulation

Difference b/w abstraction and encapsulation

  • Abstraction is detail / implementation hiding.
  • Encapsulation is data / information hiding.
  • Data abstraction deals with exposing the interface to the user and hiding the details of the implementation.
  • Encapsulation groups together data and a method that acts upon the data.
Inheritance :

Inheritance :

  • Inheritance in JAVA is a mechanism in which one object acquires all the properties and behavior of a parent object.
package com.hitarth.packages;
/* ------------------------------------------------------ */

//superclass or parent class
class Calc {
    public int add(int n1, int n2) {
        return n1 + n2;
    }

    public int sub(int n1, int n2) {
        return n1 - n2;
    }
}

//subclass or child class
class AdvCalc extends Calc
{
    public int mult(int n1, int n2)
    {
        return n1*n2;
    }
}

/* ------------------------------------------------------ */

public class _07_Inheritance {
    public static void main(String[] args) {
        Calc obj = new Calc();
        int r1 = obj.add(1,2);
        System.out.println(r1); // → 3

        AdvCalc obj2 = new AdvCalc();
        int r2 = obj2.mult(2,3);
        int r3 = obj2.add(1,3);
        System.out.println(r2); // → 6
        System.out.println(r3); // → 4
    }
}

AdvCalc IS-A (read as "is a") Calc : means that AdvCalc is a child class and Calc is a parent class.

  • Inheritance offers IS-A relationship
  • The main advantage of Inheritance is code reusability. If we require to reuse a class then we can simply use the extend keyword.
  • We can achieve polymorphism by using inheritance.
    Disadvantage :
  • Two classes will be tightly coupled. Child class will inherit / access all the classes of the parent class.
  • When there are many child classes of a parent class then when a change is made to the parent class then that change will be reflected in all the child classes of that parent class which may or may not be required.
  • Child class will be tightly coupled with the parent class, so any change in the parent class will cause impact on all the child classes.

Types of Inheritance :

1. Single Inheritance :

  • Ek parent class hogi and ek child class hogi
  • Pasted image 20240314142416.png

2. Multilevel Inheritance

  • Pasted image 20240314142446.png
example khud se padh lena bhai

Pasted image 20240314143125.png

3. Hierarchical Inheritance :

Pasted image 20240314142532.png

example khud se padh lena bhai

4. Multiple Inheritance :

Pasted image 20240314142629.png

5. Hybrid Inheritance :

When any two inheritance types are combined :
Pasted image 20240314142758.png

Only 1,2,3 types of inheritances are used in JAVA.

Can a child class Access all the properties of the parent class ?

  • If a method is private in a parent class then the child class will not be able to access that private method.
  • If there is a constructor in a parent class then a child class will not be able to access/call the constructor of its parent class.
  • Constructor and private methods of parent class do not get inherited into child classes.

Pasted image 20240106022114.png
Pasted image 20240222213952.png

4. Exception Handling

Try and Catch Block :

Try and Catch Block :

Try Block:

  • The try block encloses the code that may generate exceptions.
  • It is followed by one or more catch blocks.
  • If an exception occurs within the try block, the execution of the try block is halted, and the control is transferred to the corresponding catch block.

Catch Block:

  • A catch block catches and handles exceptions thrown within the associated try block.
  • Each catch block specifies the type of exception it can handle, allowing for selective exception handling.
  • If an exception of the specified type occurs, the code inside the corresponding catch block is executed.
  • If no catch block matches the thrown exception, it propagates up the call stack, potentially halting the program if unhandled.
try {
    // Code that may throw exceptions
} catch (ExceptionType1 e1) {
    // Exception handling for ExceptionType1
} catch (ExceptionType2 e2) {
    // Exception handling for ExceptionType2
} finally {
    // Optional: Code that always executes, regardless of exceptions
}

Finally Block:

  • Optionally, a finally block can be used after all catch blocks.
  • The code inside the finally block executes whether an exception occurs or not.
  • Commonly used for cleanup operations like closing files or releasing resources.

Example:

try {
    int result = 10 / 0; // This will throw an ArithmeticException
} catch (ArithmeticException e) {
    System.out.println("An error occurred: " + e.getMessage());
} finally {
    System.out.println("This code always executes.");
}
public class Example {
    public static void main(String[] args) {
        try {
            // Creating and throwing a NullPointerException with a "custom" esxception explicitly
            throw new NullPointerException("Custom NullPointerException message");
        } catch (NullPointerException e) {
            System.out.println("Caught NullPointerException: " + e.getMessage());
        }
    }
}

Difference between throw and throws :

  1. throw:

    • throw is a keyword used to explicitly throw an exception from within a method or block of code.
    • It is used when a specific condition occurs that warrants the interruption of the normal flow of execution due to an exceptional situation.
    • With throw, you can throw both built-in exceptions provided by Java (such as NullPointerException, IllegalArgumentException, etc.) and custom exceptions that you define in your code.
    • When you throw an exception, you are responsible for creating and specifying the exception object to be thrown.

    Example:

    public void method() {
        if (condition) {
            throw new SomeException("Custom message");
        }
    }
    
  2. throws:

    • throws is used in the method declaration to indicate that the method may throw certain types of exceptions during its execution.
    • It specifies the types of exceptions that a method might throw but does not actually throw them itself.
    • When you use throws, you are declaring the exceptions that can be thrown by a method, allowing the caller of the method to handle those exceptions.

    Example:

    public void method() throws SomeException {
        // Method code that may throw SomeException
    }
    

    The caller of this method would then need to handle the SomeException either by catching it or declaring it to be thrown further.

In summary, throw is used to throw an exception explicitly within a method, while throws is used to declare the types of exceptions that a method might throw, allowing the caller to handle them appropriately.

Custom Exception Message

In Java, you can create your own custom exceptions by extending the built-in Exception class or one of its subclasses. Here's how you can create and use a custom exception:

  1. Create Custom Exception Class:
    First, create a new class that extends Exception or one of its subclasses. You can define constructors and methods specific to your custom exception.

    public class CustomException extends Exception {
        public CustomException() {
            super("Custom exception message");
        }
        
        public CustomException(String message) {
            super(message);
        }
    }
    
  2. Throw Custom Exception:
    In your code, when you encounter a situation that warrants throwing your custom exception, use the throw keyword followed by an instance of your custom exception class.

    public void someMethod() throws CustomException {
        // Condition that triggers the exception
        if (condition) {
            throw new CustomException("Custom message for the exception");
        }
    }
    
  3. Handle Custom Exception:
    When calling the method that can throw your custom exception, handle it using a try-catch block.

    try {
        someObject.someMethod();
    } catch (CustomException e) {
        // Handle the custom exception
        System.out.println("Custom exception occurred: " + e.getMessage());
    }
    

Putting it all together, here's an example demonstrating the creation, throwing, and handling of a custom exception:

// CustomException.java
public class CustomException extends Exception {
    public CustomException() {
        super("Custom exception message");
    }

    public CustomException(String message) {
        super(message);
    }
}
// Example.java
public class Example {
    public void someMethod() throws CustomException {
        // Simulating a condition that triggers the custom exception
        boolean condition = true;
        if (condition) {
            throw new CustomException("Custom message for the exception");
        }
    }
}
// Main.java
public class Main {
    public static void main(String[] args) {
        Example example = new Example();
        try {
            example.someMethod();
        } catch (CustomException e) {
            System.out.println("Custom exception occurred: " + e.getMessage());
        }
    }
}

In this example, we define a custom exception CustomException and then throw and handle it in the Example and Main classes, respectively.


  • ! AI Generated :
    In Java, you can achieve multitasking, multiprocessing, and multithreading using various features of the language and the Java Runtime Environment (JRE). Let's explore each concept in the context of Java:
  1. Multitasking in Java:

    • Java supports multitasking through its multithreading capabilities. You can run multiple threads within a single Java process, allowing you to perform multiple tasks concurrently.
    • Multitasking in Java is typically achieved by creating and managing multiple threads using the Thread class or implementing the Runnable interface.
  2. Multiprocessing in Java:

    • Multiprocessing, which involves utilizing multiple CPUs or CPU cores, can be achieved indirectly in Java by running multiple Java Virtual Machine (JVM) instances on a multicore system.
    • Each JVM instance runs as a separate process and can execute Java applications independently. Therefore, if you have multiple CPU cores, you can run multiple Java processes concurrently, effectively achieving multiprocessing.
  3. Multithreading in Java:

    • Multithreading is a fundamental feature of Java, allowing you to create and manage multiple threads within a single Java process.
    • Java provides built-in support for multithreading through the Thread class and the java.util.concurrent package.
    • You can create threads by extending the Thread class or implementing the Runnable interface and then starting these threads using the start() method.
    • Java also provides high-level concurrency utilities such as ExecutorService, ThreadPoolExecutor, and ConcurrentHashMap to simplify multithreaded programming and manage thread execution, synchronization, and communication.
    • Java provides predefined APIs for multithreading, for e.g. : Thread, Runnable, ThreadGroup, Concurrency, ThreadPool etc.

Here's a simple example demonstrating multithreading in Java:

class MyThread extends Thread {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
            try {
                Thread.sleep(1000); // Simulate some work
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();

        thread1.start(); // Start the first thread
        thread2.start(); // Start the second thread
    }
}

This example creates two threads (thread1 and thread2) that execute concurrently, each printing numbers from 0 to 4 with a 1-second delay between each iteration.

In summary:

  • Multitasking refers to running multiple tasks concurrently on a single CPU.
  • Multiprocessing involves using multiple CPUs or CPU cores to execute tasks concurrently.
  • Multithreading involves running multiple threads within a single process to achieve concurrency.
    • Executing multiple threads (subtasks) at a single time is known as multithreading.
    • It is used in various softwares, games, animations etc.

These concepts are fundamental to understanding how modern computer systems handle concurrent execution and optimize resource utilization.

8. Multithreading

Difference between Process and Thread in JAVA :

Thread Synchronization:

Thread synchronization is the process of controlling the access to shared resources by multiple threads to prevent data inconsistency and race conditions. In Java, synchronization can be achieved using synchronized blocks or methods, locks, or other concurrency utilities.

class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }
}

Concurrent Collections:
Java provides a set of thread-safe collection classes in the java.util.concurrent package, known as concurrent collections. These collections are designed to be used in multithreaded environments and provide better performance and scalability compared to traditional synchronized collections.

Examples of concurrent collections include ConcurrentHashMap, ConcurrentLinkedQueue, and CopyOnWriteArrayList.

ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("one", 1);
map.put("two", 2);

These concurrent collections offer thread-safe operations without the need for explicit synchronization, making them suitable for concurrent programming.

Understanding threads, thread management, synchronization, and concurrent collections is essential for developing efficient and scalable multithreaded Java applications. Proper synchronization ensures data consistency and avoids race conditions, while concurrent collections provide efficient access to shared data in multithreaded environments.