PROGRAMMING IN JAVA
1. Introduction to Basic Java Concepts
Java is a high-level, object-oriented programming language developed by Sun Microsystems (now
owned by Oracle Corporation). It emphasizes portability, robustness, security, and platform
independence, following the "write once, run anywhere" (WORA) philosophy.
Key Java features:
Object-Oriented Programming (OOP): Supports inheritance, polymorphism, encapsulation,
and abstraction.
Platform Independence: Java code is compiled into bytecode, which can run on any system
with a JVM.
Automatic Memory Management: Through garbage collection.
Rich Standard Library: Extensive APIs across data structures, networking, GUI, and more.
2. JDK, JRE, and JVM
These components are foundational to the Java ecosystem:
a) JVM (Java Virtual Machine)
Definition: An abstract computing machine that enables Java bytecode execution.
Functionality:
o Loads .class files (compiled bytecode).
o Verifies and executes code using either an interpreter or a Just-In-Time (JIT) compiler.
o Manages runtime memory (heap, stack, method area).
Platform-Specific: Although Java is platform-independent, the JVM is platform-dependent.
b) JRE (Java Runtime Environment)
Definition: A package providing the environment required to run Java applications.
Components:
o JVM
o Core libraries
o Other supporting files
Note: Does not contain development tools like the compiler (javac).
c) JDK (Java Development Kit)
Definition: A complete software development kit required for developing Java applications.
Includes:
o JRE (hence includes the JVM)
o Development tools such as javac, javadoc, jdb, and other utilities
Versions: Oracle provides standard and enterprise editions; open-source alternatives like
OpenJDK also exist.
Summary Table:
Component Contains Used For
JVM Bytecode interpreter Running Java bytecode
JRE JVM + Libraries Running Java applications
JDK JRE + Tools Developing Java applications
3. Wrapper Classes
Java is strictly object-oriented, and primitive types (e.g., int, double) are not objects. Wrapper
classes allow primitive types to be treated as objects.
a) Purpose:
Enable primitives to be stored in collections (like ArrayList, which require objects).
Provide utility methods (e.g., parsing strings to numbers).
Enable use of generics and autoboxing/unboxing.
b) Key Wrapper Classes:
Primitive Wrapper Class
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
c) Example:
Integer x = 10; // autoboxing
int y = x; // unboxing
4. Inner and Nested Classes
Java supports classes defined within other classes or methods, primarily for better encapsulation and
logical grouping.
a) Nested Classes:
All classes defined within another class.
Two main types:
1. Static Nested Class
2. Non-static Inner Class
b) Types of Inner Classes:
Type Description
Member Inner Class Non-static, defined at class level
Anonymous Inner Class Class without a name, often used for one-time-use implementations
Local Inner Class Defined within a method or block
Static Nested Class Declared with static keyword; doesn't require enclosing class instance
Example:
class Outer {
private int data = 30;
class Inner {
void msg() { System.out.println("Data is " + data); }
}
static class StaticNested {
void display() { System.out.println("Static nested class"); }
}
}
Use Cases:
GUI programming (event handling).
Logic encapsulation without polluting the top-level namespace.
Creating closely coupled helper classes.
Arrays in Java
An array is a container object that holds a fixed number of values of a single type.
1. Declaring and Creating an Array
int[] numbers = new int[5]; // creates an array of 5 integers
2. Initializing an Array
int[] numbers = {10, 20, 30, 40, 50};
3. Accessing Array Elements
System.out.println(numbers[2]); // Output: 30
4. Iterating through an Array
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]);
}
Or using an enhanced for-loop:
for (int num : numbers) {
System.out.println(num);
}
✨ Strings in Java
A String in Java is an object that represents a sequence of characters.
1. Creating Strings
String greeting = "Hello, World!";
2. String Methods
System.out.println(greeting.length()); // 13
System.out.println(greeting.toUpperCase()); // "HELLO, WORLD!"
System.out.println(greeting.charAt(0)); // 'H'
System.out.println(greeting.substring(0, 5)); // "Hello"
System.out.println(greeting.contains("World")); // true
3. String Concatenation
String name = "Alice";
String message = "Hello, " + name + "!";
System.out.println(message); // "Hello, Alice!"
4. Comparing Strings
String a = "Java";
String b = "java";
System.out.println(a.equals(b)); // false (case-sensitive)
System.out.println(a.equalsIgnoreCase(b)); // true
� Mini Example: Count Vowels in a String
public class VowelCounter {
public static void main(String[] args) {
String str = "Hello World";
int count = 0;
for (int i = 0; i < str.length(); i++) {
char ch = Character.toLowerCase(str.charAt(i));
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
count++;
}
}
System.out.println("Number of vowels: " + count);
}
}
� 1. String (Immutable)
Once a String object is created, it cannot be changed.
Any operation that seems to modify a string actually creates a new object.
🔹 Example:
String s = "Hello";
s.concat(" World"); // This creates a new string but doesn't assign it
System.out.println(s); // Output: "Hello"
s = s.concat(" World"); // Now we assign the result
System.out.println(s); // Output: "Hello World"
✅ Use String when you have a fixed or rarely changed value.
🔗 2. StringBuffer (Mutable + Thread-safe)
A StringBuffer can be modified without creating new objects.
It is synchronized, so it's safe to use in multi-threaded environments.
Slightly slower than StringBuilder because of the synchronization overhead.
🔹 Example:
StringBuffer sb = new StringBuffer("Hello");
sb.append(" World");
System.out.println(sb); // Output: "Hello World"
✅ Use StringBuffer when you need to modify strings in multi-threaded code.
⚡ 3. StringBuilder (Mutable + Not Thread-safe)
Just like StringBuffer, but not synchronized.
It is faster and preferred for single-threaded applications.
🔹 Example:
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb); // Output: "Hello World"
✅ Use StringBuilder when you're building strings in loops or in single-threaded code.
Access Modifiers
Java access modifiers are used to specify the scope of the variables, data members,
methods, classes, or constructors. These help to restrict and secure the access (or,
level of access) of the data.
There are four different types of access modifiers in Java, we have listed them as
follows:
Default (No keyword required)
Private
Protected
Public
🔐 1. private
The member is accessible only within the same class.
Not visible to other classes, not even subclasses.
class Example {
private int data = 10;
private void show() {
System.out.println("Private method");
}
}
✅ Use when you want to encapsulate and protect data.
👪 2. default (no specifier)
If no access specifier is mentioned, it's considered default.
Accessible only within the same package.
class Example {
int data = 20; // default access
void show() {
System.out.println("Default access");
}
}
✅ Use when you want to allow access within the same package only.
👨👩👧 3. protected
Accessible within the same package and also in subclasses (even if they are in different
packages).
class Example {
protected int data = 30;
protected void show() {
System.out.println("Protected method");
}
}
✅ Use when you want controlled inheritance with access in subclasses.
🌐 4. public
Accessible from any class in any package.
The least restrictive.
public class Example {
public int data = 40;
public void show() {
System.out.println("Public method");
}
}
✅ Use when you want maximum visibility, like public APIs.
Java Inheritance
In Java programming, the inheritance is an important of concept of Java OOPs. Inheritance is a
process where one class acquires the properties (methods and attributes) of another. With the use of
inheritance, the information is made manageable in a hierarchical order.
The class which inherits the properties of other is known as subclass (derived class, child class) and
the class whose properties are inherited is known as superclass (base class, parent class).
Need of Java Inheritance
Code Reusability: The basic need of an inheritance is to reuse the features. If you have defined some
functionality once, by using the inheritance you can easily use them in other classes and packages.
Extensibility: The inheritance helps to extend the functionalities of a class. If you have a base class with some
functionalities, you can extend them by using the inheritance in the derived class.
Implantation of Method Overriding: Inheritance is required to achieve one of the concepts of Polymorphism
which is Method overriding.
Achieving Abstraction: Another concept of OOPs that is abstraction also needs inheritance.
Implementation of Java Inheritance
To implement (use) inheritance in Java, the extends keyword is used. It inherits the properties
(attributes or/and methods) of the base class to the derived class. The word "extends" means to extend
functionalities i.e., the extensibility of the features.
Syntax to implement inheritance
Consider the below syntax to implement (use) inheritance in Java:
class Super {
.....
.....
class Sub extends Super {
.....
.....
Java Inheritance Example
Following is an example demonstrating Java inheritance. In this example, you can observe two
classes namely Calculation and My_Calculation.
Using extends keyword, the My_Calculation inherits the methods addition() and Subtraction() of
Calculation class.
Copy and paste the following program in a file with name My_Calculation.java
Java Program to Implement Inheritance
Open Compiler
class Calculation {
int z;
public void addition(int x, int y) {
z = x + y;
System.out.println("The sum of the given numbers:"+z);
public void Subtraction(int x, int y) {
z = x - y;
System.out.println("The difference between the given numbers:"+z);
public class My_Calculation extends Calculation {
public void multiplication(int x, int y) {
z = x * y;
System.out.println("The product of the given numbers:"+z);
public static void main(String args[]) {
int a = 20, b = 10;
My_Calculation demo = new My_Calculation();
demo.addition(a, b);
demo.Subtraction(a, b);
demo.multiplication(a, b);
javac My_Calculation.java
java My_Calculation
The sum of the given numbers:30
The difference between the given numbers:10
The product of the given numbers:200
In the given program, when an object to My_Calculation class is created, a copy of the contents of
the superclass is made within it. That is why, using the object of the subclass you can access the
members of a superclass.
The Superclass reference variable can hold the subclass object, but using that variable you can access
only the members of the superclass, so to access the members of both classes it is recommended to
always create reference variable to the subclass.
If you consider the above program, you can instantiate the class as given below. But using the
superclass reference variable ( cal in this case) you cannot call the method multiplication(), which
belongs to the subclass My_Calculation.
Calculation demo = new My_Calculation();
demo.addition(a, b);
demo.Subtraction(a, b);
Note − A subclass inherits all the members (fields, methods, and nested classes) from its superclass.
Constructors are not members, so they are not inherited by subclasses, but the constructor of the
superclass can be invoked from the subclass.
Java Inheritance: The super Keyword
The super keyword is similar to this keyword. Following are the scenarios where the super keyword
is used.
It is used to differentiate the members of superclass from the members of subclass, if they have same
names.
It is used to invoke the superclass constructor from subclass.
Differentiating the Members
If a class is inheriting the properties of another class. And if the members of the superclass have the
names same as the sub class, to differentiate these variables we use super keyword as shown below.
super.variable
super.method();
Sample Code
This section provides you a program that demonstrates the usage of the super keyword.
In the given program, you have two classes namely Sub_class and Super_class, both have a method
named display() with different implementations, and a variable named num with different values. We
are invoking display() method of both classes and printing the value of the variable num of both
classes. Here you can observe that we have used super keyword to differentiate the members of
superclass from subclass.
Copy and paste the program in a file with name Sub_class.java.
Example
Open Compiler
class Super_class {
int num = 20;
// display method of superclass
public void display() {
System.out.println("This is the display method of superclass");
}
public class Sub_class extends Super_class {
int num = 10;
// display method of sub class
public void display() {
System.out.println("This is the display method of subclass");
public void my_method() {
// Instantiating subclass
Sub_class sub = new Sub_class();
// Invoking the display() method of sub class
sub.display();
// Invoking the display() method of superclass
super.display();
// printing the value of variable num of subclass
System.out.println("value of the variable named num in sub class:"+ sub.num);
// printing the value of variable num of superclass
System.out.println("value of the variable named num in super class:"+ super.num);
public static void main(String args[]) {
Sub_class obj = new Sub_class();
obj.my_method();
}
}
Compile and execute the above code using the following syntax.
javac Super_Demo
java Super
On executing the program, you will get the following result −
Output
This is the display method of subclass
This is the display method of superclass
value of the variable named num in sub class:10
value of the variable named num in super class:20
Invoking Superclass Constructor
If a class is inheriting the properties of another class, the subclass automatically acquires the default
constructor of the superclass. But if you want to call a parameterized constructor of the superclass,
you need to use the super keyword as shown below.
super(values);
Sample Code
The program given in this section demonstrates how to use the super keyword to invoke the
parametrized constructor of the superclass. This program contains a superclass and a subclass, where
the superclass contains a parameterized constructor which accepts a integer value, and we used the
super keyword to invoke the parameterized constructor of the superclass.
Copy and paste the following program in a file with the name Subclass.java
Example
Open Compiler
Types of Java Inheritance
In Java, there are mainly three types of inheritances Single, Multilevel,
and Hierarchical. Java does not support Multiple and Hybrid inheritance.
Java ListIterator Interface
The ListIterator interface of the Java collections framework provides the
functionality to access elements of a list.
It is bidirectional. This means it allows us to iterate elements of a list in both the
direction.
It extends the Iterator interface.
The List interface provides a listIterator() method that returns an instance of the ListIterator interface.
Methods of ListIterator
The ListIterator interface provides methods that can be used to perform various operations on the elements
of a list.
hasNext() - returns true if there exists an element in the list
next() - returns the next element of the list
nextIndex() returns the index of the element that the next() method will return
previous() - returns the previous element of the list
previousIndex() - returns the index of the element that the previous() method will return
remove() - removes the element returned by either next() or previous()
set() - replaces the element returned by either next() or previous() with the specified element
Example 1: Implementation of ListIterator
In the example below, we have implemented the next(), nextIndex() and hasNext() methods of
the ListIterator interface in an array list.
import java.util.ArrayList;
import java.util.ListIterator;
class Main {
public static void main(String[] args) {
// Creating an ArrayList
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(3);
numbers.add(2);
System.out.println("ArrayList: " + numbers);
// Creating an instance of ListIterator
ListIterator<Integer> iterate = numbers.listIterator();
// Using the next() method
int number1 = iterate.next();
System.out.println("Next Element: " + number1);
// Using the nextIndex()
int index1 = iterate.nextIndex();
System.out.println("Position of Next Element: " + index1);
// Using the hasNext() method
System.out.println("Is there any next element? " + iterate.hasNext());
Run Code
Output
ArrayList: [1, 3, 2]
Next Element: 1
Position of Next Element: 1
Is there any next element? true
Java LinkedList
The LinkedList class of the Java collections framework provides the functionality
of the linked list data structure (doubly linkedlist).
Each element in a linked list is known as a node. It consists of 3 fields:
Prev - stores an address of the previous element in the list. It is null for the first element
Next - stores an address of the next element in the list. It is null for the last element
Data - stores the actual data
Creating a Java LinkedList
Here is how we can create linked lists in Java:
LinkedList<Type> linkedList = new LinkedList<>();
Here, Type indicates the type of a linked list. For example,
// create Integer type linked list
LinkedList<Integer> linkedList = new LinkedList<>();
// create String type linked list
LinkedList<String> linkedList = new LinkedList<>();
Example: Create LinkedList in Java
import java.util.LinkedList;
class Main {
public static void main(String[] args){
// create linkedlist
LinkedList<String> animals = new LinkedList<>();
// Add elements to LinkedList
animals.add("Dog");
animals.add("Cat");
animals.add("Cow");
System.out.println("LinkedList: " + animals);
Run Code
Output
LinkedList: [Dog, Cat, Cow]
Java TreeSet
The TreeSet class of the Java collections framework provides the functionality of a
tree data structure.
It extends the NavigableSet interface.
Creating a TreeSet
In order to create a tree set, we must import the java.util.TreeSet package first.
Once we import the package, here is how we can create a TreeSet in Java.
TreeSet<Integer> numbers = new TreeSet<>();
Here, we have created a TreeSet without any arguments. In this case, the elements in TreeSet are sorted
naturally (ascending order).
However, we can customize the sorting of elements by using the Comparator interface. We will learn about it
later in this tutorial.
Methods of TreeSet
The TreeSet class provides various methods that allow us to perform various operations on the set.
Insert Elements to TreeSet
add() - inserts the specified element to the set
addAll() - inserts all the elements of the specified collection to the set
For example,
import java.util.TreeSet;
class Main {
public static void main(String[] args) {
TreeSet<Integer> evenNumbers = new TreeSet<>();
// Using the add() method
evenNumbers.add(2);
evenNumbers.add(4);
evenNumbers.add(6);
System.out.println("TreeSet: " + evenNumbers);
TreeSet<Integer> numbers = new TreeSet<>();
numbers.add(1);
// Using the addAll() method
numbers.addAll(evenNumbers);
System.out.println("New TreeSet: " + numbers);
Run Code
Output
TreeSet: [2, 4, 6]
New TreeSet: [1, 2, 4, 6]
Remove Elements
remove() - removes the specified element from the set
removeAll() - removes all the elements from the set
Methods for Navigation
Since the TreeSet class implements NavigableSet , it provides various methods to
navigate over the elements of the tree set.
1. first() and last() Methods
first() - returns the first element of the set
last() - returns the last element of the set
2. ceiling(), floor(), higher() and lower() Methods
higher(element) - Returns the lowest element among those elements that are
greater than the specified element .
lower(element) - Returns the greatest element among those elements that are
less than the specified element .
ceiling(element) - Returns the lowest element among those elements that are
greater than the specified element . If the element passed exists in a tree set, it
returns the element passed as an argument.
floor(element) - Returns the greatest element among those elements that are
less than the specified element . If the element passed exists in a tree set, it returns
the element passed as an argument.
3. pollfirst() and pollLast() Methods
pollFirst() - returns and removes the first element from the set
pollLast() - returns and removes the last element from the set
4. headSet(), tailSet() and subSet() Methods
headSet(element, booleanValue)
The headSet() method returns all the elements of a tree set before the
specified element (which is passed as an argument).
The booleanValue parameter is optional. Its default value is false .
If true is passed as a booleanValue , the method returns all the elements before the
specified element including the specified element.
Other Methods of TreeSet
Method Description
clone() Creates a copy of the TreeSet
contains() Searches the TreeSet for the specified element and returns a boolean result
isEmpty() Checks if the TreeSet is empty
size() Returns the size of the TreeSet
clear() Removes all the elements from the TreeSet
Java PriorityQueue
The Java PriorityQueue class is an unbounded priority queue based on a priority heap.
Following are the important points about PriorityQueue −
The elements of the priority queue are ordered according to their natural ordering, or
by a Comparator provided at queue construction time, depending on which
constructor is used.
A priority queue does not permit null elements.
A priority queue relying on natural ordering also does not permit insertion of non-
comparable objects.
Class declaration
Following is the declaration for java.util.PriorityQueue class −
public class PriorityQueue<E>
extends AbstractQueue<E>
implements Serializable
Parameters
Following is the parameter for java.util.PriorityQueue class −
E − This is the type of elements held in this collection.
Class constructors
Sr.No. Constructor & Description
PriorityQueue()
1 This creates a PriorityQueue with the default initial capacity (11) that
orders its elements according to their natural ordering.
PriorityQueue(Collection<? extends E> c)
2 This creates a PriorityQueue containing the elements in the specified
collection.
PriorityQueue(int initialCapacity)
3 This creates a PriorityQueue with the specified initial capacity that orders
its elements according to their natural ordering.
PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
4 This creates a PriorityQueue with the specified initial capacity that orders
its elements according to the specified comparator.
PriorityQueue(PriorityQueue<? extends E> c)
5 This creates a PriorityQueue containing the elements in the specified
priority queue.
PriorityQueue(SortedSet<? extends E> c)
6 This creates a PriorityQueue containing the elements in the specified
sorted set.
Class methods
Sr.No. Method & Description
boolean add(E e)
1
This method inserts the specified element into this priority queue.
void clear()
2
This method removes all of the elements from this priority queue.
Comparator<? super E> comparator()
3 This method returns the comparator used to order the elements in this
queue, or null if this queue is sorted according to the natural ordering of
its elements.
boolean contains(Object o)
4
This method returns true if this queue contains the specified element.
void forEach(Consumer<? super E> action)
5 This method performs the given action for each element of the Iterable
until all elements have been processed or the action throws an
exception.
Iterator<E> iterator()
6
This method returns an iterator over the elements in this queue.
boolean offer(E e)
7
This method inserts the specified element into this priority queue.
boolean remove(Object o)
8
This method removes a single instance of the specified element from
this queue, if it is present.
boolean removeAll(Collection<?> c)
9
This method removes all of this collection's elements that are also
contained in the specified collection (optional operation).
boolean removeIf(Predicate<? super E> filter)
10
This method removes all of the elements of this collection that satisfy
the given predicate.
boolean retainAll(Collection<?> c)
11
This method retains only the elements in this collection that are
contained in the specified collection (optional operation).
Spliterator<E> spliterator()
12
This method creates a late-binding and fail-fast Spliterator over the
elements in this queue.
<T> T[] toArray(T[] a)
13 This method returns an array containing all of the elements in this
queue; the runtime type of the returned array is that of the specified
array.
Methods inherited
This class inherits methods from the following classes −
java.util.AbstractQueue
java.util.AbstractCollection
java.util.Object
java.util.Collection
Adding an Item to a Priority Queue Example
The following example shows the usage of Java PriorityQueue add(E) method to add
Integers. We're adding couple of Integers to the PriorityQueue object using add()
method calls per element and then print each element to show the elements added.
import java.util.PriorityQueue;
public class PriorityQueueDemo {
public static void main(String[] args) {
// create an empty priority queue with an initial capacity
PriorityQueue<Integer> queue = new PriorityQueue<>(5);
// use add() method to add elements in the queue
queue.add(20);
queue.add(30);
queue.add(20);
queue.add(30);
queue.add(15);
queue.add(22);
queue.add(11);
// let us print all the elements available in queue
for (Integer number : queue) {
System.out.println("Number = " + number);
Let us compile and run the above program, this will produce the following result −
Number = 11
Number = 20
Number = 15
Number = 30
Number = 30
Number = 22
Number = 20
Comparable and Comparator
✅ Comparable (java.lang.Comparable)
Purpose: Defines the natural ordering of objects.
How: You implement the Comparable<T> interface and override the compareTo() method in
your class.
Used when: The object knows how to compare itself with another object of the same type.
Example:
public class Student implements Comparable<Student> {
int id;
String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public int compareTo(Student other) {
return this.id - other.id; // sort by id
}
}
Then you can sort like this:
Collections.sort(studentList); // uses compareTo()
✅ Comparator (java.util.Comparator)
Purpose: Defines custom orderings, external to the object.
How: You create a separate class (or use lambda/anonymous class) that implements
Comparator<T> and overrides compare().
Used when: You want multiple ways to compare objects, or don’t want to modify the class
you're sorting.
Example:
class NameComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
return s1.name.compareTo(s2.name);
}
}
Then:
Collections.sort(studentList, new NameComparator());
Or, using lambdas (Java 8+):
studentList.sort((s1, s2) -> s1.name.compareTo(s2.name));
✅ What is the Properties class?
It's part of java.util.
Basically a subclass of Hashtable<Object, Object>, but it's specifically used to manage
key-value pairs where both keys and values are Strings.
Commonly used to read/write configuration files like .properties files.
✅ Typical Use Cases
Storing app settings (e.g. database URL, username, password).
Loading configurations from .properties files.
Writing updated settings back to a file.
✅ Basic Example: Loading Properties from a File
Let's say you have a file called config.properties:
db.url=jdbc:mysql://localhost:3306/mydb
db.user=root
db.password=12345
Java code to load it:
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class ConfigLoader {
public static void main(String[] args) {
Properties props = new Properties();
try (FileInputStream fis = new FileInputStream("config.properties")) {
props.load(fis);
String url = props.getProperty("db.url");
String user = props.getProperty("db.user");
String password = props.getProperty("db.password");
System.out.println("URL: " + url);
System.out.println("User: " + user);
System.out.println("Password: " + password);
} catch (IOException e) {
e.printStackTrace();
}
}
}
✅ Storing/Writing Properties to a File
You can also create or modify properties and save them:
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class SaveProperties {
public static void main(String[] args) {
Properties props = new Properties();
props.setProperty("app.name", "MyCoolApp");
props.setProperty("app.version", "1.0");
try (FileOutputStream fos = new FileOutputStream("app.properties")) {
props.store(fos, "App Settings");
} catch (IOException e) {
e.printStackTrace();
}
}
}
lambda expressions
Lambda expression is, essentially, an anonymous or unnamed method. The
lambda expression does not execute on its own. Instead, it is used to implement a
method defined by a functional interface.
How to define lambda expression in Java?
Here is how we can define lambda expression in Java.
(parameter list) -> lambda body
The new operator ( -> ) used is known as an arrow operator or a lambda operator.
The syntax might not be clear at the moment. Let's explore some examples,
Suppose, we have a method like this:
double getPiValue() {
return 3.1415;
}
We can write this method using lambda expression as:
() -> 3.1415
Here, the method does not have any parameters. Hence, the left side of the
operator includes an empty parameter. The right side is the lambda body that
specifies the action of the lambda expression. In this case, it returns the value
Types of Lambda Body
In Java, the lambda body is of two types.
1. A body with a single expression
() -> System.out.println("Lambdas are great");
This type of lambda body is known as the expression body.
2. A body that consists of a block of code.
() -> {
double pi = 3.1415;
return pi;
};
This type of the lambda body is known as a block body. The block body allows the
lambda body to include multiple statements. These statements are enclosed
inside the braces and you have to add a semi-colon after the braces.
Note: For the block body, you can have a return statement if the body returns a
value. However, the expression body does not require a return statement.
Example 3: Lambda Expression
Let's write a Java program that returns the value of Pi using the lambda
expression.
As mentioned earlier, a lambda expression is not executed on its own. Rather, it
forms the implementation of the abstract method defined by the functional
interface.
So, we need to define a functional interface first.
import java.lang.FunctionalInterface;
// this is functional interface
@FunctionalInterface
interface MyInterface{
// abstract method
double getPiValue();
}
public class Main {
public static void main( String[] args ) {
// declare a reference to MyInterface
MyInterface ref;
// lambda expression
ref = () -> 3.1415;
System.out.println("Value of Pi = " + ref.getPiValue());
}
}
Run Code
Output:
Value of Pi = 3.1415
In the above example,
We have created a functional interface named MyInterface . It contains a single
abstract method named getPiValue()
Inside the Main class, we have declared a reference to MyInterface . Note that we
can declare a reference of an interface but we cannot instantiate an interface.
That is,
// it will throw an error
MyInterface ref = new myInterface();
// it is valid
MyInterface ref;
We then assigned a lambda expression to the reference.
ref = () -> 3.1415;
Finally, we call the method getPiValue() using the reference interface. When
System.out.println("Value of Pi = " + ref.getPiValue());
Lambda Expressions with parameters
Till now we have created lambda expressions without any parameters. However,
similar to methods, lambda expressions can also have parameters. For example,
(n) -> (n%2)==0
Life Cycle of a Thread in Java
The life cycle of a thread in Java refers to the various states of a thread goes
through. For example, a thread is born, started, runs, and then dies. Thread
class defines the life cycle and various states of a thread.
Flow Chart of Java Thread Life Cycle
The following diagram shows the complete life cycle of a thread.
States of a Thread Life Cycle in Java
Following are the stages of the life cycle −
New − A new thread begins its life cycle in the new state. It remains in this state until
the program starts the thread. It is also referred to as a born thread.
Runnable − After a newly born thread is started, the thread becomes runnable. A
thread in this state is considered to be executing its task.
Waiting − Sometimes, a thread transitions to the waiting state while the thread waits
for another thread to perform a task. A thread transitions back to the runnable state
only when another thread signals the waiting thread to continue executing.
Timed Waiting − A runnable thread can enter the timed waiting state for a specified
interval of time. A thread in this state transitions back to the runnable state when
that time interval expires or when the event it is waiting for occurs.
Terminated (Dead) − A runnable thread enters the terminated state when it completes
its task or otherwise terminates.
Java Example for Demonstrating Thread States
In this example, we're creating two threads by extending the Thread class. We're
printing each state of the thread. When a thread object is created, its state is NEW;
when start() method is called, state is START; when run() method is called, state is
RUNNING; When a thread finished the processing the run() method, it went to
DEAD state.
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo( String name) {
threadName = name;
System.out.println("Thread: " + threadName + ", " + "State: New");
public void run() {
System.out.println("Thread: " + threadName + ", " + "State: Running");
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
System.out.println("Thread: " + threadName + ", " + "State: Dead");
public void start () {
System.out.println("Thread: " + threadName + ", " + "State: Start");
if (t == null) {
t = new Thread (this, threadName);
t.start ();
public class TestThread {
public static void main(String args[]) {
ThreadDemo thread1 = new ThreadDemo( "Thread-1");
ThreadDemo thread2 = new ThreadDemo( "Thread-2");
thread1.start();
thread2.start();
}
Output
Thread: Thread-1, State: New
Thread: Thread-2, State: New
Thread: Thread-1, State: Start
Thread: Thread-2, State: Start
Thread: Thread-1, State: Running
Thread: Thread-2, State: Running
Thread: Thread-2, 4
Thread: Thread-2, 3
Thread: Thread-2, 2
Thread: Thread-2, 1
Thread: Thread-2, State: Dead
Thread: Thread-1, 4
Thread: Thread-1, 3
Thread: Thread-1, 2
Thread: Thread-1, 1
Thread: Thread-1, State: Dead
🔁 1. Suspending and Resuming Threads in Java
🚫 Deprecated Approach (Dangerous)
Java used to offer methods like Thread.suspend() and Thread.resume(), but they are now
deprecated because they could lead to deadlocks and thread starvation.
Thread t = new Thread(() -> {
while (true) {
System.out.println("Running...");
}
});
t.start();
t.suspend(); // ❌ Deprecated
t.resume(); // ❌ Deprecated
❗ These methods can leave locks held, and prevent other threads from making progress.
✅ Safe Approach Using a Volatile Flag with wait()/notify()
class ControlledThread extends Thread {
private volatile boolean suspended = false;
public void run() {
while (true) {
synchronized (this) {
while (suspended) {
try {
wait(); // Thread waits here
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Interrupted while suspended");
return;
}
}
}
// Simulated task
System.out.println("Thread is working...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Thread interrupted during work.");
return;
}
}
}
public synchronized void suspendThread() {
suspended = true;
}
public synchronized void resumeThread() {
suspended = false;
notify();
}
}
✅ Usage:
public class Main {
public static void main(String[] args) throws InterruptedException {
ControlledThread t = new ControlledThread();
t.start();
Thread.sleep(3000);
t.suspendThread();
System.out.println("Thread suspended.");
Thread.sleep(3000);
t.resumeThread();
System.out.println("Thread resumed.");
}
}
❌ 2. Stopping Threads in Java
🚫 Deprecated Method: Thread.stop()
Thread t = new Thread(() -> {
while (true) {
// Doing work
}
});
t.start();
t.stop(); // ❌ Dangerous!
❗ Stops the thread immediately, potentially leaving shared resources in an inconsistent state.
✅ Safe Way: Using a Volatile Flag
class StoppableThread extends Thread {
private volatile boolean running = true;
public void run() {
while (running) {
System.out.println("Thread running safely...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Interrupted!");
break;
}
}
System.out.println("Thread exiting gracefully.");
}
public void stopThread() {
running = false;
}
}
✅ Usage:
public class Main {
public static void main(String[] args) throws InterruptedException {
StoppableThread t = new StoppableThread();
t.start();
Thread.sleep(2000);
t.stopThread(); // Signal to stop
}
}
✅ Alternative Way: Using interrupt()
class InterruptExample extends Thread {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Working...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println("Thread was interrupted!");
break;
}
}
}
}
✅ Usage:
InterruptExample t = new InterruptExample();
t.start();
Thread.sleep(2000);
t.interrupt(); // Gracefully stop
🔒 3. Deadlock in Java
💥 What is Deadlock?
Deadlock happens when two or more threads are waiting for each other to release a resource, and
none of them can proceed.
� Deadlock Example in Java
class A {
synchronized void methodA(B b) {
System.out.println("Thread-1: Holding lock on A...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("Thread-1: Waiting for lock on B...");
b.last(); // tries to get lock on B
}
synchronized void last() {
System.out.println("Inside A.last()");
}
}
class B {
synchronized void methodB(A a) {
System.out.println("Thread-2: Holding lock on B...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("Thread-2: Waiting for lock on A...");
a.last(); // tries to get lock on A
}
synchronized void last() {
System.out.println("Inside B.last()");
}
}
public class DeadlockDemo {
public static void main(String[] args) {
A a = new A();
B b = new B();
new Thread(() -> a.methodA(b)).start();
new Thread(() -> b.methodB(a)).start();
}
}
🛑 Output (Typical):
Thread-1: Holding lock on A...
Thread-2: Holding lock on B...
Thread-1: Waiting for lock on B...
Thread-2: Waiting for lock on A...
Both threads are now stuck → deadlock.
✅ Preventing Deadlocks
🔐 1. Lock Ordering
Always acquire multiple locks in the same order.
class Safe {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void method1() {
synchronized (lock1) {
synchronized (lock2) {
// Safe
}
}
}
public void method2() {
synchronized (lock1) { // Same order as method1
synchronized (lock2) {
// Safe
}
}
}
}
🔄 2. Using ReentrantLock.tryLock() with Timeout
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;
class SafeLock {
private final Lock lock1 = new ReentrantLock();
private final Lock lock2 = new ReentrantLock();
public void doWork() {
try {
if (lock1.tryLock(50, TimeUnit.MILLISECONDS)) {
try {
if (lock2.tryLock(50, TimeUnit.MILLISECONDS)) {
try {
// Safe critical section
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
☠️ What Happens When an Exception Is Thrown in a Thread?
If an exception (like NullPointerException, IOException, etc.) is thrown inside a thread and not
caught, it will terminate that thread—but not the entire program (unless it’s the main thread or
you're relying on the thread to complete a critical task).
✅ How to Handle Exceptions in Threads
1. Handle Exceptions Within the Thread Itself
The simplest and safest way is to wrap your thread logic in a try-catch block.
class MyThread extends Thread {
public void run() {
try {
// Thread logic
System.out.println("Thread running...");
int result = 10 / 0; // This will cause ArithmeticException
} catch (Exception e) {
System.out.println("Exception caught in thread: " + e);
}
}
}
2. Use UncaughtExceptionHandler
Java provides a way to catch exceptions that were not caught inside the thread itself using
Thread.UncaughtExceptionHandler.
class MyThread extends Thread {
public void run() {
System.out.println("Thread will throw exception...");
throw new RuntimeException("Oops!");
}
}
public class Main {
public static void main(String[] args) {
MyThread t = new MyThread();
t.setUncaughtExceptionHandler((thread, ex) -> {
System.out.println("Caught exception from thread: " +
thread.getName() + " - " + ex.getMessage());
});
t.start();
}
}
This is useful for logging or alerting when something goes wrong unexpectedly in background
threads.
3. Handling Exceptions in Thread Pools (Executors)
If you're using ExecutorService (e.g., via Executors.newFixedThreadPool()), exceptions are
wrapped in the Future object. You have to explicitly call get() to retrieve the exception.
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(() -> {
throw new RuntimeException("Error inside task!");
});
try {
future.get(); // this will throw ExecutionException
} catch (ExecutionException e) {
System.out.println("Caught: " + e.getCause()); // e.getCause() gives the
actual exception
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
✅ Tip: Always check exceptions from submitted tasks via Future.
4. Custom ThreadFactory (Advanced Use)
You can use a custom ThreadFactory to apply a common UncaughtExceptionHandler to all
threads created by an ExecutorService.
ThreadFactory factory = runnable -> {
Thread t = new Thread(runnable);
t.setUncaughtExceptionHandler((th, ex) -> {
System.out.println("Handled in factory: " + ex.getMessage());
});
return t;
};
ExecutorService executor = Executors.newFixedThreadPool(2, factory);
executor.submit(() -> {
throw new RuntimeException("Boom!");
});
☑️ JButton — Push Button
Used to perform an action when clicked.
🔹 Example:
import javax.swing.*;
public class JButtonExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JButton Example");
JButton button = new JButton("Click Me");
button.addActionListener(e -> JOptionPane.showMessageDialog(frame,
"Button Clicked!"));
frame.add(button);
frame.setSize(300, 200);
frame.setLayout(null);
button.setBounds(100, 80, 100, 30);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
🔘 JRadioButton — Radio Button
Allows single selection among a group.
🔹 Example:
import javax.swing.*;
public class JRadioButtonExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JRadioButton Example");
JRadioButton rb1 = new JRadioButton("Male");
JRadioButton rb2 = new JRadioButton("Female");
rb1.setBounds(100, 50, 100, 30);
rb2.setBounds(100, 80, 100, 30);
ButtonGroup group = new ButtonGroup(); // Group to allow single
selection
group.add(rb1);
group.add(rb2);
frame.add(rb1);
frame.add(rb2);
frame.setSize(300, 200);
frame.setLayout(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
📝 JTextArea — Multi-line Text Input
Allows input/output of multiple lines of text.
🔹 Example:
import javax.swing.*;
public class JTextAreaExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JTextArea Example");
JTextArea area = new JTextArea("Type something here...");
area.setBounds(50, 50, 200, 100);
frame.add(area);
frame.setSize(300, 250);
frame.setLayout(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
📑 JComboBox — Drop-down Menu
Provides a menu with selectable items.
🔹 Example:
import javax.swing.*;
public class JComboBoxExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JComboBox Example");
String[] courses = {"Java", "Python", "C++", "Kotlin"};
JComboBox<String> comboBox = new JComboBox<>(courses);
comboBox.setBounds(50, 50, 150, 30);
frame.add(comboBox);
frame.setSize(300, 200);
frame.setLayout(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
📊 JTable — Displaying Tabular Data
Displays data in a grid format (rows and columns).
🔹 Example:
import javax.swing.*;
public class JTableExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JTable Example");
String[][] data = {
{"101", "Alice", "90"},
{"102", "Bob", "85"},
{"103", "Charlie", "95"}
};
String[] column = {"ID", "Name", "Marks"};
JTable table = new JTable(data, column);
JScrollPane sp = new JScrollPane(table);
sp.setBounds(20, 20, 250, 100);
frame.add(sp);
frame.setSize(300, 200);
frame.setLayout(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
🎨 JColorChooser — Color Picker Dialog
Allows users to pick a color from a palette.
🔹 Example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class JColorChooserExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JColorChooser Example");
JButton button = new JButton("Choose Color");
JLabel label = new JLabel("Color will appear here");
label.setBounds(50, 100, 200, 30);
button.setBounds(50, 50, 150, 30);
button.addActionListener(e -> {
Color color = JColorChooser.showDialog(frame, "Pick a Color",
Color.white);
if (color != null) {
label.setForeground(color);
}
});
frame.add(button);
frame.add(label);
frame.setSize(300, 200);
frame.setLayout(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
📊 JProgressBar — Visual Progress Indicator
Displays task progress (e.g., loading, downloading).
🔹 Example:
import javax.swing.*;
public class JProgressBarExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JProgressBar Example");
JProgressBar progressBar = new JProgressBar(0, 100);
progressBar.setBounds(50, 50, 200, 30);
progressBar.setValue(0);
progressBar.setStringPainted(true); // Shows percentage
frame.add(progressBar);
frame.setSize(300, 150);
frame.setLayout(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
// Simulate progress
for (int i = 0; i <= 100; i++) {
try {
Thread.sleep(50); // delay
progressBar.setValue(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
🎚️ JSlider — Value Slider (Horizontal/Vertical)
Lets the user choose a numeric value by sliding a knob.
🔹 Example:
import javax.swing.*;
import javax.swing.event.*;
public class JSliderExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JSlider Example");
JLabel label = new JLabel("Value: 50");
label.setBounds(100, 100, 200, 30);
JSlider slider = new JSlider(0, 100, 50); // min, max, initial value
slider.setBounds(50, 50, 200, 40);
slider.setMajorTickSpacing(25);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(e -> label.setText("Value: " +
slider.getValue()));
frame.add(slider);
frame.add(label);
frame.setSize(300, 200);
frame.setLayout(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
📦 What is a Layout Manager?
A layout manager is an object that determines the size and position of components within a
container. It automates the placement of UI components so you don’t have to manually set
setBounds().
You set the layout using:
container.setLayout(new LayoutManagerType());
🌐 1. BorderLayout (Default for JFrame)
Divides the container into 5 regions:
NORTH
SOUTH
EAST
WEST
CENTER
🔹 Example:
import javax.swing.*;
import java.awt.*;
public class BorderLayoutExample {
public static void main(String[] args) {
JFrame frame = new JFrame("BorderLayout");
frame.setLayout(new BorderLayout());
frame.add(new JButton("North"), BorderLayout.NORTH);
frame.add(new JButton("South"), BorderLayout.SOUTH);
frame.add(new JButton("East"), BorderLayout.EAST);
frame.add(new JButton("West"), BorderLayout.WEST);
frame.add(new JButton("Center"), BorderLayout.CENTER);
frame.setSize(400, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
🔲 2. GridLayout
Divides container into a grid of rows and columns, and all components get equal size.
🔹 Example:
import javax.swing.*;
import java.awt.*;
public class GridLayoutExample {
public static void main(String[] args) {
JFrame frame = new JFrame("GridLayout");
frame.setLayout(new GridLayout(2, 3)); // 2 rows, 3 columns
for (int i = 1; i <= 6; i++) {
frame.add(new JButton("Button " + i));
}
frame.setSize(400, 200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
➡️ 3. FlowLayout
Places components left to right, like words in a sentence, wrapping to next line as needed. It's the
default for JPanel.
🔹 Example:
import javax.swing.*;
import java.awt.*;
public class FlowLayoutExample {
public static void main(String[] args) {
JFrame frame = new JFrame("FlowLayout");
frame.setLayout(new FlowLayout(FlowLayout.LEFT)); // LEFT, CENTER, RIGHT
for (int i = 1; i <= 5; i++) {
frame.add(new JButton("Button " + i));
}
frame.setSize(300, 200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
📦 4. BoxLayout
Lays out components in a single row (X_AXIS) or a single column (Y_AXIS).
🔹 Example (Vertical Layout):
import javax.swing.*;
import java.awt.*;
public class BoxLayoutExample {
public static void main(String[] args) {
JFrame frame = new JFrame("BoxLayout");
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); // vertical
panel.add(new JButton("Button 1"));
panel.add(Box.createRigidArea(new Dimension(0, 10))); // spacer
panel.add(new JButton("Button 2"));
panel.add(new JButton("Button 3"));
frame.add(panel);
frame.setSize(200, 200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
🃏 5. CardLayout
Like a deck of cards—only one component is visible at a time. Used in wizards, tabbed UIs, etc.
🔹 Example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class CardLayoutExample {
public static void main(String[] args) {
JFrame frame = new JFrame("CardLayout");
CardLayout card = new CardLayout();
JPanel cardPanel = new JPanel(card);
JPanel card1 = new JPanel();
card1.add(new JLabel("This is Card 1"));
JPanel card2 = new JPanel();
card2.add(new JLabel("This is Card 2"));
cardPanel.add(card1, "Card1");
cardPanel.add(card2, "Card2");
JButton switchBtn = new JButton("Switch Card");
switchBtn.addActionListener(e -> card.next(cardPanel));
frame.setLayout(new BorderLayout());
frame.add(cardPanel, BorderLayout.CENTER);
frame.add(switchBtn, BorderLayout.SOUTH);
frame.setSize(300, 200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
🔌 Introduction to JDBC
JDBC (Java Database Connectivity) is an API that enables Java applications to interact with
databases using SQL queries. It acts as a bridge between a Java program and a database.
🔧 JDBC Workflow (Steps):
1. Load JDBC driver
2. Establish a connection
3. Create a statement
4. Execute SQL query
5. Process the result
6. Close the connection
� Basic Example: JDBC with MySQL
import java.sql.*;
public class JdbcExample {
public static void main(String[] args) {
try {
// 1. Load driver
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. Connect to DB
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/testdb", "root", "yourpassword");
// 3. Create Statement
Statement stmt = con.createStatement();
// 4. Execute Query
ResultSet rs = stmt.executeQuery("SELECT * FROM students");
// 5. Process Result
while (rs.next()) {
System.out.println(rs.getInt(1) + " " + rs.getString(2));
}
// 6. Close connection
con.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
Make sure:
MySQL is running
You have a database named testdb
Table students exists
JDBC driver (mysql-connector-java) is in your classpath
⚙️ CRUD Operations (Create, Read, Update, Delete)
Let’s look at how to do each using PreparedStatement (safer and prevents SQL injection):
1�⃣ Create (INSERT)
PreparedStatement ps = con.prepareStatement("INSERT INTO students VALUES (?,
?)");
ps.setInt(1, 101);
ps.setString(2, "Alice");
ps.executeUpdate();
2�⃣ Read (SELECT)
PreparedStatement ps = con.prepareStatement("SELECT * FROM students");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt(1) + " " + rs.getString(2));
}
3�⃣ Update
PreparedStatement ps = con.prepareStatement("UPDATE students SET name=? WHERE
id=?");
ps.setString(1, "Bob");
ps.setInt(2, 101);
ps.executeUpdate();
4�⃣ Delete
PreparedStatement ps = con.prepareStatement("DELETE FROM students WHERE id=?");
ps.setInt(1, 101);
ps.executeUpdate();
🔌 Connection Interface
The Connection interface represents a session with a specific database. It's part of java.sql.
🔑 Key Methods:
Method Description
createStatement() Creates a basic SQL statement
prepareStatement(String sql) Creates a precompiled SQL statement
close() Closes the connection
commit() Commits a transaction
rollback() Rolls back a transaction
You're on a roll! Let's get into Java Networking, especially the key terminology, the Socket classes,
and how to create client-server communication using Socket and ServerSocket.
🌐 Java Network Terminology
Term Meaning
IP Address Unique number to identify a device on a network
A logical channel between client and server for communication (e.g., port
Port
80 for HTTP)
Protocol Set of rules for communication (e.g., TCP, UDP, HTTP)
TCP (Transmission Control
Reliable, connection-based communication
Protocol)
UDP (User Datagram Protocol) Fast, connectionless, but unreliable
Socket Endpoint for sending/receiving data between machines
Client Program that requests data
Server Program that listens and responds to clients
🔌 Socket Classes in Java
Java provides the java.net package for networking.
🔹 Socket Class (Client Side)
Used by the client to connect to a server.
Constructor:
Socket s = new Socket("localhost", 6666);
🔹 ServerSocket Class (Server Side)
Listens for incoming connections.
Constructor:
ServerSocket ss = new ServerSocket(6666);
� Basic Client-Server Example (TCP)
🖥� Server Program:
import java.io.*;
import java.net.*;
public class MyServer {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(6666); // server on port 6666
Socket s = ss.accept(); // waits for client
DataInputStream dis = new DataInputStream(s.getInputStream());
String str = dis.readUTF();
System.out.println("Client says: " + str);
ss.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
💻 Client Program:
import java.io.*;
import java.net.*;
public class MyClient {
public static void main(String[] args) {
try {
Socket s = new Socket("localhost", 6666);
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF("Hello Server");
dos.flush();
dos.close();
s.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
️ Pro Tip: Run the server first, then the client, or the client won’t find the server.
📚 Important Methods and Classes
🔑 Socket Class (Client):
Method Description
getInputStream() Reads from server
getOutputStream() Sends data to server
close() Closes socket
🔑 ServerSocket Class (Server):
Method Description
accept() Waits for a client to connect
close() Closes the server socket
Great! You're covering all the key areas of Java Networking. Let’s break it down:
🌐 URL Class — Handling Web Addresses
The URL class in java.net is used to handle Uniform Resource Locators, like web addresses.
🔹 Example:
import java.net.*;
import java.io.*;
public class URLExample {
public static void main(String[] args) throws Exception {
URL url = new URL("https://example.com");
System.out.println("Protocol: " + url.getProtocol());
System.out.println("Host: " + url.getHost());
System.out.println("File: " + url.getFile());
System.out.println("Port: " + url.getPort());
}
}
🔗 URLConnection Class — Reading from Web Resources
The URLConnection class helps open connections and read data from a URL.
🔹 Example: Reading HTML from a Website
import java.net.*;
import java.io.*;
public class URLConnectionExample {
public static void main(String[] args) throws Exception {
URL url = new URL("https://example.com");
URLConnection conn = url.openConnection();
BufferedReader br = new BufferedReader(new
InputStreamReader(conn.getInputStream()));
String inputLine;
while ((inputLine = br.readLine()) != null) {
System.out.println(inputLine);
}
br.close();
}
}
📤📥 DatagramSocket & DatagramPacket — UDP Programming
Unlike TCP, UDP is faster but unreliable and uses DatagramSocket and DatagramPacket.
🖥� Server: DatagramSocket Example
import java.net.*;
public class UDPServer {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket(3000);
byte[] buffer = new byte[1024];
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
ds.receive(dp); // Wait for packet
String msg = new String(dp.getData(), 0, dp.getLength());
System.out.println("Client says: " + msg);
ds.close();
}
}
💻 Client:
import java.net.*;
public class UDPClient {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
String str = "Hello UDP Server";
InetAddress ip = InetAddress.getByName("localhost");
DatagramPacket dp = new DatagramPacket(str.getBytes(), str.length(), ip,
3000);
ds.send(dp);
ds.close();
}
}
🔌 Java Socket Programming (TCP Recap)
TCP is reliable and connection-based.
� Server (Recap from before):
ServerSocket ss = new ServerSocket(6666);
Socket s = ss.accept(); // Waits for client
💬 Client:
Socket s = new Socket("localhost", 6666);
🔧 When to Use Which
Class / Concept Use For
Socket / ServerSocket Reliable 2-way connection (TCP)
Class / Concept Use For
DatagramSocket Fast, connectionless communication (UDP)
URL / URLConnection Accessing websites or APIs