Core Java Best Practices
If you're preparing for interviews or want to strengthen your Core Java knowledge, here are
the most important topics to focus on:
1. Java Basics
Features of Java
JDK, JRE, and JVM
Data Types, Variables, and Operators
Type Casting (Widening & Narrowing)
Control Statements (if-else, switch, loops)
2. OOPs (Object-Oriented Programming)
Four Pillars of OOP:
Encapsulation
Inheritance
Polymorphism (Method Overloading & Overriding)
Abstraction (Interfaces & Abstract Classes)
Other OOP Concepts:
this and super keywords
final keyword (class, method, variable)
Static vs Non-static members
Access Modifiers (private, protected, public, default)
1/5
3. Strings
String Pool, Immutability
String Manipulation ( String , StringBuilder , StringBuffer )
Important String Methods
String Comparisons ( == , .equals() , .compareTo() )
4. Arrays and Collections Framework (Java.util)
Arrays: Declaration, Initialization, Multi-Dimensional Arrays
Collections Framework:
List ( ArrayList , LinkedList , Vector )
Set ( HashSet , TreeSet , LinkedHashSet )
Map ( HashMap , TreeMap , LinkedHashMap )
Queue ( PriorityQueue , Deque )
Comparable vs Comparator
5. Exception Handling
Types of Exceptions (Checked, Unchecked)
try , catch , finally , throw , throws
Custom Exceptions
6. Multithreading & Concurrency
Thread Lifecycle
Creating Threads ( Thread class, Runnable interface)
2/5
Synchronization (Locks, synchronized keyword)
Deadlock and Thread Communication
7. File Handling (Java I/O)
File Reading & Writing ( FileReader , FileWriter , BufferedReader , BufferedWriter )
Serialization & Deserialization
8. Java 8 Features
Functional Interfaces & Lambda Expressions
Stream API
Method References
Default & Static Methods in Interfaces
Optional Class
9. JDBC (Java Database Connectivity)
Steps to connect Java with a Database
JDBC Drivers
CRUD Operations with JDBC
10. Design Patterns (Basic Understanding)
Singleton Pattern
Factory Pattern
3/5
Builder Pattern
Observer Pattern
11. Memory Management & Garbage Collection
Stack vs Heap Memory
Garbage Collection Mechanisms
Weak References & Soft References
12. Reflection API & Annotations
@Override , @FunctionalInterface , @SuppressWarnings , @Deprecated
Creating Custom Annotations
13. Inner Classes
Regular Inner Class
Static Nested Class
Anonymous Inner Class
Local Inner Class
14. Java Networking
Sockets & HTTP Communication
URL & URLConnection
4/5
15. Java Security
Hashing (MD5, SHA)
Encryption & Decryption (AES, RSA)
16. Java Interview-Specific Topics
Difference Between:
== vs .equals()
StringBuffer vs StringBuilder
ArrayList vs LinkedList
HashMap vs Hashtable
final , finally , finalize
Common Coding Questions:
Fibonacci Series
Palindrome String/Number
Sorting Algorithms (Bubble, Quick, Merge)
Find Duplicates in Array
Reverse a String
Next Steps?
Let me know if you need in-depth explanations on any of these topics! 😊
5/5
Core Java Best Practices
1. Java Basics
1.1 Introduction to Java
Java is a high-level, object-oriented programming language developed by Sun
Microsystems in 1995 and later acquired by Oracle Corporation. It is platform-independent
and widely used for building enterprise applications, mobile apps, and web applications.
Why Java?
✔ Write Once, Run Anywhere (WORA) – Java applications can run on any platform with a
JVM.
✔ Robust and Secure – Java provides strong memory management and built-in security
features.
✔ Multithreading Support – Java can execute multiple tasks simultaneously.
✔ Rich API & Libraries – Comes with a vast set of prebuilt functions.
2. Features of Java
1️⃣ Platform Independence
Java code is compiled into bytecode, which can run on any OS with a JVM (Java Virtual
Machine).
Example:
java
System.out.println("Java is platform-independent!");
2️⃣ Object-Oriented
Java follows OOP principles: Encapsulation, Inheritance, Polymorphism, and Abstraction.
3️⃣ Automatic Memory Management
1/8
Java has Garbage Collection, which automatically removes unused objects.
4️⃣ Multithreading
Java supports multithreading, allowing efficient CPU utilization.
5️⃣ Secure
Java does not use pointers, reducing vulnerabilities.
It provides bytecode verification and runtime security checks.
6️⃣ Rich Standard Library
Java comes with extensive libraries such as Collections, JDBC, Networking, I/O, etc..
3. JDK, JRE, and JVM
Component Description
JDK (Java Development Kit) Includes JRE + development tools (compiler, debugger) to develop
Java programs.
JRE (Java Runtime Contains JVM + libraries required to run Java applications.
Environment)
JVM (Java Virtual Machine) Converts bytecode into machine code for execution on different
platforms.
Execution Flow:
1️⃣ Java Source Code ( ) .java
➡ Compiled by javaccompiler
2️⃣ Bytecode ( file)
.class
➡ Executed by JVM ( java command)
Example:
sh
javac HelloWorld.java # Compile
2/8
java HelloWorld # Run
4. Data Types, Variables, and
Operators
4.1 Data Types in Java
Java has two categories of data types:
Data Type Category Example
Primitive Basic types int , char , double , boolean
Non-Primitive Objects String , Array , Class , Interface
Primitive Data Types
Data Type Size Default Value Example
byte 1 byte 0 byte b = 100;
short 2 bytes 0 short s = 32000;
int 4 bytes 0 int i = 100000;
long 8 bytes 0L long l = 9999999999L;
float 4 bytes 0.0f float f = 10.5f;
double 8 bytes 0.0d double d = 99.99;
char 2 bytes '\u0000' char c = 'A';
boolean 1 bit false boolean flag = true;
Non-Primitive Data Types
Example: String , Array , Class , Interface
java
String name = "Java";
int[] numbers = {1, 2, 3};
3/8
4.2 Variables in Java
A variable is a name given to a memory location that stores data.
Types of Variables
Type Scope Example
Local Variable Inside method/block int age = 25;
Instance Variable Inside a class but outside a method String name;
Static Variable Shared among all objects static int count;
Example:
java
class Example {
int instanceVar = 10; // Instance Variable
static int staticVar = 20; // Static Variable
public void method() {
int localVar = 30; // Local Variable
}
}
4.3 Operators in Java
Java provides operators to perform operations on variables.
Types of Operators
Operator Type Example
Arithmetic Operators +, -, *, /, %
Relational Operators == , != , > , < , >= , <=
Logical Operators && , `
Bitwise Operators & ,`
4/8
Operator Type Example
Assignment Operators = , += , -= , *= , /=
Unary Operators ++ , --
Ternary Operator ? :
Example:
java
int a = 10, b = 20;
System.out.println(a + b); // 30 (Arithmetic)
System.out.println(a > b); // false (Relational)
System.out.println(a < b && b > 15); // true (Logical)
5. Type Casting in Java
Type casting converts one data type into another.
5.1 Widening (Implicit Type Casting)
Small to large data type (automatic conversion).
java
int num = 10;
double d = num; // Implicit conversion
System.out.println(d); // Output: 10.0
5.2 Narrowing (Explicit Type Casting)
Large to small data type (manual conversion).
java
5/8
double num = 10.5;
int n = (int) num; // Explicit conversion
System.out.println(n); // Output: 10
6. Control Statements
Control statements manage the flow of execution in Java.
6.1 Conditional Statements
(i) if-else Statement
java
int age = 18;
if (age >= 18) {
System.out.println("You can vote!");
} else {
System.out.println("You cannot vote.");
}
(ii) switch Statement
java
int day = 2;
switch (day) {
case 1: System.out.println("Monday"); break;
case 2: System.out.println("Tuesday"); break;
default: System.out.println("Invalid day");
}
6/8
6.2 Looping Statements
Loops execute a block of code multiple times.
(i) for Loop
java
for (int i = 1; i <= 5; i++) {
System.out.println("Count: " + i);
}
(ii) while Loop
java
int i = 1;
while (i <= 5) {
System.out.println("Number: " + i);
i++;
}
(iii) do-while Loop
java
int i = 1;
do {
System.out.println("Hello");
i++;
} while (i <= 5);
Conclusion
✔ Java provides strong features like platform independence, security, and OOP principles.
✔ Data types, variables, and operators are fundamental building blocks.
✔ Control statements allow us to manage the program flow efficiently.
7/8
Next Topic: Do you want to explore OOP concepts (Classes, Objects, Inheritance,
Polymorphism)? 🚀
8/8
Core Java Best Practices
Object-Oriented Programming (OOP)
in Java
1. Introduction to OOP
Object-Oriented Programming (OOP) is a programming paradigm that uses objects and
classes to design software applications. Java is fully object-oriented because it supports
OOP principles.
Benefits of OOP
✔ Modularity – Code is divided into smaller parts (objects and classes).
✔ Reusability – Inheritance allows using existing code.
✔ Scalability – OOP allows easy modifications and extensions.
✔ Security – Encapsulation hides data and methods.
2. Four Pillars of OOP
2.1 Encapsulation
Encapsulation is hiding the data (variables) inside a class and allowing controlled access
through getters and setters.
Example: Encapsulation in a Bank Account
java
class BankAccount {
private double balance; // Private variable (hidden from outside access)
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
1/9
}
}
public double getBalance() {
return balance;
}
}
public class Main {
public static void main(String[] args) {
BankAccount acc = new BankAccount();
acc.deposit(1000);
System.out.println("Balance: " + acc.getBalance());
}
}
✔ Private data cannot be accessed directly from outside the class.
✔ Public methods provide controlled access.
2.2 Inheritance
Inheritance allows a child class to inherit properties and behavior from a parent class
using the extends keyword.
Example: Car class inherits Vehicle class
java
class Vehicle {
void move() {
System.out.println("Vehicle is moving...");
}
}
class Car extends Vehicle {
void speed() {
System.out.println("Car is speeding...");
}
}
2/9
public class Main {
public static void main(String[] args) {
Car myCar = new Car();
myCar.move(); // Inherited from Vehicle
myCar.speed(); // Defined in Car
}
}
✔ Code reuse – The Car class does not need to redefine the move() method.
✔ Hierarchy – Inheritance forms a relationship between classes.
2.3 Polymorphism
Polymorphism means "many forms", allowing the same method to perform different tasks.
(i) Method Overloading (Compile-time Polymorphism)
Same method name but different parameters in the same class.
java
class MathOperations {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
MathOperations obj = new MathOperations();
System.out.println(obj.add(5, 3)); // Calls int version
System.out.println(obj.add(5.5, 2.2)); // Calls double version
}
}
3/9
(ii) Method Overriding (Runtime Polymorphism)
Child class provides a new implementation for an inherited method.
java
class Animal {
void sound() {
System.out.println("Animals make sounds");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // Upcasting
myDog.sound(); // Calls Dog's sound() method
}
}
✔ Method Overriding enables runtime behavior change.
✔ Dynamic Method Dispatch – The overridden method is called based on the object type.
2.4 Abstraction
Abstraction hides implementation details and shows only essential features.
(i) Using Abstract Classes
Abstract classes can have both abstract (unimplemented) and concrete methods.
4/9
java
abstract class Vehicle {
abstract void start(); // Abstract method (no implementation)
void stop() { // Concrete method
System.out.println("Vehicle stopped.");
}
}
class Car extends Vehicle {
@Override
void start() {
System.out.println("Car started with a key");
}
}
public class Main {
public static void main(String[] args) {
Vehicle myCar = new Car();
myCar.start();
myCar.stop();
}
}
(ii) Using Interfaces
Interfaces contain only abstract methods (until Java 8).
A class can implement multiple interfaces.
java
interface Engine {
void start();
}
class Bike implements Engine {
public void start() {
System.out.println("Bike started with self-start");
5/9
}
}
public class Main {
public static void main(String[] args) {
Bike myBike = new Bike();
myBike.start();
}
}
✔ Interfaces support multiple inheritance.
✔ They provide full abstraction since they contain no concrete methods.
3. Other OOP Concepts
3.1 this Keyword
Refers to the current object.
Used to avoid variable shadowing.
java
class Example {
int x;
Example(int x) {
this.x = x; // Resolves variable shadowing
}
}
3.2 super Keyword
Refers to the parent class.
6/9
Used to call parent class methods and constructors.
java
class Parent {
Parent() {
System.out.println("Parent Constructor");
}
}
class Child extends Parent {
Child() {
super(); // Calls Parent() constructor
System.out.println("Child Constructor");
}
}
public class Main {
public static void main(String[] args) {
Child obj = new Child();
}
}
✔ super() must be the first statement in the constructor.
3.3 final Keyword
Usage Example
Final Variable (Cannot change value) final int PI = 3.14;
Final Method (Cannot be overridden) final void display() {}
Final Class (Cannot be inherited) final class Animal {}
Example:
java
final class Animal {} // Cannot be extended by any other class
7/9
3.4 Static vs Non-Static Members
Feature Static Non-Static
Memory Allocation Class level Object level
Access ClassName.method() object.method()
Example static int x; int y;
Example:
java
class Example {
static int staticVar = 10; // Shared across objects
int instanceVar = 20; // Separate for each object
}
3.5 Access Modifiers
Accessible Within Same Outside Package Outside
Modifier Class Package (Subclass) Package
private ✅ ❌ ❌ ❌
default ✅ ✅ ❌ ❌
protected ✅ ✅ ✅ ❌
public ✅ ✅ ✅ ✅
Example:
java
public class Example {
private int x; // Cannot be accessed outside
protected int y; // Can be accessed in subclasses
public int z; // Can be accessed anywhere
}
8/9
Conclusion
✔ Java follows four OOP principles: Encapsulation, Inheritance, Polymorphism, and
Abstraction.
✔ Additional OOP concepts like this, super, final, static, and access modifiers improve code
structure.
Next Topic: Do you want to explore Java Collections (List, Set, Map, etc.) or Multithreading
in Java? 🚀
9/9
Core Java Best Practices
Java Strings - In-depth Explanation
Strings are one of the most commonly used data types in Java. Java provides the String
class for handling text-based data efficiently.
1. What is a String in Java?
A String in Java is a sequence of characters.
It is immutable, meaning once created, its value cannot be changed.
The String class is part of java.lang package.
Example: Creating Strings
java
public class StringExample {
public static void main(String[] args) {
String str1 = "Hello"; // String literal
String str2 = new String("World"); // Using new keyword
System.out.println(str1 + " " + str2);
}
}
2. String Pool & Immutability
2.1 What is String Pool?
1/8
The String Pool is a special memory area inside the Heap where Java stores String
literals.
If a String already exists in the pool, Java returns the same reference instead of creating
a new one.
Example: String Pool Behavior
java
public class StringPoolExample {
public static void main(String[] args) {
String s1 = "Java"; // Stored in String pool
String s2 = "Java"; // References the same object
String s3 = new String("Java"); // Creates a new object
System.out.println(s1 == s2); // true (same reference)
System.out.println(s1 == s3); // false (different objects)
}
}
✔ Strings created using literals are stored in the String Pool.
✔ Strings created with new String("...") are stored in Heap memory separately.
2.2 Why are Strings Immutable?
In Java, Strings are immutable to ensure security, caching, and thread safety.
Any modification creates a new object, instead of changing the original.
Example: String Immutability
java
public class StringImmutableExample {
public static void main(String[] args) {
String s = "Java";
s.concat(" Programming"); // Creates a new String, but the reference isn't
updated
System.out.println(s); // Output: Java (unchanged)
2/8
s = s.concat(" Programming"); // Now, `s` points to the new object
System.out.println(s); // Output: Java Programming
}
}
✔ The original s remains unchanged after calling concat() .
✔ A new object is created with "Java Programming" .
3. String Manipulation
Java provides three classes for String manipulation:
1. String – Immutable
2. StringBuilder – Mutable, not thread-safe
3. StringBuffer – Mutable, thread-safe
3.1 String Class (Immutable)
Every modification creates a new object.
Used when Strings are rarely changed.
Example: Concatenation using String
java
public class StringExample {
public static void main(String[] args) {
String str = "Hello";
str = str + " World"; // Creates a new object
System.out.println(str);
}
}
3/8
3.2 StringBuilder (Mutable, Fast)
Faster than StringBuffer since it's not synchronized.
Used when String modifications are frequent.
Example: Using StringBuilder
java
public class StringBuilderExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb); // Output: Hello World
}
}
✔ StringBuilder modifies the same object, improving performance.
3.3 StringBuffer (Mutable, Thread-Safe)
Thread-safe but slower than StringBuilder .
Used in multi-threaded applications.
Example: Using StringBuffer
java
public class StringBufferExample {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello");
sb.append(" World");
System.out.println(sb); // Output: Hello World
}
}
4/8
✔ StringBuffer ensures data consistency in multi-threaded environments.
4. Important String Methods
Method Description Example
length() Returns length of the "Hello".length() → 5
string
charAt(index) Returns character at "Java".charAt(2) → 'v'
given index
substring(start, Extracts a substring "Hello".substring(1, 4) → "ell"
end)
toUpperCase() Converts to uppercase "java".toUpperCase() → "JAVA"
toLowerCase() Converts to lowercase "JAVA".toLowerCase() → "java"
trim() Removes leading/trailing " Hello ".trim() → "Hello"
spaces
replace(old, new) Replaces characters "Hello".replace('H', 'J') → "Jello"
split(regex) Splits a string "apple,orange".split(",") → ["apple",
"orange"]
contains(str) Checks if substring exists "Hello".contains("He") → true
indexOf(str) Returns first occurrence "Java".indexOf("v") → 2
index
Example: Using String Methods
java
public class StringMethodsExample {
public static void main(String[] args) {
String str = " Hello Java ";
System.out.println(str.trim()); // Removes spaces
System.out.println(str.toUpperCase()); // Converts to uppercase
System.out.println(str.replace("Java", "World")); // Replaces text
}
}
5/8
5. String Comparisons
Java provides three ways to compare Strings:
5.1 Using == (Reference Comparison)
Compares memory addresses, not values.
java
String s1 = "Java";
String s2 = "Java";
String s3 = new String("Java");
System.out.println(s1 == s2); // true (same reference)
System.out.println(s1 == s3); // false (different objects)
✔ Use == only for reference checks.
5.2 Using .equals() (Value Comparison)
Compares actual content of Strings.
java
String s1 = "Java";
String s2 = new String("Java");
System.out.println(s1.equals(s2)); // true (same content)
✔ Always use .equals() to compare String content.
6/8
5.3 Using .compareTo() (Lexicographical Comparison)
Used for sorting Strings based on ASCII values.
Returns:
0 → Both strings are equal
< 0 → First string is smaller
> 0 → First string is greater
java
public class StringCompareExample {
public static void main(String[] args) {
String s1 = "Apple";
String s2 = "Banana";
System.out.println(s1.compareTo(s2)); // Output: -1 (Apple < Banana)
}
}
✔ Useful for sorting Strings in Java.
Conclusion
✔ Strings in Java are immutable, meaning their value cannot be changed.
✔ Use StringBuilder or StringBuffer for efficient modifications.
✔ Use .equals() for content comparison, not == .
✔ Use .compareTo() for lexicographical comparison.
Next Topic: Do you want to explore Java Collections (List,
Set, Map, etc.) or Exception Handling in Java? 🚀
7/8
8/8
Core Java Best Practices
Update memory?
Java Arrays and Collections
Framework - In-depth Explanation
1. Arrays in Java
An array is a fixed-size, ordered collection of elements of the same data type.
1.1 Declaring and Initializing Arrays
java
// Declaration
int[] arr1; // Recommended
int arr2[]; // Also valid
// Initialization
int[] numbers = {1, 2, 3, 4, 5}; // Using array literal
int[] values = new int[5]; // Creating an array of size 5
// Assigning values
values[0] = 10;
values[1] = 20;
System.out.println(values[1]); // Output: 20
1.2 Multi-Dimensional Arrays
java
int[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
System.out.println(matrix[1][2]); // Output: 6
✔ Arrays have fixed size, meaning you cannot dynamically resize them.
1/9
2. Collections Framework
The Java Collections Framework (JCF) provides dynamic and flexible data structures.
Key Interfaces in JCF
Interface Description
List Ordered collection (allows duplicates)
Set Unordered collection (no duplicates)
Map Key-value pairs (unique keys)
Queue FIFO (First-In-First-Out) collection
3. List Interface (Ordered, Allows Duplicates)
3.1 ArrayList (Dynamic Array)
✔ Fast read, slow insert/delete (uses a dynamic array internally).
java
import java.util.*;
public class ArrayListExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("Java");
list.remove("Python");
System.out.println(list); // Output: [Java, Java]
}
}
2/9
3.2 LinkedList (Doubly Linked List)
✔ Fast insert/delete, slow read.
java
import java.util.*;
public class LinkedListExample {
public static void main(String[] args) {
List<Integer> list = new LinkedList<>();
list.add(10);
list.add(20);
list.addFirst(5);
System.out.println(list); // Output: [5, 10, 20]
}
}
3.3 Vector (Thread-Safe)
✔ Similar to ArrayList , but synchronized.
java
import java.util.*;
public class VectorExample {
public static void main(String[] args) {
Vector<Integer> vec = new Vector<>();
vec.add(100);
vec.add(200);
System.out.println(vec); // Output: [100, 200]
}
}
3/9
4. Set Interface (Unordered, No Duplicates)
4.1 HashSet (No Order, Fast Access)
✔ Uses HashMap internally.
java
import java.util.*;
public class HashSetExample {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Java");
set.add("Python");
set.add("Java"); // Duplicate, will be ignored
System.out.println(set); // Output: [Java, Python] (Order may vary)
}
}
4.2 TreeSet (Sorted Order)
✔ Uses Red-Black Tree (sorted, slower than HashSet ).
java
import java.util.*;
public class TreeSetExample {
public static void main(String[] args) {
Set<Integer> set = new TreeSet<>();
set.add(30);
set.add(10);
set.add(20);
System.out.println(set); // Output: [10, 20, 30] (Sorted)
}
}
4/9
4.3 LinkedHashSet (Insertion Order Maintained)
java
import java.util.*;
public class LinkedHashSetExample {
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<>();
set.add("Java");
set.add("Python");
set.add("C++");
System.out.println(set); // Output: [Java, Python, C++]
}
}
5. Map Interface (Key-Value Pairs, Unique Keys)
5.1 HashMap (Fast, No Order)
✔ Uses Hashing (allows null keys).
java
import java.util.*;
public class HashMapExample {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "Java");
map.put(2, "Python");
System.out.println(map.get(1)); // Output: Java
}
}
5/9
5.2 TreeMap (Sorted by Key)
✔ Uses Red-Black Tree.
java
import java.util.*;
public class TreeMapExample {
public static void main(String[] args) {
Map<Integer, String> map = new TreeMap<>();
map.put(3, "C++");
map.put(1, "Java");
map.put(2, "Python");
System.out.println(map); // Output: {1=Java, 2=Python, 3=C++}
}
}
5.3 LinkedHashMap (Insertion Order Maintained)
java
import java.util.*;
public class LinkedHashMapExample {
public static void main(String[] args) {
Map<String, Integer> map = new LinkedHashMap<>();
map.put("Apple", 50);
map.put("Banana", 30);
System.out.println(map); // Output: {Apple=50, Banana=30}
}
}
6/9
6. Queue Interface (FIFO - First In First Out)
6.1 PriorityQueue (Elements in Natural Order)
✔ Uses Heap Data Structure.
java
import java.util.*;
public class PriorityQueueExample {
public static void main(String[] args) {
Queue<Integer> pq = new PriorityQueue<>();
pq.add(30);
pq.add(10);
pq.add(20);
System.out.println(pq.poll()); // Output: 10 (Smallest element)
}
}
6.2 Deque (Double-Ended Queue)
✔ Allows insert/remove at both ends.
java
import java.util.*;
public class DequeExample {
public static void main(String[] args) {
Deque<String> dq = new ArrayDeque<>();
dq.addFirst("First");
dq.addLast("Last");
System.out.println(dq.pollFirst()); // Output: First
}
}
7/9
7. Comparable vs Comparator
✔ Comparable is used for natural ordering ( compareTo() ).
✔ Comparator is used for custom sorting ( compare() ).
7.1 Comparable (Default Sorting)
java
import java.util.*;
class Student implements Comparable<Student> {
int id;
String name;
Student(int id, String name) {
this.id = id;
this.name = name;
}
public int compareTo(Student s) {
return this.id - s.id; // Ascending order
}
}
public class ComparableExample {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student(2, "Alice"));
list.add(new Student(1, "Bob"));
Collections.sort(list); // Uses compareTo()
}
}
7.2 Comparator (Custom Sorting)
8/9
java
import java.util.*;
class Student {
int id;
String name;
Student(int id, String name) {
this.id = id;
this.name = name;
}
}
class NameComparator implements Comparator<Student> {
public int compare(Student s1, Student s2) {
return s1.name.compareTo(s2.name); // Sort by name
}
}
public class ComparatorExample {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student(2, "Alice"));
list.add(new Student(1, "Bob"));
Collections.sort(list, new NameComparator());
}
}
Next Topic: Do you want to explore
Exception Handling in Java? 🚀
9/9
Core Java Best Practices
Java Exception Handling - In-depth
Explanation
1. What is Exception Handling in Java?
An exception is an unwanted or unexpected event that occurs during program execution,
disrupting the normal flow. Exception Handling ensures that the program runs smoothly,
even when unexpected errors occur.
Example: Exception Without Handling
java
public class ExceptionExample {
public static void main(String[] args) {
int num = 10, denom = 0;
int result = num / denom; // Causes ArithmeticException
System.out.println(result);
}
}
💥 Error: Exception in thread "main" java.lang.ArithmeticException: / by zero
2. Types of Exceptions in Java
Java exceptions are categorized into:
Type Description Examples
Checked Must be handled using try- IOException , SQLException
Exceptions catch or throws . Compiler
checks these exceptions.
1/6
Type Description Examples
Unchecked Runtime exceptions caused by NullPointerException ,
Exceptions logic errors. Compiler doesn't ArrayIndexOutOfBoundsException ,
check them. ArithmeticException
Errors Critical issues that cannot be StackOverflowError , OutOfMemoryError
handled at runtime.
3. Handling Exceptions in Java
3.1 try and catch Blocks
✔ The try block contains risky code.
✔ The catch block handles exceptions if they occur.
java
public class TryCatchExample {
public static void main(String[] args) {
try {
int num = 10, denom = 0;
int result = num / denom; // Exception occurs here
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero!");
}
}
}
🛡 Output: Cannot divide by zero!
3.2 finally Block
✔ Executes always, regardless of whether an exception occurs or not.
✔ Used for resource cleanup (e.g., closing database connections, files).
java
2/6
public class FinallyExample {
public static void main(String[] args) {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[5]); // Throws ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Index out of bounds!");
} finally {
System.out.println("This will always execute.");
}
}
}
🛡 Output:
pgsql
Index out of bounds!
This will always execute.
4. throw and throws in Java
4.1 throw (Manually Throwing an Exception)
✔ Used to explicitly throw an exception.
✔ Typically used in custom validation logic.
java
public class ThrowExample {
public static void validateAge(int age) {
if (age < 18) {
throw new IllegalArgumentException("Age must be 18 or above");
}
System.out.println("Access granted!");
}
public static void main(String[] args) {
3/6
validateAge(16); // Throws IllegalArgumentException
}
}
🛡 Output: Exception in thread "main" java.lang.IllegalArgumentException: Age must
be 18 or above
4.2 throws (Declaring Exceptions)
✔ Used in method signatures to indicate that a method may throw exceptions.
✔ Calling code must handle or propagate the exception.
java
import java.io.*;
public class ThrowsExample {
public static void readFile() throws IOException {
FileReader file = new FileReader("nonexistent.txt"); // May throw
IOException
}
public static void main(String[] args) {
try {
readFile();
} catch (IOException e) {
System.out.println("File not found!");
}
}
}
🛡 Output: File not found!
5. Custom Exceptions
4/6
✔ We can define our own exception classes by extending Exception (for checked
exceptions) or RuntimeException (for unchecked exceptions).
Example: Custom Exception for Invalid Age
java
class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message);
}
}
public class CustomExceptionExample {
public static void validateAge(int age) throws InvalidAgeException {
if (age < 18) {
throw new InvalidAgeException("You must be at least 18.");
}
System.out.println("Welcome!");
}
public static void main(String[] args) {
try {
validateAge(16);
} catch (InvalidAgeException e) {
System.out.println("Caught Exception: " + e.getMessage());
}
}
}
🛡 Output: Caught Exception: You must be at least 18.
6. Best Practices for Exception Handling
✅ Use Specific Exceptions (e.g., ,
IOException ) instead of generic
SQLException
Exception.
✅ Log Exceptions Properly using instead of printing stack traces.
Logger
✅ Use for Cleanup (e.g., closing files, database connections).
finally
5/6
✅ Avoid Empty Blocks (handle exceptions properly).
catch
✅ Create Custom Exceptions when necessary.
Next Topic: Do you want to explore
Multithreading in Java? 🚀
6/6
Core Java Best Practices
Java Multithreading & Concurrency -
In-depth Explanation
1. What is Multithreading?
Multithreading is a technique where multiple threads (lightweight processes) run
concurrently to achieve parallel execution and improve performance.
Example: Single-threaded vs Multithreaded Execution
Single-threaded Execution (Sequential)
java
public class SingleThreadExample {
public static void main(String[] args) {
System.out.println("Task 1");
System.out.println("Task 2");
System.out.println("Task 3");
}
}
🛡 Output (Always same order):
arduino
Task 1
Task 2
Task 3
Multithreaded Execution (Parallel)
java
1/9
class MyThread extends Thread {
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
}
}
public class MultiThreadExample {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start();
t2.start();
}
}
🛡 Output (Unpredictable Order):
mathematica
Thread running: Thread-0
Thread running: Thread-1
2. Thread Lifecycle in Java
A thread goes through the following states:
State Description
New Thread is created but not started yet.
Runnable Thread is ready to run but waiting for CPU.
Running Thread is executing its task.
Blocked Thread is waiting to acquire a lock.
Waiting Thread is waiting indefinitely for another thread’s signal.
Timed Waiting Thread is waiting for a specific time.
Terminated Thread has finished execution.
Example: Thread Lifecycle
2/9
java
class MyThread extends Thread {
public void run() {
System.out.println("Thread running...");
}
}
public class ThreadLifecycle {
public static void main(String[] args) {
MyThread t = new MyThread();
System.out.println("Thread state: " + t.getState()); // NEW
t.start();
System.out.println("Thread state: " + t.getState()); // RUNNABLE
}
}
3. Creating Threads in Java
There are two ways to create a thread in Java:
3.1 Extending the Thread Class
✔ Override the run() method.
✔ Call start() to begin execution.
java
class MyThread extends Thread {
public void run() {
System.out.println("Thread running...");
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start();
3/9
}
}
3.2 Implementing the Runnable Interface (Recommended)
✔ More flexible, avoids single inheritance limitation.
java
class MyRunnable implements Runnable {
public void run() {
System.out.println("Thread running...");
}
}
public class RunnableExample {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable());
t1.start();
}
}
4. Synchronization in Java
Problem: When multiple threads access a shared resource, data inconsistency can occur.
4.1 synchronized Keyword
✔ Ensures that only one thread accesses the critical section at a time.
java
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
4/9
return count;
}
}
public class SynchronizationExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) counter.increment();
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) counter.increment();
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + counter.getCount());
}
}
🛡 Output: Final count: 2000 (without synchronization, it may give inconsistent results)
4.2 Locks in Java ( ReentrantLock )
✔ Provides better control than synchronized .
java
import java.util.concurrent.locks.*;
class Counter {
private int count = 0;
private final Lock lock = new ReentrantLock();
5/9
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
}
5. Deadlock in Java
A deadlock occurs when two threads hold locks on different resources and wait indefinitely
for each other.
Example: Deadlock Scenario
java
class DeadlockExample {
static final Object resource1 = new Object();
static final Object resource2 = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (resource1) {
System.out.println("Thread 1 locked resource 1");
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (resource2) {
System.out.println("Thread 1 locked resource 2");
}
}
});
Thread t2 = new Thread(() -> {
6/9
synchronized (resource2) {
System.out.println("Thread 2 locked resource 2");
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (resource1) {
System.out.println("Thread 2 locked resource 1");
}
}
});
t1.start();
t2.start();
}
}
🛡 Output: May result in a deadlock, where both threads wait forever.
6. Thread Communication ( wait() , notify() ,
notifyAll() )
✔ Used to make threads communicate while sharing resources.
Example: Producer-Consumer Problem
java
class SharedResource {
private int data;
private boolean available = false;
public synchronized void produce(int value) {
while (available) {
try { wait(); } catch (InterruptedException e) {}
}
data = value;
available = true;
System.out.println("Produced: " + value);
notify();
}
7/9
public synchronized void consume() {
while (!available) {
try { wait(); } catch (InterruptedException e) {}
}
System.out.println("Consumed: " + data);
available = false;
notify();
}
}
public class ProducerConsumerExample {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Thread producer = new Thread(() -> {
for (int i = 1; i <= 5; i++) {
resource.produce(i);
}
});
Thread consumer = new Thread(() -> {
for (int i = 1; i <= 5; i++) {
resource.consume();
}
});
producer.start();
consumer.start();
}
}
🛡 Output (Randomized Order):
makefile
Produced: 1
Consumed: 1
Produced: 2
Consumed: 2
...
8/9
Summary
Concept Description
Thread Lifecycle States a thread goes through (New → Runnable → Running →
Terminated).
Creating Threads Thread class or Runnable interface (Runnable preferred).
Synchronization synchronized keyword or ReentrantLock to prevent data inconsistency.
Deadlock Occurs when two threads wait indefinitely for each other’s lock.
Thread Uses wait() , notify() , notifyAll() for coordination.
Communication
Next Topic: Do you want to explore Java Collections
Framework? 🚀
9/9
Core Java Best Practices
Java File Handling (Java I/O) - In-depth
Explanation
Java provides the java.io package to handle file operations such as reading, writing, and
managing files. Let’s go step by step.
1. File Handling in Java
Java provides several classes to perform file operations:
Class Purpose
File Represents file and directory pathnames.
FileReader Reads character data from a file.
FileWriter Writes character data to a file.
BufferedReader Reads text from a file efficiently.
BufferedWriter Writes text to a file efficiently.
ObjectOutputStream Used for serialization (saving objects to a file).
ObjectInputStream Used for deserialization (reading objects from a file).
2. Creating a File in Java
Use the File class to create a file.
java
import java.io.File;
import java.io.IOException;
1/8
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) {
System.out.println("An error occurred.");
e.printStackTrace();
}
}
}
🛡 Output:
arduino
File created: example.txt
3. Writing to a File
3.1 Using FileWriter
FileWriter is used to write character data to a file.
java
import java.io.FileWriter;
import java.io.IOException;
public class FileWriteExample {
public static void main(String[] args) {
try {
FileWriter writer = new FileWriter("example.txt");
writer.write("Hello, Java File Handling!");
writer.close();
2/8
System.out.println("Successfully written to the file.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
🛡 Output: "Successfully written to the file."
📌 Note: The previous content is overwritten. Use FileWriter("example.txt", true) to
append data instead.
3.2 Using BufferedWriter (Efficient Writing)
BufferedWriter is more efficient because it uses a buffer to write data in chunks.
java
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWriterExample {
public static void main(String[] args) {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter("example.txt",
true));
writer.write("\nAppending new line using BufferedWriter.");
writer.close();
System.out.println("Data appended successfully.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
🛡 Output: "Data appended successfully."
(New line added in the file.)
3/8
4. Reading from a File
4.1 Using FileReader
FileReader reads characters from a file.
java
import java.io.FileReader;
import java.io.IOException;
public class FileReaderExample {
public static void main(String[] args) {
try {
FileReader reader = new FileReader("example.txt");
int character;
while ((character = reader.read()) != -1) {
System.out.print((char) character);
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
🛡 Output: Hello, Java File Handling! Appending new line using BufferedWriter.
4.2 Using BufferedReader (Efficient Reading)
BufferedReader reads data line by line.
java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderExample {
public static void main(String[] args) {
4/8
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();
}
}
}
🛡 Output (Line-by-line reading):
arduino
Hello, Java File Handling!
Appending new line using BufferedWriter.
5. Deleting a File
You can delete a file using the delete() method of the File class.
java
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("File deleted: " + file.getName());
} else {
System.out.println("Failed to delete the file.");
}
5/8
}
}
🛡 Output: "File deleted: example.txt" (if exists)
6. Serialization & Deserialization
Serialization allows storing Java objects as binary data in a file and retrieving them later.
6.1 Serialization (Saving an Object to a File)
✔ Convert an object into a byte stream and save it.
✔ The class must implement Serializable .
java
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Student implements Serializable {
private static final long serialVersionUID = 1L;
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
public class SerializationExample {
public static void main(String[] args) {
try {
Student student = new Student("John Doe", 22);
FileOutputStream fileOut = new FileOutputStream("student.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(student);
out.close();
6/8
fileOut.close();
System.out.println("Object serialized successfully.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
🛡 Output: "Object serialized successfully."
6.2 Deserialization (Reading an Object from a File)
✔ Convert a byte stream back into an object.
java
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class DeserializationExample {
public static void main(String[] args) {
try {
FileInputStream fileIn = new FileInputStream("student.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
Student student = (Student) in.readObject();
in.close();
fileIn.close();
System.out.println("Object deserialized: " + student.name + ", " +
student.age);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
🛡 Output: "Object deserialized: John Doe, 22"
7/8
Summary
Concept Description
File Creation Use File class ( createNewFile() ).
Writing to File Use FileWriter , BufferedWriter .
Reading from File Use FileReader , BufferedReader .
Deleting File Use delete() method of File .
Serialization Convert object → byte stream using ObjectOutputStream .
Deserialization Convert byte stream → object using ObjectInputStream .
Next Topic: Would you like to explore Java Networking
(Socket Programming) or move to another Java topic? 🚀
8/8
Core Java Best Practices
Java 8 Features - In-depth Explanation
Java 8 introduced significant improvements to the language, making it more functional and
concise. Below are the key Java 8 features:
1. Functional Interfaces & Lambda Expressions
1.1 Functional Interfaces
A functional interface is an interface with only one abstract method. It can have multiple
default and static methods.
📌 Example of Functional Interface
java
@FunctionalInterface
interface MyFunctionalInterface {
void display(); // Single Abstract Method (SAM)
default void show() {
System.out.println("Default method in functional interface.");
}
}
1.2 Lambda Expressions
A lambda expression provides a simple way to implement a functional interface.
📌 Example without Lambda
java
class MyClass implements MyFunctionalInterface {
public void display() {
System.out.println("Hello from MyClass!");
1/8
}
}
public class LambdaExample {
public static void main(String[] args) {
MyFunctionalInterface obj = new MyClass();
obj.display();
}
}
📌 Example using Lambda
java
public class LambdaExample {
public static void main(String[] args) {
MyFunctionalInterface obj = () -> System.out.println("Hello from Lambda!");
obj.display();
}
}
🛡 Output:
csharp
Hello from Lambda!
✅ Advantages of Lambda Expressions:
Less code: No need for anonymous inner classes.
More readable: Directly pass behavior instead of creating separate classes.
Improves performance.
2. Stream API (java.util.stream)
The Stream API is used to process collections in a functional and parallelized way.
2.1 Creating Streams
2/8
java
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamExample {
public static void main(String[] args) {
// Creating a stream from a list
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Stream<String> stream = names.stream();
// Using stream methods
stream.forEach(System.out::println);
}
}
🛡 Output:
nginx
Alice
Bob
Charlie
2.2 Stream Operations
Operation Description
filter() Filters elements based on a condition.
map() Transforms elements in the stream.
sorted() Sorts elements in ascending order.
collect() Collects results into a List, Set, or Map.
📌 Example: Filtering & Mapping
java
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamOperations {
3/8
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Alice", "Bob", "Charlie");
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("A")) // Filters names starting with
"A"
.map(String::toUpperCase) // Converts to uppercase
.collect(Collectors.toList());
System.out.println(filteredNames);
}
}
🛡 Output:
csharp
[Alice]
3. Method References
Method references allow referring to methods by their names instead of writing lambda
expressions.
📌 Types of Method References:
Type Example
Static Method Reference ClassName::staticMethod
Instance Method Reference object::instanceMethod
Constructor Reference ClassName::new
📌 Example: Using Method References
java
import java.util.Arrays;
import java.util.List;
public class MethodReferenceExample {
4/8
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Alice", "Bob");
// Using method reference instead of lambda
names.forEach(System.out::println);
}
}
4. Default & Static Methods in Interfaces
4.1 Default Methods
Allows interfaces to have method implementations.
Helps in backward compatibility.
📌 Example of Default Method
java
interface MyInterface {
default void show() {
System.out.println("Default method in interface.");
}
}
class MyClass implements MyInterface { }
public class DefaultMethodExample {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.show(); // Calls the default method
}
}
🛡 Output:
sql
5/8
Default method in interface.
4.2 Static Methods
Defined in interfaces but not inherited by implementing classes.
Can be accessed using InterfaceName.methodName().
📌 Example of Static Method in Interface
java
interface MathUtil {
static int square(int x) {
return x * x;
}
}
public class StaticMethodExample {
public static void main(String[] args) {
int result = MathUtil.square(5);
System.out.println("Square of 5: " + result);
}
}
🛡 Output:
scss
Square of 5: 25
5. Optional Class (java.util.Optional)
The Optional class helps avoid NullPointerException.
📌 Example of Optional
6/8
java
import java.util.Optional;
public class OptionalExample {
public static void main(String[] args) {
Optional<String> optional = Optional.ofNullable(null);
// Using ifPresent() to execute code if value exists
optional.ifPresent(value -> System.out.println("Value: " + value));
// Using orElse() to provide a default value
System.out.println(optional.orElse("Default Value"));
}
}
🛡 Output:
rust
Default Value
Summary
Feature Description
Functional Interfaces & Lambda Allows functional-style programming with concise syntax.
Stream API Processes collections in a functional way.
Method References Shorter syntax for calling existing methods.
Default & Static Methods Adds functionality to interfaces without breaking old code.
Optional Class Handles null values safely to prevent exceptions.
Next Topic: Would you like to explore Java 9 Features or go deeper into
any Java 8 concept? 🚀
7/8
8/8
Core Java Best Practices
JDBC (Java Database Connectivity) - In-
depth Explanation
JDBC (Java Database Connectivity) is an API in Java that allows applications to interact with
databases. It provides methods to connect, execute queries, and manage transactions with
relational databases like MySQL, PostgreSQL, Oracle, etc.
1. Steps to Connect Java with a Database
To connect Java with a database using JDBC, follow these steps:
Step 1: Load the JDBC Driver
Each database has a specific JDBC driver that must be loaded before connecting.
java
Class.forName("com.mysql.cj.jdbc.Driver"); // MySQL Driver
Note: Since JDBC 4.0, the driver is auto-loaded when DriverManager.getConnection() is
called.
Step 2: Establish a Connection
Create a connection using DriverManager.getConnection() .
java
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydatabase", "username", "password");
1/5
URL format: jdbc:mysql://hostname:port/databaseName
Example for different databases:
MySQL: "jdbc:mysql://localhost:3306/mydb"
PostgreSQL: "jdbc:postgresql://localhost:5432/mydb"
Oracle: "jdbc:oracle:thin:@localhost:1521:xe"
Step 3: Create a Statement
There are three types of statements in JDBC:
Statement Type Description
Statement Used for static queries.
PreparedStatement Used for parameterized queries (prevents SQL injection).
CallableStatement Used to call stored procedures.
Example:
java
Statement stmt = con.createStatement();
Step 4: Execute the Query
For SELECT queries, use executeQuery() .
For INSERT, UPDATE, DELETE, use executeUpdate() .
java
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
while (rs.next()) {
System.out.println(rs.getString("username"));
}
2/5
Step 5: Close the Connection
Always close the connection to free up resources.
java
con.close();
2. JDBC Drivers
JDBC drivers enable Java applications to interact with different databases.
JDBC Driver Type Description
Type 1: JDBC-ODBC Bridge Uses ODBC driver; not recommended.
Type 2: Native-API Driver Uses database-specific native API; requires client installation.
Type 3: Network Protocol Driver Uses middleware to communicate with databases.
Type 4: Thin Driver (Pure Java) Directly connects to the database; most commonly used.
✅ Example JDBC Drivers:
MySQL: com.mysql.cj.jdbc.Driver
PostgreSQL: org.postgresql.Driver
Oracle: oracle.jdbc.driver.OracleDriver
3. CRUD Operations with JDBC
3.1 Create (INSERT)
java
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb",
"root", "password");
3/5
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1, "John Doe");
pstmt.setString(2, "john@example.com");
int rowsInserted = pstmt.executeUpdate();
System.out.println(rowsInserted + " row(s) inserted.");
con.close();
3.2 Read (SELECT)
java
String sql = "SELECT * FROM users";
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
System.out.println("User: " + rs.getString("name") + ", Email: " +
rs.getString("email"));
}
3.3 Update
java
String sql = "UPDATE users SET email = ? WHERE name = ?";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1, "newemail@example.com");
pstmt.setString(2, "John Doe");
int rowsUpdated = pstmt.executeUpdate();
System.out.println(rowsUpdated + " row(s) updated.");
4/5
3.4 Delete
java
String sql = "DELETE FROM users WHERE name = ?";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1, "John Doe");
int rowsDeleted = pstmt.executeUpdate();
System.out.println(rowsDeleted + " row(s) deleted.");
Conclusion
JDBC provides a standard way to interact with databases. Key points:
Steps to connect: Load driver → Establish connection → Create statement → Execute
query → Close connection.
JDBC drivers: Type 1-4; Type 4 is the most common.
CRUD operations: executeQuery() for reading, executeUpdate() for insert, update,
and delete.
Next Topic: Do you want to explore JDBC Transactions (commit &
rollback) or any specific database integration? 🚀
5/5
Core Java Best Practices
Design Patterns - Basic Understanding
Design patterns are best practices used in software development to solve common problems
efficiently. They improve code reusability, scalability, and maintainability.
1. Singleton Pattern
Definition
The Singleton Pattern ensures that a class has only one instance and provides a global
access point to it.
Use Cases
Managing database connections.
Logging frameworks.
Configuration settings.
Implementation
java
class Singleton {
private static Singleton instance;
private Singleton() { } // Private constructor
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
1/8
public class SingletonExample {
public static void main(String[] args) {
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();
System.out.println(obj1 == obj2); // Output: true (same instance)
}
}
Thread-Safe Singleton
java
class Singleton {
private static Singleton instance;
private Singleton() { }
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
✅ Advantages:
Saves memory by preventing multiple instances.
Centralized control.
🚫 Disadvantages:
Can be difficult to unit test due to global state.
2. Factory Pattern
Definition
2/8
The Factory Pattern provides an interface for creating objects but lets subclasses decide the
instantiation.
Use Cases
When object creation logic is complex.
When you need to create multiple related objects without exposing the instantiation
logic.
Implementation
java
// Step 1: Create an interface
interface Shape {
void draw();
}
// Step 2: Implement different classes
class Circle implements Shape {
public void draw() {
System.out.println("Drawing a Circle");
}
}
class Square implements Shape {
public void draw() {
System.out.println("Drawing a Square");
}
}
// Step 3: Create a Factory class
class ShapeFactory {
public static Shape getShape(String shapeType) {
if (shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
} else if (shapeType.equalsIgnoreCase("SQUARE")) {
return new Square();
}
return null;
}
}
3/8
// Step 4: Use the Factory
public class FactoryExample {
public static void main(String[] args) {
Shape shape1 = ShapeFactory.getShape("CIRCLE");
shape1.draw(); // Output: Drawing a Circle
Shape shape2 = ShapeFactory.getShape("SQUARE");
shape2.draw(); // Output: Drawing a Square
}
}
✅ Advantages:
Promotes loose coupling.
Centralized object creation.
🚫 Disadvantages:
Additional class overhead.
3. Builder Pattern
Definition
The Builder Pattern simplifies object creation when a class has many optional parameters.
Use Cases
When a class has too many constructor parameters.
When an object needs to be immutable.
Implementation
java
class Car {
private String engine;
private int wheels;
private boolean sunroof;
4/8
private Car(CarBuilder builder) {
this.engine = builder.engine;
this.wheels = builder.wheels;
this.sunroof = builder.sunroof;
}
public static class CarBuilder {
private String engine;
private int wheels;
private boolean sunroof;
public CarBuilder(String engine, int wheels) {
this.engine = engine;
this.wheels = wheels;
}
public CarBuilder setSunroof(boolean sunroof) {
this.sunroof = sunroof;
return this;
}
public Car build() {
return new Car(this);
}
}
@Override
public String toString() {
return "Car [engine=" + engine + ", wheels=" + wheels + ", sunroof=" +
sunroof + "]";
}
}
public class BuilderExample {
public static void main(String[] args) {
Car car = new Car.CarBuilder("V8", 4)
.setSunroof(true)
.build();
System.out.println(car); // Output: Car [engine=V8, wheels=4, sunroof=true]
5/8
}
}
✅ Advantages:
Improves readability for large constructors.
Ensures immutability.
🚫 Disadvantages:
Slightly more code than using multiple constructors.
4. Observer Pattern
Definition
The Observer Pattern defines a one-to-many dependency, meaning when one object
changes state, all its dependents (observers) are notified.
Use Cases
Event-driven programming (e.g., GUI applications).
Real-time notifications.
Implementation
java
import java.util.ArrayList;
import java.util.List;
// Step 1: Create an Observer interface
interface Observer {
void update(String message);
}
// Step 2: Create a Subject (Observable)
class NewsAgency {
private List<Observer> observers = new ArrayList<>();
6/8
public void addObserver(Observer observer) {
observers.add(observer);
}
public void notifyObservers(String news) {
for (Observer observer : observers) {
observer.update(news);
}
}
}
// Step 3: Create Concrete Observers
class Subscriber implements Observer {
private String name;
public Subscriber(String name) {
this.name = name;
}
public void update(String message) {
System.out.println(name + " received update: " + message);
}
}
// Step 4: Use the Observer pattern
public class ObserverExample {
public static void main(String[] args) {
NewsAgency newsAgency = new NewsAgency();
Observer subscriber1 = new Subscriber("Alice");
Observer subscriber2 = new Subscriber("Bob");
newsAgency.addObserver(subscriber1);
newsAgency.addObserver(subscriber2);
newsAgency.notifyObservers("Breaking News: Observer Pattern Implemented!");
}
}
🛡 Output:
sql
7/8
Alice received update: Breaking News: Observer Pattern Implemented!
Bob received update: Breaking News: Observer Pattern Implemented!
✅ Advantages:
Decouples subjects and observers, making systems flexible.
Useful in event-driven architectures.
🚫 Disadvantages:
Can cause memory leaks if observers are not removed when no longer needed.
Summary
Pattern Description Use Case
Singleton Ensures only one instance of a Logging, Configuration, Database connections.
class.
Factory Centralized object creation. When multiple similar objects are created
dynamically.
Builder Simplifies complex object Objects with many optional parameters (Immutable
creation. objects).
Observer Allows objects to listen for Event-driven systems, notifications.
updates.
Next Topic: Would you like to explore more Design Patterns (e.g.,
Prototype, Adapter, Strategy) or go deeper into one of the above? 🚀
8/8
Core Java Best Practices
Memory Management & Garbage
Collection in Java
Memory management in Java is handled by the JVM (Java Virtual Machine), which
automatically allocates and deallocates memory. The Garbage Collector (GC) is responsible
for cleaning up unused objects.
1. Stack vs Heap Memory
Java divides memory into two main areas: Stack and Heap.
📝 Stack Memory (Method Execution)
Stores method calls, local variables, and references to objects.
Follows LIFO (Last In, First Out).
Memory is automatically allocated and deallocated when a method is called or returns.
🔹 Example of Stack Memory:
java
class StackExample {
void methodA() {
int x = 10; // Stored in Stack
methodB();
}
void methodB() {
int y = 20; // Stored in Stack
}
public static void main(String[] args) {
StackExample obj = new StackExample(); // Reference stored in Stack, Object
1/6
stored in Heap
obj.methodA();
}
}
📝 Heap Memory (Object Storage)
Stores objects and class instances.
Objects are created using new keyword.
JVM’s Garbage Collector (GC) manages memory deallocation.
🔹 Example of Heap Memory:
java
class HeapExample {
int data; // Instance variable stored in Heap
HeapExample(int data) {
this.data = data;
}
public static void main(String[] args) {
HeapExample obj1 = new HeapExample(100); // Stored in Heap
HeapExample obj2 = new HeapExample(200); // Stored in Heap
}
}
📌 Key Differences Between Stack and Heap:
Feature Stack Heap
Storage Method calls, local variables Objects, instance variables
Access Fast Slower
Lifetime Short (Method execution) Long (Until GC removes it)
Management Managed by JVM automatically Managed by Garbage Collector
2. Garbage Collection Mechanisms in Java
2/6
The Garbage Collector (GC) removes unused objects from the Heap to free up memory.
Garbage Collection Process
1. Mark – Identifies which objects are in use.
2. Sweep – Deletes unreferenced objects.
3. Compact – Rearranges remaining objects to improve memory allocation.
Types of Garbage Collectors
Java provides multiple GC algorithms:
GC Type Description
Serial GC Single-threaded, best for small applications.
Parallel GC Uses multiple threads for GC. Default for JVM before Java 9.
G1 (Garbage First) GC Low-latency GC, default from Java 9 onwards.
ZGC (Experimental) Ultra-low latency, handles large heaps efficiently.
🔹 Forcing Garbage Collection Manually
java
System.gc(); // Requests GC (Not guaranteed)
3. Weak References & Soft References
Java provides different types of references to manage memory efficiently.
🔹 Strong Reference (Default)
Prevents garbage collection as long as a reference exists.
Example:
java
String str = new String("Hello"); // Strong reference
3/6
🔹 Soft Reference (GC removes if memory is low)
Used for caching.
Example:
java
import java.lang.ref.SoftReference;
public class SoftRefExample {
public static void main(String[] args) {
String data = new String("Cache Data");
SoftReference<String> softRef = new SoftReference<>(data);
data = null; // Eligible for GC if memory is low
System.out.println(softRef.get()); // Still accessible
}
}
🔹 Weak Reference (GC removes in next cycle)
Used for memory-sensitive objects like WeakHashMap.
Example:
java
import java.lang.ref.WeakReference;
public class WeakRefExample {
public static void main(String[] args) {
String data = new String("Temporary Data");
WeakReference<String> weakRef = new WeakReference<>(data);
data = null; // Now weakly reachable
System.gc(); // Requests GC
System.out.println(weakRef.get()); // May return null
}
}
🔹 Phantom Reference (Used for finalization)
4/6
Used when the object is almost ready for GC.
Example:
java
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
public class PhantomRefExample {
public static void main(String[] args) {
String data = new String("Phantom Data");
ReferenceQueue<String> queue = new ReferenceQueue<>();
PhantomReference<String> phantomRef = new PhantomReference<>(data, queue);
data = null;
System.gc();
System.out.println(phantomRef.get()); // Always null
}
}
📌 Comparison of References:
Type When is it Collected? Example Use Case
Strong Never (unless set to null ) Regular object references
Soft If memory is low Caching, Image loading
Weak In next GC cycle WeakHashMap
Phantom Before object is finalized Resource cleanup
Summary
Stack stores method calls & local variables, while Heap stores objects.
Garbage Collector (GC) automatically removes unused objects.
Use Soft/Weak References for memory optimization.
Choose the right GC Algorithm based on application needs.
5/6
Would you like more details on GC tuning or JVM memory monitoring tools? 🚀
6/6
Core Java Best Practices
Reflection API & Annotations in Java
1. Reflection API
The Reflection API in Java allows inspection and manipulation of classes, methods, fields,
and constructors at runtime.
📌 Key Features of Reflection API
Inspect class details (methods, fields, constructors).
Modify private fields and invoke private methods.
Create objects dynamically.
🔹 Example: Getting Class Information
java
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;
class Example {
private String name;
public Example() {}
public void show() {
System.out.println("Hello, Reflection API!");
}
}
public class ReflectionDemo {
public static void main(String[] args) {
Class<?> obj = Example.class;
// Get Class Name
System.out.println("Class Name: " + obj.getName());
1/7
// Get Methods
Method[] methods = obj.getDeclaredMethods();
for (Method method : methods) {
System.out.println("Method: " + method.getName());
}
// Get Fields
Field[] fields = obj.getDeclaredFields();
for (Field field : fields) {
System.out.println("Field: " + field.getName());
}
// Get Constructors
Constructor<?>[] constructors = obj.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("Constructor: " + constructor.getName());
}
}
}
🔹 Modifying Private Fields Using Reflection
java
import java.lang.reflect.Field;
class Student {
private String name = "John";
public void display() {
System.out.println("Name: " + name);
}
}
public class ModifyPrivateField {
public static void main(String[] args) throws Exception {
Student student = new Student();
student.display();
// Access private field
Field field = Student.class.getDeclaredField("name");
2/7
field.setAccessible(true);
field.set(student, "Alice");
student.display();
}
}
🚀 Use Cases of Reflection API
Frameworks (Spring, Hibernate) use Reflection for dependency injection.
Testing (JUnit, Mockito) uses Reflection to invoke private methods.
Serialization/Deserialization libraries (Jackson, Gson).
2. Java Annotations
Annotations provide metadata about classes, methods, or fields.
🔹 Common Built-in Annotations
Annotation Description
@Override Ensures a method is overriding a superclass method.
@FunctionalInterface Ensures an interface has only one abstract method.
@SuppressWarnings Suppresses compiler warnings.
@Deprecated Marks a method/class as deprecated.
🔹 @Override Example
java
class Parent {
void display() {
System.out.println("Parent class");
}
}
class Child extends Parent {
@Override
3/7
void display() { // Ensures this method is actually overriding the parent method
System.out.println("Child class");
}
}
🔹 @FunctionalInterface Example
java
@FunctionalInterface
interface MyFunctionalInterface {
void greet();
}
public class FunctionalDemo {
public static void main(String[] args) {
MyFunctionalInterface obj = () -> System.out.println("Hello, Lambda!");
obj.greet();
}
}
🔹 @SuppressWarnings Example
java
public class SuppressWarningDemo {
@SuppressWarnings("deprecation")
public static void main(String[] args) {
OldClass obj = new OldClass();
obj.display();
}
}
class OldClass {
@Deprecated
void display() {
System.out.println("This method is deprecated");
}
}
🔹 @Deprecated Example
4/7
java
class OldVersion {
@Deprecated
public void oldMethod() {
System.out.println("This method is outdated.");
}
}
public class DeprecatedDemo {
public static void main(String[] args) {
OldVersion obj = new OldVersion();
obj.oldMethod(); // Warning: Deprecated method
}
}
3. Creating Custom Annotations
We can define our own annotations using @interface .
🔹 Steps to Create a Custom Annotation
1. Define the annotation using @interface .
2. Use @Retention to specify if it's available at runtime.
3. Use @Target to specify where it can be used (Class, Method, Field, etc.).
4. Apply the annotation to a method or class.
5. Use Reflection to process the annotation.
🔹 Example: Creating & Using Custom Annotations
java
import java.lang.annotation.*;
import java.lang.reflect.*;
@Retention(RetentionPolicy.RUNTIME) // Available at runtime
@Target(ElementType.METHOD) // Can be applied to methods
5/7
@interface MyAnnotation {
String value();
}
class CustomAnnotationExample {
@MyAnnotation(value = "Hello Annotation")
public void testMethod() {
System.out.println("Method Executed");
}
}
public class CustomAnnotationDemo {
public static void main(String[] args) throws Exception {
CustomAnnotationExample obj = new CustomAnnotationExample();
Method method = obj.getClass().getMethod("testMethod");
if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
System.out.println("Annotation Value: " + annotation.value());
}
obj.testMethod();
}
}
📌 Explanation:
@Retention(RetentionPolicy.RUNTIME) : Annotation is available at runtime.
@Target(ElementType.METHOD) : Can be applied only to methods.
Reflection API reads the annotation at runtime.
Summary
Reflection API allows dynamic class inspection and modification.
Annotations provide metadata for classes, methods, and variables.
Custom Annotations can be created for specific use cases.
6/7
Frameworks like Spring, Hibernate, and JUnit rely heavily on Reflection and
Annotations.
Would you like more details on Spring Boot annotations? 🚀
7/7
Core Java Best Practices
Inner Classes in Java
Inner classes in Java are classes defined within another class. They help group logically
related classes together, improve encapsulation, and enhance code readability.
1. Regular Inner Class (Member Inner Class)
A regular inner class is a non-static class defined inside another class. It has access to all
members of the outer class, including private members.
📌 Key Points
Requires an instance of the outer class to be instantiated.
Can access private members of the outer class.
🔹 Example: Regular Inner Class
java
class OuterClass {
private String message = "Hello from Outer Class";
// Inner Class
class InnerClass {
void display() {
System.out.println(message); // Accessing outer class private member
}
}
}
public class RegularInnerClassDemo {
public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass(); // Creating inner
class object
inner.display();
1/6
}
}
📌 Explanation:
InnerClass is a non-static member of OuterClass .
InnerClass can access the private message variable.
2. Static Nested Class
A static nested class is a static class inside another class. Unlike regular inner classes, it does
not require an instance of the outer class.
📌 Key Points
Can only access static members of the outer class.
Instantiated without an instance of the outer class.
🔹 Example: Static Nested Class
java
class OuterClass {
static String message = "Hello from Outer Class";
// Static Nested Class
static class StaticNestedClass {
void display() {
System.out.println(message); // Can access only static members
}
}
}
public class StaticNestedClassDemo {
public static void main(String[] args) {
OuterClass.StaticNestedClass nested = new OuterClass.StaticNestedClass(); //
No need for an OuterClass instance
nested.display();
2/6
}
}
📌 Explanation:
StaticNestedClass is declared with static , so it does not require an instance of
OuterClass .
It can only access static variables/methods from OuterClass .
3. Anonymous Inner Class
An anonymous inner class is a class without a name, created for one-time use. It is mainly
used with interfaces or abstract classes.
📌 Key Points
Defined and instantiated in a single expression.
Can be used to override methods of an interface or a superclass.
🔹 Example: Anonymous Inner Class using an Interface
java
interface Greeting {
void sayHello();
}
public class AnonymousInnerClassDemo {
public static void main(String[] args) {
Greeting greet = new Greeting() {
public void sayHello() {
System.out.println("Hello from Anonymous Inner Class!");
}
};
greet.sayHello();
}
}
📌 Explanation:
3/6
We created an anonymous inner class that implements the Greeting interface without
a separate class declaration.
🔹 Example: Anonymous Inner Class using a Class
java
abstract class Animal {
abstract void makeSound();
}
public class AnonymousClassExample {
public static void main(String[] args) {
Animal cat = new Animal() {
void makeSound() {
System.out.println("Meow! Meow!");
}
};
cat.makeSound();
}
}
📌 Explanation:
We created an anonymous inner class that extends Animal and overrides
makeSound() .
4. Local Inner Class
A local inner class is a class declared inside a method. It is accessible only within that
method.
📌 Key Points
Defined inside a method and cannot be accessed outside.
Can access local variables of the method if they are final or effectively final.
🔹 Example: Local Inner Class
4/6
java
class OuterClass {
void outerMethod() {
System.out.println("Inside Outer Method");
class LocalInnerClass {
void localDisplay() {
System.out.println("Inside Local Inner Class");
}
}
LocalInnerClass localInner = new LocalInnerClass();
localInner.localDisplay();
}
}
public class LocalInnerClassDemo {
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.outerMethod();
}
}
📌 Explanation:
LocalInnerClass is defined inside outerMethod() , so it cannot be used outside the
method.
Local inner classes can access variables from the enclosing method if they are final or
effectively final.
Summary
Requires Outer Class Access to Outer Class
Inner Class Type Static? Instance? Members
Regular Inner Class ❌ No ✅ Yes ✅ Yes (All Members)
Static Nested Class ✅ Yes ❌ No ❌ Only Static Members
5/6
Requires Outer Class Access to Outer Class
Inner Class Type Static? Instance? Members
Anonymous Inner ❌ No ✅ Yes ✅ Yes (All Members)
Class
Local Inner Class ❌ No ✅ Yes ✅ Yes (Final Variables Only)
Real-World Use Cases
✅ Regular Inner Class: Encapsulating helper classes that need access to private members.
✅ Static Nested Class: Utility classes like
Map.Entry in Java collections.
✅ Anonymous Inner Class: Event handling in GUI applications.
✅ Local Inner Class: Encapsulating logic within a method.
Would you like more examples on any specific type of inner class? 🚀
6/6
Core Java Best Practices
Java Networking
Java Networking allows communication between computers using TCP/IP protocols. Java
provides built-in classes in the java.net package to handle networking.
1. Sockets & HTTP Communication
📌 What is a Socket?
A socket is an endpoint for sending or receiving data across a network. Java supports two
types of sockets:
1. TCP Sockets (Reliable, Connection-Oriented)
2. UDP Sockets (Faster, Connectionless)
🔹 TCP Socket Programming
TCP (Transmission Control Protocol) ensures reliable data transfer.
🔸 Server Side (Socket Server)
java
import java.io.*;
import java.net.*;
public class TCPServer {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(5000)) {
System.out.println("Server is waiting for a client...");
Socket socket = serverSocket.accept();
System.out.println("Client connected!");
BufferedReader input = new BufferedReader(new
1/7
InputStreamReader(socket.getInputStream()));
PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
String clientMessage = input.readLine();
System.out.println("Client says: " + clientMessage);
output.println("Hello from Server!");
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
🔸 Client Side (Socket Client)
java
import java.io.*;
import java.net.*;
public class TCPClient {
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 5000)) {
BufferedReader input = new BufferedReader(new
InputStreamReader(socket.getInputStream()));
PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
output.println("Hello from Client!");
String serverMessage = input.readLine();
System.out.println("Server says: " + serverMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
}
📌 Explanation:
ServerSocket listens on port 5000.
2/7
Socket connects the client to the server.
BufferedReader & PrintWriter handle data transmission.
🔹 UDP Socket Programming
UDP (User Datagram Protocol) is faster but unreliable.
🔸 UDP Server
java
import java.net.*;
public class UDPServer {
public static void main(String[] args) {
try (DatagramSocket socket = new DatagramSocket(5000)) {
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
System.out.println("Server is waiting for a message...");
socket.receive(packet);
String received = new String(packet.getData(), 0, packet.getLength());
System.out.println("Client says: " + received);
} catch (Exception e) {
e.printStackTrace();
}
}
}
🔸 UDP Client
java
import java.net.*;
public class UDPClient {
public static void main(String[] args) {
try (DatagramSocket socket = new DatagramSocket()) {
String message = "Hello UDP Server!";
3/7
byte[] buffer = message.getBytes();
InetAddress address = InetAddress.getByName("localhost");
DatagramPacket packet = new DatagramPacket(buffer, buffer.length,
address, 5000);
socket.send(packet);
System.out.println("Message sent to server!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
📌 Key Differences Between TCP & UDP
Feature TCP (Sockets) UDP (DatagramSockets)
Connection Connection-oriented Connectionless
Reliability Reliable Unreliable
Speed Slower Faster
Usage File transfer, web browsing VoIP, streaming
2. URL & URLConnection
Java provides the java.net.URL and URLConnection classes to interact with URLs.
🔹 Fetching Webpage Content
java
import java.io.*;
import java.net.*;
public class URLReader {
public static void main(String[] args) {
try {
URL url = new URL("https://www.example.com");
BufferedReader reader = new BufferedReader(new
InputStreamReader(url.openStream()));
4/7
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
📌 Explanation:
URL.openStream() opens a stream to the webpage.
BufferedReader reads the webpage content line by line.
🔹 Sending an HTTP GET Request
java
import java.io.*;
import java.net.*;
public class HTTPGetRequest {
public static void main(String[] args) {
try {
URL url = new URL("https://jsonplaceholder.typicode.com/posts/1");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
BufferedReader reader = new BufferedReader(new
InputStreamReader(connection.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
} catch (Exception e) {
5/7
e.printStackTrace();
}
}
}
📌 Explanation:
HttpURLConnection is used to send GET requests.
getInputStream() reads the response.
🔹 Sending an HTTP POST Request
java
import java.io.*;
import java.net.*;
public class HTTPPostRequest {
public static void main(String[] args) {
try {
URL url = new URL("https://jsonplaceholder.typicode.com/posts");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
String jsonData = "{\"title\": \"foo\", \"body\": \"bar\", \"userId\":
1}";
OutputStream os = connection.getOutputStream();
os.write(jsonData.getBytes());
os.flush();
os.close();
BufferedReader reader = new BufferedReader(new
InputStreamReader(connection.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
6/7
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
📌 Explanation:
setRequestMethod("POST") sets the request type.
setDoOutput(true) allows writing data.
JSON data is sent using OutputStream .
Summary
Feature Key Classes
Sockets (TCP/UDP) Socket , ServerSocket , DatagramSocket , DatagramPacket
HTTP Communication HttpURLConnection
URL Handling URL , URLConnection
Real-World Use Cases
✅ Sockets (TCP/UDP) – Chat applications, multiplayer games
✅ URL & URLConnection – Web scraping, API calls
✅ HTTP Communication – REST API integration
Would you like additional details on any of these topics? 🚀
7/7
Core Java Best Practices
Java Security
Java provides various security mechanisms to protect data through Hashing, Encryption,
and Decryption techniques. These are essential for securing passwords, sensitive data, and
communication.
1. Hashing (MD5, SHA)
Hashing is a one-way function that converts data into a fixed-length value, making it
impossible to reverse. It's commonly used for password storage.
🔹 MD5 (Message Digest Algorithm 5)
MD5 produces a 128-bit hash value (32 hexadecimal characters). However, it is considered
insecure due to collision vulnerabilities.
Example: Hashing a String Using MD5
java
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Hashing {
public static String hashMD5(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest(input.getBytes());
StringBuilder hexString = new StringBuilder();
for (byte b : messageDigest) {
hexString.append(String.format("%02x", b));
}
return hexString.toString();
1/6
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
System.out.println("MD5 Hash: " + hashMD5("HelloWorld"));
}
}
📌 Output Example:
yaml
MD5 Hash: fc5e038d38a57032085441e7fe7010b0
🛑 Weakness: MD5 is vulnerable to hash collisions, where two different inputs produce the
same hash.
🔹 SHA (Secure Hash Algorithm)
SHA produces a more secure hash compared to MD5. Java supports multiple versions:
SHA-1: 160-bit hash (deprecated due to weaknesses)
SHA-256: 256-bit hash (more secure)
SHA-512: 512-bit hash (stronger security)
Example: Hashing a String Using SHA-256
java
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class SHAHashing {
public static String hashSHA256(String input) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] messageDigest = md.digest(input.getBytes());
2/6
StringBuilder hexString = new StringBuilder();
for (byte b : messageDigest) {
hexString.append(String.format("%02x", b));
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
System.out.println("SHA-256 Hash: " + hashSHA256("HelloWorld"));
}
}
📌 Output Example:
yaml
SHA-256 Hash: a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b53a4d6b6ddf0f4d5
✅ SHA-256 is widely used for password hashing, digital signatures, and data integrity.
2. Encryption & Decryption (AES, RSA)
Encryption converts plaintext into ciphertext, and decryption reverts it back to plaintext.
🔹 AES (Advanced Encryption Standard)
AES is a symmetric-key encryption algorithm (same key is used for encryption and
decryption). It supports 128-bit, 192-bit, and 256-bit key sizes.
Example: AES Encryption & Decryption
java
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
3/6
import javax.crypto.SecretKey;
import java.util.Base64;
public class AESEncryption {
public static void main(String[] args) throws Exception {
String data = "HelloAES";
// Generate AES Key
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128); // 128-bit AES
SecretKey secretKey = keyGen.generateKey();
// Encrypt Data
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedData = cipher.doFinal(data.getBytes());
String encryptedText = Base64.getEncoder().encodeToString(encryptedData);
System.out.println("Encrypted: " + encryptedText);
// Decrypt Data
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decryptedData =
cipher.doFinal(Base64.getDecoder().decode(encryptedText));
System.out.println("Decrypted: " + new String(decryptedData));
}
}
📌 Output Example:
pgsql
Encrypted: s9BbxHTH8T6UYWd/KT8vxQ==
Decrypted: HelloAES
✅ AES is widely used in file encryption, database encryption, and secure communication.
🔹 RSA (Rivest-Shamir-Adleman)
RSA is an asymmetric encryption algorithm, meaning it uses:
4/6
Public Key (for encryption)
Private Key (for decryption)
Example: RSA Encryption & Decryption
java
import java.security.*;
import javax.crypto.Cipher;
import java.util.Base64;
public class RSAEncryption {
public static void main(String[] args) throws Exception {
String data = "HelloRSA";
// Generate Key Pair
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// Encrypt Data
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedData = cipher.doFinal(data.getBytes());
String encryptedText = Base64.getEncoder().encodeToString(encryptedData);
System.out.println("Encrypted: " + encryptedText);
// Decrypt Data
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedData =
cipher.doFinal(Base64.getDecoder().decode(encryptedText));
System.out.println("Decrypted: " + new String(decryptedData));
}
}
📌 Output Example:
makefile
Encrypted: ZmVmM3NydDg...
5/6
Decrypted: HelloRSA
✅ RSA is commonly used in SSL/TLS certificates, digital signatures, and secure email
communication.
🔹 Key Differences Between AES & RSA
Feature AES RSA
Type Symmetric Asymmetric
Key Used Single Secret Key Public & Private Key
Speed Fast Slower
Usage Data encryption Secure communication, digital signatures
Summary
Security Feature Algorithm Use Case
Hashing MD5, SHA-256 Password hashing, data integrity
Encryption AES File encryption, database encryption
Asymmetric Encryption RSA Digital signatures, secure key exchange
Real-World Use Cases
🔹 Hashing: Secure password storage in databases
🔹 AES Encryption: Encrypting sensitive files
🔹 RSA Encryption: Secure web communication (SSL/TLS)
Would you like a more detailed explanation or a different example? 🚀
6/6
Core Java Best Practices
I'll provide an in-depth explanation of each Java interview-specific topic, starting with key
differences and then covering common coding questions.
1. Differences Between Important Java Concepts
🔹 == vs .equals()
Feature == Operator .equals() Method
Type Compares memory addresses Compares content (for objects)
Use Case Used for primitive types and object Used for content comparison in objects
references
Example "hello" == "hello" → true (same "hello".equals("hello") → true
(Strings) reference in String Pool)
Example new String("abc") == new new String("abc").equals(new
(Objects) String("abc") → false String("abc")) → true
Example Code
java
String s1 = new String("Java");
String s2 = new String("Java");
System.out.println(s1 == s2); // false (different memory locations)
System.out.println(s1.equals(s2)); // true (same content)
🔹 StringBuffer vs StringBuilder
Feature StringBuffer StringBuilder
Mutability Mutable Mutable
1/8
Feature StringBuffer StringBuilder
Thread-Safety Thread-safe (synchronized) Not thread-safe (faster)
Performance Slower due to synchronization Faster as it is not synchronized
Example Code
java
StringBuffer sb1 = new StringBuffer("Hello");
sb1.append(" World");
System.out.println(sb1); // Hello World
StringBuilder sb2 = new StringBuilder("Hello");
sb2.append(" World");
System.out.println(sb2); // Hello World
🔹 ArrayList vs LinkedList
Feature ArrayList LinkedList
Implementation Dynamic array Doubly linked list
Insertion/Deletion Slow (shifting required) Fast (no shifting needed)
Random Access Fast (direct index access) Slow (traverse needed)
Memory Usage Less (no extra pointers) More (extra pointers for nodes)
Example Code
java
List<Integer> arrayList = new ArrayList<>();
List<Integer> linkedList = new LinkedList<>();
🔹 HashMap vs Hashtable
2/8
Feature HashMap Hashtable
Thread-Safety Not synchronized Synchronized
Performance Faster Slower
Allows null Keys/Values? Yes No
Example Code
java
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(null, "Value"); // Allowed
Hashtable<Integer, String> hashtable = new Hashtable<>();
// hashtable.put(null, "Value"); // Throws NullPointerException
🔹 final vs finally vs finalize
Feature final finally finalize
Usage Keyword for constants, method Cleanup block in Garbage collection hook
overriding prevention try-catch
Example final int x = 10; try { ... } finally protected void
{ ... } finalize() { }
Example Code
java
// final keyword
final int x = 10;
// finally block
try {
System.out.println("Inside try");
} finally {
System.out.println("Inside finally");
}
// finalize method
3/8
class Test {
protected void finalize() { System.out.println("Object garbage collected"); }
}
2. Common Coding Questions
🔹 Fibonacci Series
Print Fibonacci series up to n numbers.
java
public class Fibonacci {
public static void main(String[] args) {
int n = 10, a = 0, b = 1;
System.out.print(a + " " + b);
for (int i = 2; i < n; i++) {
int next = a + b;
System.out.print(" " + next);
a = b;
b = next;
}
}
}
📌 Output:
0 1 1 2 3 5 8 13 21 34
🔹 Palindrome Check (String & Number)
java
4/8
public class Palindrome {
public static boolean isPalindrome(String str) {
return str.equals(new StringBuilder(str).reverse().toString());
}
public static boolean isPalindrome(int num) {
int rev = 0, temp = num;
while (temp > 0) {
rev = rev * 10 + temp % 10;
temp /= 10;
}
return rev == num;
}
public static void main(String[] args) {
System.out.println(isPalindrome("madam")); // true
System.out.println(isPalindrome(121)); // true
}
}
🔹 Sorting Algorithms
🔸 Bubble Sort
java
public class BubbleSort {
public static void bubbleSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
5/8
}
}
🔸 Quick Sort
java
public class QuickSort {
public static void quickSort(int[] arr, int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
private static int partition(int[] arr, int low, int high) {
int pivot = arr[high], i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return i + 1;
}
}
🔹 Find Duplicates in Array
java
import java.util.HashSet;
6/8
public class FindDuplicates {
public static void findDuplicates(int[] arr) {
HashSet<Integer> set = new HashSet<>();
for (int num : arr) {
if (!set.add(num)) {
System.out.println("Duplicate found: " + num);
}
}
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 2, 5, 6, 1};
findDuplicates(arr);
}
}
🔹 Reverse a String
java
public class ReverseString {
public static void main(String[] args) {
String str = "Hello";
String reversed = new StringBuilder(str).reverse().toString();
System.out.println("Reversed: " + reversed);
}
}
📌 Output:
makefile
Reversed: olleH
7/8
Would you like more coding challenges or deeper
explanations on any topic?🚀
8/8