All Java Interview Questions
What is the difference between map() and flatMap() in Java streams?
map is one to one. flatMap is one to many, and it flattens the result.
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> sentences = List.of("java is fun", "streams are great");
List<String[]> mapped = sentences.stream()
.map(s -> s.split(" "))
.toList();
System.out.println(mapped.size() + " arrays"); // a list of arrays
List<String> words = sentences.stream()
.flatMap(s -> Arrays.stream(s.split(" ")))
.toList();
System.out.println(words); // one flat list
}
}
2 arrays
[java, is, fun, streams, are, great]
See Java Streams.
What is a functional interface in Java?
A functional interface has one abstract method (it can have default and static methods too). The annotation @FunctionalInterface asks the compiler to check this rule.
import java.util.function.Function;
import java.util.function.Predicate;
@FunctionalInterface
interface Validator {
boolean validate(String text);
}
public class Main {
public static void main(String[] args) {
Validator notEmpty = t -> !t.isBlank();
Predicate<Integer> positive = n -> n > 0;
Function<String, Integer> length = String::length;
System.out.println(notEmpty.validate("hi") + " " + notEmpty.validate(" "));
System.out.println(positive.test(-5));
System.out.println(length.apply("functional"));
}
}
true false
false
10
What are the ways to create a thread in Java?
import java.util.concurrent.*;
public class Main {
static class MyThread extends Thread {
public void run() { System.out.println("1. extends Thread"); }
}
public static void main(String[] args) throws Exception {
MyThread t1 = new MyThread();
t1.start();
t1.join();
Thread t2 = new Thread(() -> System.out.println("2. Runnable lambda"));
t2.start();
t2.join();
try (ExecutorService pool = Executors.newFixedThreadPool(2)) {
Future<String> f = pool.submit(() -> "3. Callable returns a value");
System.out.println(f.get());
}
Thread t4 = Thread.ofVirtual().start(() -> System.out.println("4. virtual thread"));
t4.join();
}
}
1. extends Thread
2. Runnable lambda
3. Callable returns a value
4. virtual thread
| Way | Returns a value? | Note |
|---|---|---|
| Extend Thread | No | Uses your only parent class |
| Runnable | No | The usual simple way |
| Callable + ExecutorService | Yes (Future) | Best for real programs |
| Virtual thread | Same as above | Light, for many waiting tasks (Java 21+) |
See Java Threads.
What is the difference between synchronized and volatile in Java?
| Point | synchronized | volatile |
|---|---|---|
| Applies to | Methods and blocks | Variables |
| Mutual exclusion | Yes (one thread at a time) | No |
| Visibility of changes | Yes | Yes |
Atomic count++ | Yes, inside a synchronized block | No |
| Cost | Higher (locking) | Low |
Use volatile for a simple flag which one thread writes and others read. Use synchronized, a Lock or AtomicInteger when several steps must be done together.
public class Main {
static volatile boolean running = true;
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> {
long loops = 0;
while (running) {
loops++;
}
System.out.println("Worker stopped");
});
worker.start();
Thread.sleep(200);
running = false; // the worker sees this change because of volatile
worker.join();
}
}
Worker stopped
What is a deadlock in Java and how to avoid it?
Thread A locks lock1 and waits for lock2. Thread B locks lock2 and waits for lock1. Both wait for ever.
public class Main {
static final Object lock1 = new Object();
static final Object lock2 = new Object();
public static void main(String[] args) throws InterruptedException {
Thread a = new Thread(() -> {
synchronized (lock1) {
pause();
synchronized (lock2) { System.out.println("A done"); }
}
});
Thread b = new Thread(() -> {
synchronized (lock2) {
pause();
synchronized (lock1) { System.out.println("B done"); }
}
});
a.setDaemon(true);
b.setDaemon(true);
a.start();
b.start();
a.join(1500);
b.join(1500);
System.out.println("A alive: " + a.isAlive() + ", B alive: " + b.isAlive());
}
static void pause() {
try { Thread.sleep(300); } catch (InterruptedException e) { }
}
}
A alive: true, B alive: true
Both threads are still alive after waiting, so they are in a deadlock. How to avoid it:
- Always take the locks in the same order in all threads.
- Use
tryLock(timeout)ofReentrantLockand give up after some time. - Keep the locked code small and do not call unknown code inside it.
- Prefer high level tools (
ExecutorService, concurrent collections).
How to create a thread safe singleton in Java?
A singleton allows only one object of a class. The two simple and safe ways are:
public class Main {
// 1. Holder idiom: lazy and thread safe, because class loading is thread safe
static class Config {
private Config() { System.out.println("Config created"); }
private static class Holder {
static final Config INSTANCE = new Config();
}
static Config getInstance() { return Holder.INSTANCE; }
}
// 2. Enum singleton: also safe against reflection and serialization
enum Registry {
INSTANCE;
int counter;
}
public static void main(String[] args) {
System.out.println("Start");
Config a = Config.getInstance();
Config b = Config.getInstance();
System.out.println(a == b);
Registry.INSTANCE.counter++;
System.out.println(Registry.INSTANCE.counter);
}
}
Start
Config created
true
1
The object is created when it is used the first time, and only once. Other common ways are double checked locking with a volatile field, but the two above are simpler.
What is new in Java 25?
Java 25 (September 2025) is an LTS release, so it gets updates for many years. Some of the final features:
- Compact source files and instance main methods (JEP 512): small programs without the class and
public static, plusIO.println. - Module import declarations (JEP 511):
import module java.base;imports all the public packages of a module. - Flexible constructor bodies (JEP 513): statements before
super(...), for checks. - Scoped values (JEP 506): a safer way to share data between threads than thread locals.
- Compact object headers (JEP 519) and other performance work.
We can test the first three on a real Java 25:
import module java.base;
void main() {
List<String> names = new ArrayList<>(List.of("Riya", "Aman")); // List and ArrayList without a normal import
IO.println(names);
IO.println(new Child(-5).value());
}
class Parent {
final int value;
Parent(int value) { this.value = value; }
int value() { return value; }
}
class Child extends Parent {
Child(int raw) {
int fixed = Math.max(raw, 0); // a statement before super(...), allowed in Java 25
super(fixed);
}
}
[Riya, Aman]
0
Java 27 is newer, but it is not an LTS. See the chapter Java Introduction for the versions.
Which Java version should I learn? What are the LTS versions?
Java has a new version every 6 months (in March and September). Every 2 years, one of them is an LTS (long term support) release, which gets updates for many years.
| LTS version | Released |
|---|---|
| Java 8 | March 2014 |
| Java 11 | September 2018 |
| Java 17 | September 2021 |
| Java 21 | September 2023 |
| Java 25 | September 2025 |
Learn the newest LTS (Java 25), because almost everything of Java 8, 11, 17 and 21 works in it, and you also learn the modern features. In a job you may meet Java 8, 11 or 17 code, so the older features are in this tutorial too.
$ java -version 2>&1 | head -1
openjdk version "25.0.5" 2026-10-20 LTS
Java vs Python: which language should you learn first?
Both are among the most popular languages. In the TIOBE index of November 2026 Python is first (20.9%) and Java is third (8.9%), and in the PYPL index of Google tutorial searches the two are on the first and the second place.
| Point | Python | Java |
|---|---|---|
| Start | Very easy, short syntax | More code to write, stricter rules |
| Typing | Dynamic (types checked when running) | Static (types checked by the compiler) |
| Speed | Slower for heavy work | Faster (JIT compiler) |
| Strong in | Data, AI, scripts, automation | Big back ends, Android, banking, large teams |
| Run | Interpreter | Compile to bytecode, run on the JVM |
If you want to start fast, begin with Python. If you want to learn how programs are built with types and classes, or you plan an enterprise or Android career, Java is a great choice. After one, the other becomes easy.
What is the difference between throw and throws in Java?
| Point | throw | throws |
|---|---|---|
| Kind | Statement inside a method | Keyword in the method declaration |
| Use | Create and send an exception object | Warn that the method can throw exceptions |
| Followed by | One exception object | One or many exception types |
import java.io.IOException;
public class Main {
static void check(int age) throws IOException { // throws: declaration
if (age < 0) {
throw new IOException("Age can not be negative"); // throw: action
}
System.out.println("Age ok");
}
public static void main(String[] args) {
try {
check(10);
check(-1);
} catch (IOException e) {
System.out.println("Caught: " + e.getMessage());
}
}
}
Age ok
Caught: Age can not be negative
See Java Exceptions.
What are annotations in Java?
An annotation adds information (metadata) to classes, methods and fields. It does not change the code by itself. The compiler or a framework reads it. Well known ones: @Override, @Deprecated, @FunctionalInterface, @SuppressWarnings. Frameworks like Spring use many.
You can make your own, and read it with reflection:
import java.lang.annotation.*;
import java.lang.reflect.Method;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Run {
String value() default "no name";
}
public class Main {
@Run("first")
public void alpha() { System.out.println("alpha called"); }
public void beta() { }
@Run
public void gamma() { System.out.println("gamma called"); }
public static void main(String[] args) throws Exception {
Main obj = new Main();
for (String name : new String[]{"alpha", "beta", "gamma"}) {
Method m = Main.class.getMethod(name);
Run run = m.getAnnotation(Run.class);
if (run != null) {
System.out.println("Running " + run.value());
m.invoke(obj);
} else {
System.out.println(name + " has no @Run");
}
}
}
}
Running first
alpha called
beta has no @Run
Running no name
gamma called
What are the best practices for exception handling in Java?
- Catch specific exceptions, not just
ExceptionorThrowable. - Never swallow an exception with an empty
catch. At least log it. - Use try with resources to close files, sockets and connections.
- Keep the cause when you wrap an exception:
throw new MyException("message", e). - Add useful details to the message: which value, which file.
- Do not use exceptions for normal flow, like ending a loop. They are slow and unclear.
- Throw early, catch late: check arguments at the start, and handle the error where you can do something about it.
- Use unchecked exceptions for programming errors, and checked ones only when the caller can recover.
public class Main {
static class ConfigException extends RuntimeException {
ConfigException(String message, Throwable cause) { super(message, cause); }
}
static int readPort(String text) {
try {
return Integer.parseInt(text);
} catch (NumberFormatException e) {
throw new ConfigException("Invalid port value '" + text + "'", e); // keeps the cause
}
}
public static void main(String[] args) {
try {
readPort("80x");
} catch (ConfigException e) {
System.out.println(e.getMessage());
System.out.println("Cause: " + e.getCause());
}
}
}
Invalid port value '80x'
Cause: java.lang.NumberFormatException: For input string: "80x"
See Java Exceptions.
What is reflection in Java?
Reflection (the package java.lang.reflect) lets code look at classes, methods and fields at run time, and call them, even if the names were not known when the code was written.
import java.lang.reflect.Method;
import java.util.Arrays;
public class Main {
public static class Greeter {
public String hello(String name) { return "Hello, " + name; }
public int twice(int n) { return n * 2; }
}
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("Main$Greeter");
System.out.println(c.getSimpleName());
Object obj = c.getDeclaredConstructor().newInstance();
Method hello = c.getMethod("hello", String.class);
System.out.println(hello.invoke(obj, "Riya"));
String[] names = Arrays.stream(c.getDeclaredMethods()).map(Method::getName).sorted().toArray(String[]::new);
System.out.println(Arrays.toString(names));
}
}
Greeter
Hello, Riya
[hello, twice]
- It is powerful but slower, and it breaks the safety checks of the compiler. Use it for frameworks and tools, not for normal code.
- Modern Java also limits reflection on the internals of the JDK (modules).
- « Previous
- 1
- 2
- 3