| title | description | author | date |
|---|---|---|---|
Top 150+ Java Interview Questions & Answers |
Comprehensive guide to Java interview questions categorized by topic |
Technical Interview Prep |
2026-02-13 |
- Core Java Basics
- Object-Oriented Programming (OOP)
- Java Collections Framework
- Multithreading & Concurrency
- Exception Handling
- Java 8+ Features
- String & Memory Management
- JDBC & Database
- Design Patterns
- Advanced Java Concepts
Java is a high-level, object-oriented programming language developed by Sun Microsystems (now Oracle). Its main features include:
- Platform Independence: Write Once, Run Anywhere (WORA) through JVM
- Object-Oriented: Everything is an object with data and behavior
- Secure: Built-in security features and no explicit pointers
- Robust: Strong memory management and exception handling
- Multithreaded: Built-in support for concurrent execution
- Architecture Neutral: Bytecode can run on any platform with JVM
- JVM (Java Virtual Machine): Runtime environment that executes Java bytecode. Platform-dependent.
- JRE (Java Runtime Environment): JVM + library classes. Needed to run Java applications.
- JDK (Java Development Kit): JRE + development tools (compiler, debugger). Needed to develop Java applications.
- Heap: Stores objects and their instance variables. Shared among all threads.
- Stack: Stores local variables and method calls. One stack per thread.
- Method Area: Stores class structure, method data, runtime constant pool.
- PC Register: Stores address of current instruction being executed.
- Native Method Stack: Contains native method information.
==: Compares references (memory addresses) for objects, values for primitivesequals(): Compares object contents based on the implementation
String s1 = new String("hello");
String s2 = new String("hello");
s1 == s2 // false (different objects)
s1.equals(s2) // true (same content)- private: Accessible only within the same class
- default (no modifier): Accessible within the same package
- protected: Accessible within the same package and subclasses
- public: Accessible from anywhere
Static members:
- Belong to the class, not instances
- Shared among all instances
- Can be accessed without creating an object
- Loaded when class is loaded
Non-static members:
- Belong to individual instances
- Each instance has its own copy
- Require object creation to access
A constructor is a special method that initializes objects. It has the same name as the class and no return type.
public class Person {
String name;
// Default constructor
public Person() {
name = "Unknown";
}
// Parameterized constructor
public Person(String name) {
this.name = name;
}
}Having multiple constructors with different parameter lists in the same class.
public class Box {
int width, height;
Box() { width = height = 0; }
Box(int side) { width = height = side; }
Box(int w, int h) { width = w; height = h; }
}Multiple methods with the same name but different parameters in the same class.
public class Calculator {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
int add(int a, int b, int c) { return a + b + c; }
}Classes that encapsulate primitive types to use them as objects. Each primitive has a corresponding wrapper class: Integer, Double, Boolean, Character, etc.
int primitive = 10;
Integer wrapper = Integer.valueOf(10); // Boxing
int back = wrapper.intValue(); // UnboxingAutoboxing: Automatic conversion of primitive to wrapper class Unboxing: Automatic conversion of wrapper class to primitive
// Autoboxing
Integer obj = 5; // Compiler converts to Integer.valueOf(5)
// Unboxing
int num = obj; // Compiler converts to obj.intValue()this: Refers to current instance of the classsuper: Refers to parent class instance
class Parent {
int x = 10;
}
class Child extends Parent {
int x = 20;
void display() {
System.out.println(this.x); // 20 (current class)
System.out.println(super.x); // 10 (parent class)
}
}Yes, but JVM only calls public static void main(String[] args).
public class Main {
public static void main(String[] args) {
System.out.println("Standard main");
}
public static void main(int x) {
System.out.println("Overloaded main");
}
}Static block executes once when class is loaded, before main method.
public class Test {
static {
System.out.println("Static block executed");
}
public static void main(String[] args) {
System.out.println("Main method");
}
}
// Output: Static block executed, then Main methodExecutes when instance is created, before constructor.
public class Test {
{
System.out.println("Instance block");
}
Test() {
System.out.println("Constructor");
}
}
// Output: Instance block, then ConstructorJava is strictly pass by value. For objects, the value of the reference is passed.
void modify(int x) {
x = 10; // Original not affected
}
void modify(Person p) {
p.name = "John"; // Object is modified
p = new Person(); // Reference change doesn't affect original
}A namespace that organizes classes and interfaces. Prevents naming conflicts and controls access.
package com.example.myapp;
import java.util.ArrayList;
import com.example.util.*;Used in hash-based collections (HashMap, HashSet). Objects that are equal must have the same hashCode.
@Override
public int hashCode() {
return Objects.hash(id, name);
}- If
a.equals(b)is true, thena.hashCode() == b.hashCode() - If
hashCode()is equal,equals()may or may not be true - If you override
equals(), you must overridehashCode()
Variable arguments allow method to accept zero or more arguments of specified type.
public void print(String... messages) {
for (String msg : messages) {
System.out.println(msg);
}
}
print("A", "B", "C");- Encapsulation: Bundling data and methods, hiding internal details
- Inheritance: Creating new classes from existing ones
- Polymorphism: One interface, multiple implementations
- Abstraction: Hiding implementation details, showing only functionality
Encapsulation is wrapping data (variables) and code (methods) together as a single unit, and restricting access using access modifiers.
public class Account {
private double balance; // Hidden
public double getBalance() { return balance; }
public void deposit(double amount) { balance += amount; }
}Inheritance allows a class to inherit properties and methods from another class, promoting code reuse.
public class Animal {
void eat() { System.out.println("Eating..."); }
}
public class Dog extends Animal {
void bark() { System.out.println("Barking..."); }
}- Single Inheritance: Class extends one class
- Multilevel Inheritance: Class extends a class that extends another
- Hierarchical Inheritance: Multiple classes extend one class
- Multiple Inheritance: Not supported through classes, achieved through interfaces
Polymorphism allows objects to take multiple forms. Two types:
Compile-time (Method Overloading):
void print(int a) { }
void print(String s) { }Runtime (Method Overriding):
class Animal { void sound() { } }
class Dog extends Animal { void sound() { System.out.println("Bark"); } }Redefining a superclass method in a subclass with the same signature.
class Parent {
void display() { System.out.println("Parent"); }
}
class Child extends Parent {
@Override
void display() { System.out.println("Child"); }
}| Overloading | Overriding |
|---|---|
| Same class | Different classes (inheritance) |
| Different parameters | Same signature |
| Compile-time polymorphism | Runtime polymorphism |
| Can have different return types | Must have compatible return types |
Abstraction hides implementation details and shows only essential features. Achieved through abstract classes and interfaces.
abstract class Shape {
abstract void draw(); // No implementation
}
class Circle extends Shape {
void draw() { System.out.println("Drawing circle"); }
}| Abstract Class | Interface |
|---|---|
| Can have concrete methods | All methods abstract (before Java 8) |
| Can have instance variables | Only constants (public static final) |
| Single inheritance | Multiple inheritance |
| Can have constructors | Cannot have constructors |
Uses extends |
Uses implements |
No, abstract classes cannot be instantiated directly. You can only create instances of concrete subclasses.
abstract class Animal { }
class Dog extends Animal { }
// Animal a = new Animal(); // Error
Animal a = new Dog(); // CorrectInheritance (IS-A): Class extends another class Composition (HAS-A): Class contains instances of other classes
// Inheritance
class Car extends Vehicle { }
// Composition
class Car {
private Engine engine; // Car HAS-A Engine
private Wheel[] wheels;
}A contract that defines methods without implementation (before Java 8). Classes implement interfaces.
interface Drawable {
void draw();
default void print() { // Java 8+
System.out.println("Printing");
}
static void show() { // Java 8+
System.out.println("Showing");
}
}Yes, interfaces can extend multiple interfaces.
interface A { void methodA(); }
interface B { void methodB(); }
interface C extends A, B {
void methodC();
}An interface with no methods, used to mark classes for special treatment.
// Examples: Serializable, Cloneable, Remote
class MyClass implements Serializable { }super(): Calls parent class constructorthis(): Calls another constructor in same class
class Parent {
Parent(int x) { }
}
class Child extends Parent {
Child() {
this(10); // Calls Child(int)
}
Child(int x) {
super(x); // Calls Parent(int)
}
}Calling one constructor from another in the same or parent class.
class Example {
Example() {
this(10); // Constructor chaining
}
Example(int x) {
System.out.println(x);
}
}Yes, used in Singleton pattern and utility classes.
class Singleton {
private static Singleton instance;
private Singleton() { } // Private constructor
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}Multiple inheritance conflict when two parent classes have same method. Java solves this using interfaces.
interface A { default void show() { } }
interface B { default void show() { } }
class C implements A, B {
public void show() { // Must override
A.super.show(); // Can call specific interface method
}
}Overriding method can return subtype of parent method's return type.
class Animal {
Animal getAnimal() { return this; }
}
class Dog extends Animal {
@Override
Dog getAnimal() { // Covariant return type
return this;
}
}- Final variable: Cannot be changed (constant)
- Final method: Cannot be overridden
- Final class: Cannot be inherited
final class ImmutableClass { }
final int MAX = 100;
class Parent {
final void show() { }
}A unified architecture for representing and manipulating collections, providing interfaces (List, Set, Map, Queue) and implementations (ArrayList, HashSet, HashMap, etc.).
- Collection: Interface that represents a group of objects
- Collections: Utility class with static methods for operating on collections
| ArrayList | LinkedList |
|---|---|
| Dynamic array | Doubly linked list |
| Fast random access O(1) | Slow random access O(n) |
| Slow insertion/deletion O(n) | Fast insertion/deletion O(1) |
| Less memory overhead | More memory (stores references) |
| ArrayList | Vector |
|---|---|
| Not synchronized | Synchronized |
| Faster | Slower |
| Grows by 50% | Grows by 100% |
| Preferred for single-threaded | Legacy, thread-safe |
| HashSet | TreeSet |
|---|---|
| Unordered | Sorted (natural or comparator) |
| O(1) operations | O(log n) operations |
| Allows one null | No null elements |
| Uses hashing | Uses Red-Black tree |
| HashMap | Hashtable |
|---|---|
| Not synchronized | Synchronized |
| Allows one null key, multiple null values | No null keys or values |
| Faster | Slower |
| Introduced in Java 1.2 | Legacy class (Java 1.0) |
| HashMap | TreeMap |
|---|---|
| Unordered | Sorted by keys |
| O(1) operations | O(log n) operations |
| Allows null key | No null keys |
| Uses hashing | Uses Red-Black tree |
HashMap uses an array of buckets. Each bucket is a linked list (or tree in Java 8+).
- Hash function converts key to index
- If no collision, store directly
- If collision, add to linked list/tree
- Load factor (default 0.75) triggers resizing
// Simplified internals
bucket_index = hashCode(key) & (array_length - 1);| Iterator | ListIterator |
|---|---|
| Forward only | Bidirectional |
| Works on all collections | Only for List |
| Cannot add elements | Can add elements |
| Methods: hasNext(), next(), remove() | Additional: hasPrevious(), previous(), add() |
Iterators throw ConcurrentModificationException if collection is modified during iteration (except through iterator's own methods).
List<String> list = new ArrayList<>();
list.add("A");
for (String s : list) {
list.add("B"); // Throws ConcurrentModificationException
}Thread-safe HashMap alternative that allows concurrent reads and writes without locking the entire map.
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("key", 1); // Thread-safe| ConcurrentHashMap | Hashtable |
|---|---|
| Locks only segment | Locks entire map |
| Better performance | Poor performance |
| Allows null in values (not keys) | No null keys or values |
| Java 1.5+ | Legacy (Java 1.0) |
Thread-safe queue that supports operations that wait for queue to become non-empty or space to become available.
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
queue.put(1); // Blocks if full
Integer value = queue.take(); // Blocks if emptypoll(): Returns null if queue is emptyremove(): Throws exception if queue is empty
Queue<Integer> queue = new LinkedList<>();
queue.poll(); // Returns null
queue.remove(); // Throws NoSuchElementExceptionQueue where elements are ordered by natural ordering or comparator.
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.add(5);
pq.add(1);
pq.add(3);
System.out.println(pq.poll()); // 1 (smallest element)Specialized Set and Map implementations for enum types, highly efficient.
enum Day { MON, TUE, WED }
EnumSet<Day> weekend = EnumSet.of(Day.SAT, Day.SUN);
EnumMap<Day, String> schedule = new EnumMap<>(Day.class);// Using Comparable (natural ordering)
class Person implements Comparable<Person> {
public int compareTo(Person other) {
return this.age - other.age;
}
}
Collections.sort(personList);
// Using Comparator (custom ordering)
Collections.sort(personList, (p1, p2) -> p1.name.compareTo(p2.name));HashMap that maintains insertion order.
LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
map.put("A", 1);
map.put("B", 2);
// Iteration order: A, B (insertion order)Uses reference equality (==) instead of equals() for key comparison.
IdentityHashMap<String, Integer> map = new IdentityHashMap<>();
String s1 = new String("key");
String s2 = new String("key");
map.put(s1, 1);
map.put(s2, 2);
System.out.println(map.size()); // 2 (different references)Creates thread-safe wrapper around non-synchronized list.
List<String> list = Collections.synchronizedList(new ArrayList<>());
// Manual synchronization needed for iteration
synchronized(list) {
for (String s : list) {
System.out.println(s);
}
}A thread is a lightweight subprocess, the smallest unit of processing. Java supports multithreading through the Thread class and Runnable interface.
Method 1: Extending Thread class
class MyThread extends Thread {
public void run() {
System.out.println("Thread running");
}
}
MyThread t = new MyThread();
t.start();Method 2: Implementing Runnable interface
class MyRunnable implements Runnable {
public void run() {
System.out.println("Thread running");
}
}
Thread t = new Thread(new MyRunnable());
t.start();start(): Creates a new thread and invokesrun()in that threadrun(): Executes in the same thread, no new thread is created
- NEW: Thread created but not started
- RUNNABLE: Thread executing or ready to execute
- BLOCKED: Waiting for monitor lock
- WAITING: Waiting indefinitely for another thread
- TIMED_WAITING: Waiting for specific time
- TERMINATED: Thread completed execution
Synchronization controls access to shared resources by multiple threads, preventing data inconsistency.
public synchronized void increment() {
count++;
}
// Or synchronized block
public void increment() {
synchronized(this) {
count++;
}
}- Synchronized method: Locks entire method on the object
- Synchronized block: Locks only specific code section, more granular control
// Method level
synchronized void method() { }
// Block level
void method() {
synchronized(this) { }
}Deadlock occurs when two or more threads are blocked forever, waiting for each other.
Thread1: locks A, waits for B
Thread2: locks B, waits for A
// Both wait forevervolatile ensures that variable changes are visible to all threads immediately. Prevents caching in thread-local memory.
private volatile boolean flag = true;| wait() | sleep() |
|---|---|
| Object class method | Thread class method |
| Releases lock | Doesn't release lock |
| Must be in synchronized context | Can be called anywhere |
| Woken by notify()/notifyAll() | Wakes after time expires |
Framework for managing thread pools and asynchronous task execution.
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(() -> System.out.println("Task executed"));
executor.shutdown();// Fixed thread pool
ExecutorService fixed = Executors.newFixedThreadPool(5);
// Cached thread pool (creates threads as needed)
ExecutorService cached = Executors.newCachedThreadPool();
// Single thread executor
ExecutorService single = Executors.newSingleThreadExecutor();
// Scheduled thread pool
ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(3);| Runnable | Callable |
|---|---|
| No return value | Returns value |
| Cannot throw checked exception | Can throw exception |
| run() method | call() method |
Callable<Integer> task = () -> {
return 42;
};
Future<Integer> future = executor.submit(task);
Integer result = future.get(); // Blocks until completeRepresents result of asynchronous computation.
Future<String> future = executor.submit(() -> "Result");
if (future.isDone()) {
String result = future.get(); // Blocking
}
future.cancel(true); // Cancel taskSynchronization aid that allows threads to wait until set of operations complete.
CountDownLatch latch = new CountDownLatch(3);
// Worker threads
for (int i = 0; i < 3; i++) {
new Thread(() -> {
System.out.println("Working...");
latch.countDown();
}).start();
}
latch.await(); // Wait until count reaches 0
System.out.println("All tasks complete");Synchronization point where threads wait for each other.
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("All threads reached barrier");
});
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
System.out.println("Waiting at barrier");
barrier.await();
} catch (Exception e) { }
}).start();
}Controls number of threads accessing a resource.
Semaphore semaphore = new Semaphore(3); // Max 3 threads
semaphore.acquire(); // Get permit
try {
// Access resource
} finally {
semaphore.release(); // Release permit
}Advanced locking mechanism with more features than synchronized.
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
// Critical section
} finally {
lock.unlock();
}
// Try lock with timeout
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try {
// Got lock
} finally {
lock.unlock();
}
}Allows multiple readers or single writer.
ReadWriteLock rwLock = new ReentrantReadWriteLock();
// Multiple readers can acquire
rwLock.readLock().lock();
try {
// Read data
} finally {
rwLock.readLock().unlock();
}
// Only one writer
rwLock.writeLock().lock();
try {
// Write data
} finally {
rwLock.writeLock().unlock();
}Provides thread-local variables where each thread has its own copy.
ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
threadLocal.set(42);
Integer value = threadLocal.get(); // Thread-specific value
threadLocal.remove();Executor service for recursive tasks that can be broken into smaller subtasks.
class SumTask extends RecursiveTask<Long> {
protected Long compute() {
if (taskIsSmall()) {
return computeDirectly();
} else {
SumTask left = new SumTask();
SumTask right = new SumTask();
left.fork();
return right.compute() + left.join();
}
}
}An exception is an event that disrupts normal program flow. Java uses exception handling to manage runtime errors.
Throwable
├── Error (Unchecked, system errors)
└── Exception
├── RuntimeException (Unchecked)
│ ├── NullPointerException
│ ├── ArrayIndexOutOfBoundsException
│ └── ArithmeticException
└── Checked Exceptions
├── IOException
├── SQLException
└── ClassNotFoundException
Checked Exceptions:
- Must be caught or declared
- Compile-time checking
- Examples: IOException, SQLException
Unchecked Exceptions:
- Not required to catch/declare
- Runtime exceptions
- Examples: NullPointerException, ArrayIndexOutOfBoundsException
- throw: Used to explicitly throw an exception
- throws: Declares exceptions a method might throw
void method() throws IOException {
throw new IOException("Error");
}- final: Keyword for constants, prevent inheritance/override
- finally: Block that always executes after try-catch
- finalize(): Method called by garbage collector before object destruction (deprecated)
Yes, try can be used with finally without catch.
try {
// code
} finally {
// cleanup
}Yes, you can have multiple catch blocks for different exception types.
try {
// code
} catch (IOException e) {
// handle IO exception
} catch (SQLException e) {
// handle SQL exception
} catch (Exception e) {
// handle general exception
}Automatically closes resources that implement AutoCloseable.
try (FileReader fr = new FileReader("file.txt")) {
// Use resource
} // Automatically closedUser-defined exception class extending Exception or RuntimeException.
public class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message);
}
}The exception propagates up the call stack. If not caught anywhere, the program terminates and stack trace is printed.
When an exception is thrown and not caught, it propagates up the call stack to the calling method.
void method1() throws IOException {
method2(); // Exception propagates here
}
void method2() throws IOException {
throw new IOException(); // Exception thrown here
}Yes, you can catch and rethrow an exception.
try {
// code
} catch (IOException e) {
logger.log(e);
throw e; // Rethrow
}- Error: Serious problems that applications shouldn't catch (OutOfMemoryError, StackOverflowError)
- Exception: Conditions that applications should catch and handle
try {
// code
} catch (Exception e) {
e.printStackTrace(); // Prints full stack trace
String msg = e.getMessage(); // Gets error message only
}Yes, but it overrides any return in try/catch block (not recommended).
int test() {
try {
return 1;
} finally {
return 2; // This value is returned
}
}Exceptions that occur in try-with-resources when closing resources.
try (Resource r1 = new Resource(); Resource r2 = new Resource()) {
// code
} // If both throw exceptions, first is main, second is suppressed
catch (Exception e) {
Throwable[] suppressed = e.getSuppressed();
}Wrapping one exception in another to preserve stack trace.
try {
// code
} catch (SQLException e) {
throw new DataAccessException("Database error", e);
}Yes, using multi-catch (Java 7+).
try {
// code
} catch (IOException | SQLException e) {
// Handle both exceptions
}Most specific exceptions first, most general last.
try {
// code
} catch (FileNotFoundException e) { // Specific
// handle
} catch (IOException e) { // General
// handle
}Lambda expressions provide a concise way to represent anonymous functions.
// Before Java 8
Runnable r = new Runnable() {
public void run() {
System.out.println("Running");
}
};
// Java 8+
Runnable r = () -> System.out.println("Running");An interface with exactly one abstract method. Can have default and static methods.
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
}
Calculator add = (a, b) -> a + b;Stream API provides functional-style operations for processing collections.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.filter(n -> n % 2 == 0)
.mapToInt(Integer::intValue)
.sum();- map(): Transforms each element to another object
- flatMap(): Flattens nested structures into single stream
// map
List<String> words = Arrays.asList("Hello", "World");
words.stream().map(String::length); // [5, 5]
// flatMap
List<List<Integer>> nested = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4)
);
nested.stream().flatMap(List::stream); // [1, 2, 3, 4]Container object that may or may not contain a value, avoiding null pointer exceptions.
Optional<String> optional = Optional.ofNullable(getValue());
optional.ifPresent(System.out::println);
String value = optional.orElse("default");Methods with implementation in interfaces, allowing interface evolution without breaking existing implementations.
interface Vehicle {
default void start() {
System.out.println("Vehicle starting");
}
}Shorthand notation for lambda expressions calling existing methods.
// Lambda
list.forEach(s -> System.out.println(s));
// Method reference
list.forEach(System.out::println);Intermediate: Return stream, lazy (filter, map, sorted) Terminal: Trigger processing, return result (collect, forEach, reduce)
list.stream()
.filter(x -> x > 5) // Intermediate
.collect(Collectors.toList()); // Terminal- Static:
ClassName::staticMethod - Instance:
object::instanceMethod - Particular type:
ClassName::instanceMethod - Constructor:
ClassName::new
- forEach(): May process in any order (parallel streams)
- forEachOrdered(): Maintains encounter order even in parallel
Utility to transform stream elements into collections or other data structures.
// Collect to List
List<String> list = stream.collect(Collectors.toList());
// Collect to Set
Set<String> set = stream.collect(Collectors.toSet());
// Collect to Map
Map<Integer, String> map = stream.collect(
Collectors.toMap(Person::getId, Person::getName)
);
// Grouping
Map<String, List<Person>> byCity = persons.stream()
.collect(Collectors.groupingBy(Person::getCity));
// Joining strings
String result = stream.collect(Collectors.joining(", "));
// Partitioning
Map<Boolean, List<Integer>> partition = numbers.stream()
.collect(Collectors.partitioningBy(n -> n > 50));Combines stream elements into single result.
// Sum
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
// Max
Optional<Integer> max = numbers.stream().reduce(Integer::max);
// Concatenate
String result = strings.stream().reduce("", (a, b) -> a + b);- findFirst(): Returns first element, deterministic
- findAny(): Returns any element, non-deterministic in parallel streams
Optional<Integer> first = stream.findFirst();
Optional<Integer> any = stream.parallel().findAny();Intermediate operation for debugging, performs action on each element without modifying stream.
list.stream()
.peek(x -> System.out.println("Before filter: " + x))
.filter(x -> x > 5)
.peek(x -> System.out.println("After filter: " + x))
.collect(Collectors.toList());- map(): Transforms each element to another object (one-to-one)
- flatMap(): Flattens nested structures into single stream (one-to-many)
// map: Stream<String[]> -> Stream<String[]>
Stream<String[]> stream1 = words.stream().map(w -> w.split(""));
// flatMap: Stream<String[]> -> Stream<String>
Stream<String> stream2 = words.stream()
.flatMap(w -> Arrays.stream(w.split("")));Streams that use multiple threads for processing.
// Sequential
list.stream().forEach(System.out::println);
// Parallel
list.parallelStream().forEach(System.out::println);
// Convert to parallel
list.stream().parallel().forEach(System.out::println);Asynchronous computation with callback support.
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return "Result";
});
future.thenApply(result -> result.toUpperCase())
.thenAccept(System.out::println);
// Combining futures
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<String> combined = f1.thenCombine(f2,
(s1, s2) -> s1 + " " + s2);Reasons for immutability:
- Security: Prevents modification of sensitive data
- Thread-safety: No synchronization needed
- Caching: String pool possible
- Performance: Hashcode can be cached
Special memory region in heap where Java stores string literals. Strings with same content share memory.
String s1 = "Hello"; // Pool
String s2 = "Hello"; // Same reference
String s3 = new String("Hello"); // Heap
s1 == s2 // true
s1 == s3 // false| String | StringBuilder | StringBuffer |
|---|---|---|
| Immutable | Mutable | Mutable |
| Thread-safe (immutable) | Not thread-safe | Thread-safe |
| Slower for concatenation | Faster | Moderate speed |
| Use for constant strings | Single-threaded manipulation | Multi-threaded manipulation |
Automatic memory management that reclaims memory from objects no longer referenced.
- Serial GC: Single thread, small applications
- Parallel GC: Multiple threads, throughput focused
- CMS (Concurrent Mark Sweep): Low pause times
- G1 GC: Large heaps, predictable pause times
- ZGC: Very low pause times, large heaps
- Nullify references:
obj = null; - Reassign reference:
obj = new Object(); - Anonymous objects:
new Object(); - Island of isolation
Called by garbage collector before reclaiming object memory. Deprecated in Java 9.
protected void finalize() throws Throwable {
// Cleanup code
}Memory leak occurs when objects are no longer used but still referenced, preventing garbage collection.
- Strong: Normal references, never collected if reachable
- Soft: Collected when memory is low
- Weak: Collected in next GC cycle
- Phantom: Collected, used for cleanup actions
Returns canonical representation from string pool.
String s1 = new String("Hello").intern();
String s2 = "Hello";
s1 == s2 // true// Using + operator (creates StringBuilder internally)
String s1 = "Hello" + " " + "World";
// Using concat() method
String s2 = "Hello".concat(" ").concat("World");
// Using StringBuilder (most efficient for loops)
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append(s);
}Default size varies by JVM. Can be configured using -XX:StringTableSize=N.
| Stack | Heap |
|---|---|
| Stores local variables, method calls | Stores objects |
| LIFO structure | No specific order |
| Faster access | Slower access |
| Fixed size per thread | Larger, shared |
| Automatic memory management | Garbage collected |
- Serial GC: Single-threaded, simple applications
- Parallel GC: Multi-threaded, throughput-focused
- CMS (Concurrent Mark Sweep): Low pause times, deprecated
- G1 GC: Default for Java 9+, region-based
- ZGC: Ultra-low pause times, large heaps
- Shenandoah: Low pause times, concurrent
- Minor GC: Cleans young generation (frequent, fast)
- Major GC: Cleans old generation (less frequent, slower)
- Full GC: Cleans entire heap (slowest)
Both suggest JVM to run garbage collection, but don't guarantee it.
System.gc(); // Calls Runtime.getRuntime().gc()
Runtime.getRuntime().gc();Replaced PermGen space. Stores class metadata, grows dynamically.
// Configure metaspace
-XX:MetaspaceSize=128m
-XX:MaxMetaspaceSize=512mMemory leak occurs when objects are referenced but not used.
Common causes:
- Static collections
- Unclosed resources
- Inner class references
- Thread local variables
Prevention:
// Close resources
try (FileReader fr = new FileReader("file")) { }
// Clear collections
map.clear();
// Nullify references
object = null;
// Remove thread local
threadLocal.remove();Initial capacity is 16. Grows as needed.
StringBuilder sb = new StringBuilder(); // Capacity 16
StringBuilder sb2 = new StringBuilder(100); // Capacity 100
int capacity = sb.capacity();- Java 6: Returns substring sharing original char array (memory leak risk)
- Java 7+: Creates new char array (no memory leak)
Java Database Connectivity - API for connecting and executing queries with databases.
- Load driver:
Class.forName("com.mysql.jdbc.Driver") - Create connection:
DriverManager.getConnection(url, user, password) - Create statement:
connection.createStatement() - Execute query:
statement.executeQuery(sql) - Process results:
while(resultSet.next()) - Close resources
| Statement | PreparedStatement |
|---|---|
| SQL compiled every time | Precompiled |
| Slower | Faster for repeated queries |
| Vulnerable to SQL injection | Prevents SQL injection |
| No parameters | Supports parameters |
// PreparedStatement
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM users WHERE id = ?");
ps.setInt(1, userId);- executeQuery(): For SELECT statements, returns ResultSet
- executeUpdate(): For INSERT/UPDATE/DELETE, returns int (affected rows)
Object that holds data retrieved from database after executing a query.
ResultSet rs = statement.executeQuery("SELECT * FROM users");
while (rs.next()) {
String name = rs.getString("name");
}Software components enabling Java applications to interact with databases. Four types:
- Type 1: JDBC-ODBC bridge
- Type 2: Native-API driver
- Type 3: Network Protocol driver
- Type 4: Thin driver (pure Java)
Reusing database connections instead of creating new ones, improving performance.
Group of SQL statements executed as a single unit. Either all succeed or all rollback.
conn.setAutoCommit(false);
try {
statement.executeUpdate("INSERT...");
statement.executeUpdate("UPDATE...");
conn.commit();
} catch (Exception e) {
conn.rollback();
}Executing multiple SQL statements as a batch for better performance.
statement.addBatch("INSERT INTO users VALUES (1, 'John')");
statement.addBatch("INSERT INTO users VALUES (2, 'Jane')");
int[] results = statement.executeBatch();Wrapper around ResultSet, adding JavaBean functionality. Can be disconnected from database.
// TYPE_FORWARD_ONLY (default)
Statement stmt = conn.createStatement();
// TYPE_SCROLL_INSENSITIVE (scrollable, not affected by DB changes)
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY
);
// TYPE_SCROLL_SENSITIVE (scrollable, affected by DB changes)
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE
);Used to execute stored procedures.
CallableStatement cs = conn.prepareCall("{call getEmployee(?)}");
cs.setInt(1, employeeId);
ResultSet rs = cs.executeQuery();
// With OUT parameter
CallableStatement cs = conn.prepareCall("{call getTotalSalary(?, ?)}");
cs.setInt(1, deptId);
cs.registerOutParameter(2, Types.DECIMAL);
cs.execute();
double total = cs.getDouble(2);- execute(): Any SQL, returns boolean (true if ResultSet)
- executeQuery(): SELECT, returns ResultSet
- executeUpdate(): INSERT/UPDATE/DELETE, returns int (affected rows)
Provides information about the database.
DatabaseMetaData metaData = conn.getMetaData();
String dbName = metaData.getDatabaseProductName();
String dbVersion = metaData.getDatabaseProductVersion();
ResultSet tables = metaData.getTables(null, null, "%", null);Provides information about ResultSet columns.
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
String columnName = rsmd.getColumnName(1);
String columnType = rsmd.getColumnTypeName(1);// TRANSACTION_NONE
conn.setTransactionIsolation(Connection.TRANSACTION_NONE);
// TRANSACTION_READ_UNCOMMITTED (dirty reads possible)
conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
// TRANSACTION_READ_COMMITTED (prevents dirty reads)
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
// TRANSACTION_REPEATABLE_READ (prevents dirty and non-repeatable reads)
conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
// TRANSACTION_SERIALIZABLE (strictest)
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);Point within transaction to rollback to.
conn.setAutoCommit(false);
Savepoint sp1 = conn.setSavepoint("SavePoint1");
try {
stmt.executeUpdate("INSERT...");
stmt.executeUpdate("UPDATE...");
conn.commit();
} catch (Exception e) {
conn.rollback(sp1); // Rollback to savepoint
}Reuses database connections instead of creating new ones for each request.
Benefits:
- Improved performance
- Reduced overhead
- Better resource management
Popular libraries: HikariCP, Apache DBCP, C3P0
Factory for database connections, preferred over DriverManager.
DataSource ds = // Get from JNDI or connection pool
Connection conn = ds.getConnection();Reusable solution to commonly occurring problems in software design.
Ensures a class has only one instance and provides global access point.
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}Creates objects without specifying exact class, using a factory method.
interface Shape {
void draw();
}
class ShapeFactory {
public Shape getShape(String type) {
if (type.equals("CIRCLE")) return new Circle();
if (type.equals("SQUARE")) return new Square();
return null;
}
}Constructs complex objects step by step.
public class User {
private String name;
private int age;
private User(Builder builder) {
this.name = builder.name;
this.age = builder.age;
}
static class Builder {
private String name;
private int age;
Builder setName(String name) {
this.name = name;
return this;
}
Builder setAge(int age) {
this.age = age;
return this;
}
User build() {
return new User(this);
}
}
}One-to-many dependency where observers are notified of state changes.
interface Observer {
void update(String message);
}
class Subject {
private List<Observer> observers = new ArrayList<>();
void attach(Observer o) { observers.add(o); }
void notifyObservers(String msg) {
observers.forEach(o -> o.update(msg));
}
}Defines family of algorithms, encapsulates each one, makes them interchangeable.
interface PaymentStrategy {
void pay(int amount);
}
class CreditCard implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " using credit card");
}
}Design pattern where dependencies are provided to objects rather than created by them.
class Service {
private Repository repository;
// Constructor injection
public Service(Repository repository) {
this.repository = repository;
}
}Converts interface of a class into another interface clients expect.
interface MediaPlayer {
void play(String audioType, String fileName);
}
class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedPlayer;
public void play(String audioType, String fileName) {
advancedPlayer.playVlc(fileName);
}
}Adds new functionality to objects dynamically without altering structure.
interface Coffee {
double cost();
}
class SimpleCoffee implements Coffee {
public double cost() { return 5; }
}
class MilkDecorator implements Coffee {
private Coffee coffee;
public MilkDecorator(Coffee coffee) {
this.coffee = coffee;
}
public double cost() {
return coffee.cost() + 2;
}
}- Factory: Creates instances of one product family
- Abstract Factory: Creates instances of multiple related product families
Creates new objects by cloning existing ones.
class Sheep implements Cloneable {
private String name;
public Sheep clone() {
try {
return (Sheep) super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
Sheep original = new Sheep("Dolly");
Sheep clone = original.clone();Defines skeleton of algorithm, letting subclasses override specific steps.
abstract class DataProcessor {
public final void process() {
readData();
processData();
writeData();
}
abstract void readData();
abstract void processData();
void writeData() {
System.out.println("Writing data");
}
}Encapsulates request as an object.
interface Command {
void execute();
}
class LightOnCommand implements Command {
private Light light;
public void execute() {
light.turnOn();
}
}
class RemoteControl {
private Command command;
public void pressButton() {
command.execute();
}
}Passes request along chain of handlers until one handles it.
abstract class Handler {
protected Handler next;
public void setNext(Handler handler) {
this.next = handler;
}
public abstract void handleRequest(Request request);
}
class ConcreteHandler extends Handler {
public void handleRequest(Request request) {
if (canHandle(request)) {
// Handle
} else if (next != null) {
next.handleRequest(request);
}
}
}Provides placeholder for another object to control access.
interface Image {
void display();
}
class RealImage implements Image {
public void display() {
System.out.println("Displaying image");
}
}
class ProxyImage implements Image {
private RealImage realImage;
public void display() {
if (realImage == null) {
realImage = new RealImage(); // Lazy loading
}
realImage.display();
}
}Provides simplified interface to complex subsystem.
class ComputerFacade {
private CPU cpu;
private Memory memory;
private HardDrive hd;
public void start() {
cpu.freeze();
memory.load();
cpu.execute();
}
}Allows object to change behavior when internal state changes.
interface State {
void handle();
}
class Context {
private State state;
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle();
}
}Defines object that encapsulates how set of objects interact.
class ChatMediator {
private List<User> users = new ArrayList<>();
public void sendMessage(String msg, User user) {
for (User u : users) {
if (u != user) {
u.receive(msg);
}
}
}
}Provides way to access elements sequentially without exposing structure.
interface Iterator<T> {
boolean hasNext();
T next();
}
class BookCollection implements Iterable<Book> {
private List<Book> books;
public Iterator<Book> iterator() {
return books.iterator();
}
}Separates application into Model (data), View (UI), Controller (logic).
// Model
class User {
private String name;
}
// View
class UserView {
public void printUser(String name) {
System.out.println("Name: " + name);
}
}
// Controller
class UserController {
private User model;
private UserView view;
public void updateView() {
view.printUser(model.getName());
}
}Ability to inspect and manipulate classes, methods, fields at runtime.
Class<?> clazz = Class.forName("com.example.MyClass");
Method method = clazz.getMethod("myMethod");
method.invoke(object);Metadata providing information about program but not part of program itself.
@Override
@Deprecated
@SuppressWarnings("unchecked")Converting object state into byte stream for storage or transmission.
class Person implements Serializable {
private String name;
}
// Serialize
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("file"));
out.writeObject(person);
// Deserialize
ObjectInputStream in = new ObjectInputStream(new FileInputStream("file"));
Person p = (Person) in.readObject();Prevents field serialization during object serialization.
class User implements Serializable {
private String username;
private transient String password; // Not serialized
}Creating exact copy of an object.
class Person implements Cloneable {
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}- Shallow copy: Copies object references, not objects themselves
- Deep copy: Copies objects recursively, creating independent copies
| Comparable | Comparator |
|---|---|
| java.lang package | java.util package |
| compareTo() method | compare() method |
| Natural ordering | Custom ordering |
| Modify original class | Separate class |
// Comparable
class Person implements Comparable<Person> {
public int compareTo(Person other) {
return this.age - other.age;
}
}
// Comparator
Comparator<Person> nameComparator = (p1, p2) ->
p1.name.compareTo(p2.name);- ClassNotFoundException: Checked exception, class not found at runtime (reflection, Class.forName)
- NoClassDefFoundError: Error, class was present at compile time but not at runtime
Indicates method is implemented in platform-dependent code (C/C++).
public native void performOperation();Provide type safety by allowing you to parameterize types.
// Without generics
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0); // Casting needed
// With generics
List<String> list = new ArrayList<>();
list.add("Hello");
String s = list.get(0); // No castingRestricts types that can be used as type arguments.
// Upper bound
class Box<T extends Number> {
private T value;
}
Box<Integer> intBox = new Box<>(); // OK
// Box<String> strBox = new Box<>(); // Error
// Multiple bounds
class Box<T extends Number & Comparable<T>> { }
// Lower bound (wildcards only)
public void addNumbers(List<? super Integer> list) {
list.add(5);
}Generics are removed at runtime, replaced with Object or bound type.
List<String> strings = new ArrayList<>();
List<Integer> ints = new ArrayList<>();
// At runtime, both are just ListUnbounded: <?>
public void printList(List<?> list) { }Upper bounded: <? extends T>
public void processList(List<? extends Number> list) { }Lower bounded: <? super T>
public void addToList(List<? super Integer> list) { }- Class<?>: Unknown type
- Class: Specific type parameter
public <T> T create(Class<T> clazz) throws Exception {
return clazz.newInstance();
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
int timeout() default 0;
String description() default "";
}
// Usage
@Test(timeout = 1000, description = "Test login")
public void testLogin() { }Non-blocking I/O for improved performance in file and network operations.
// Reading file with NIO
Path path = Paths.get("file.txt");
byte[] bytes = Files.readAllBytes(path);
// Channel and Buffer
FileChannel channel = FileChannel.open(path);
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);- File: Legacy class (java.io)
- Path: Modern interface (java.nio), more functionality
File file = new File("path/to/file");
Path path = Paths.get("path/to/file");Loads classes into JVM at runtime.
Types:
- Bootstrap: Loads core Java classes
- Extension: Loads extension classes
- System/Application: Loads application classes
ClassLoader classLoader = MyClass.class.getClassLoader();
Class<?> clazz = classLoader.loadClass("com.example.MyClass");// Class.forName() - loads and initializes class
Class<?> clazz1 = Class.forName("com.mysql.jdbc.Driver");
// ClassLoader.loadClass() - loads but doesn't initialize
Class<?> clazz2 = ClassLoader.getSystemClassLoader()
.loadClass("com.mysql.jdbc.Driver");Object can be garbage collected even if weakly referenced.
WeakReference<MyClass> weakRef = new WeakReference<>(new MyClass());
MyClass obj = weakRef.get(); // May return null if collectedWeakHashMap allows keys to be garbage collected when no strong references exist.
WeakHashMap<Key, Value> map = new WeakHashMap<>();
map.put(new Key(), value);
// If key has no other references, entry can be removedVersion number for serializable classes to ensure compatibility.
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
}Interface extending Serializable with custom serialization logic.
class Person implements Externalizable {
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
}
public void readExternal(ObjectInput in) throws IOException {
name = (String) in.readObject();
}
}Thread-safe lazy initialization pattern.
class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}Special class type that represents group of constants.
enum Day {
MONDAY, TUESDAY, WEDNESDAY
}
// Enum with constructor
enum Planet {
EARTH(5.976e24, 6.37814e6),
MARS(6.421e23, 3.3972e6);
private final double mass;
private final double radius;
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
}Import static members to use without class name.
import static java.lang.Math.*;
double result = sqrt(4); // No Math. prefix neededDebug statement to test assumptions.
int age = getAge();
assert age >= 0 : "Age cannot be negative";
// Enable assertions with -ea flag
java -ea MyProgram- sleep(): Pauses thread for specified time
- yield(): Hints scheduler to give chance to other threads
Thread.sleep(1000); // Sleep 1 second
Thread.yield(); // Give up current time sliceBackground thread that doesn't prevent JVM from exiting.
Thread t = new Thread(() -> {
while (true) {
// Background task
}
});
t.setDaemon(true);
t.start();Introduced in Java 9 for better encapsulation and dependencies.
// module-info.java
module com.example.myapp {
requires java.sql;
exports com.example.api;
}This comprehensive guide covers 240+ Java interview questions across various categories. Understanding these concepts will help you prepare for Java technical interviews at any level from junior to senior positions.
Key Takeaways:
- Focus on understanding concepts, not just memorizing answers
- Practice implementing these patterns and techniques
- Build projects to apply knowledge in real scenarios
- Stay updated with latest Java features and best practices
- Review concurrency and collections thoroughly as they're commonly tested
- Understand JVM internals for senior-level positions
Next Steps:
- Practice coding problems on platforms like LeetCode, HackerRank
- Build real-world projects using these concepts
- Contribute to open-source Java projects
- Read Java documentation and official tutorials
- Stay current with Java release notes and new features
Good luck with your interview preparation!
Last updated: February 13, 2026