Intermediate Interview Questions

Why is String immutable in Java?

  • String pool: literals are shared, so one reference must not be able to change another's text.
  • Security: file paths, URLs, DB credentials and class names cannot be altered after checks.
  • Thread safety: immutable objects can be shared freely.
  • Hash caching: the hash code is computed once, which makes String great as a HashMap key.

String vs StringBuilder vs StringBuffer?

StringStringBuilderStringBuffer
Mutablenoyesyes
Thread-safeyes (immutable)noyes (synchronized)
Speed for many changesslow (new object each time)fastestslower than StringBuilder

Tip: Concatenating in a loop with + creates many temporary objects; use StringBuilder.

Checked vs unchecked exceptions?

CheckedUnchecked
ExtendsException (not RuntimeException)RuntimeException (or Error)
Checked atcompile time: must catch or declare throwsnot enforced by compiler
ExamplesIOException, SQLExceptionNullPointerException, ArithmeticException, IllegalArgumentException

Error (e.g. OutOfMemoryError, StackOverflowError) signals serious JVM problems that applications should not normally catch.

final vs finally vs finalize?

  • final: keyword for constants, non-overridable methods and non-extendable classes.
  • finally: block after try/catch that always runs (cleanup), except when the JVM exits (e.g. System.exit).
  • finalize(): old Object method called by GC before collection; deprecated since Java 9, use try-with-resources or Cleaner.

Does finally run if the try block returns?

Yes. finally runs before the method actually returns. If finally itself returns, it overrides the earlier return (a bad practice).

Example

The return value is computed first, then finally runs.

public class Main {
    static int test() {
        int x = 10;
        try {
            return x;
        } finally {
            x = 20;
            System.out.println("finally runs, x = " + x);
        }
    }

    public static void main(String[] args) {
        System.out.println("returned " + test());
    }
}

Output

finally runs, x = 20
returned 10

What is try-with-resources?

Introduced in Java 7, it automatically closes any resource that implements AutoCloseable at the end of the block, even if an exception is thrown. Resources close in reverse order of declaration. Exceptions thrown while closing are attached as suppressed exceptions.

try (Connection con = dataSource.getConnection();
     PreparedStatement ps = con.prepareStatement("SELECT * FROM users WHERE id = ?")) {
    ps.setLong(1, id);
    ...
} // ps.close() then con.close() are called automatically

How do you create a custom exception?

Example

Extend RuntimeException for unchecked or Exception for checked.

public class Main {
    static void withdraw(double balance, double amount) {
        if (amount > balance) {
            throw new InsufficientBalanceException("Need " + amount + " but have " + balance);
        }
        System.out.println("Withdrawn " + amount);
    }

    public static void main(String[] args) {
        try {
            withdraw(1000, 500);
            withdraw(1000, 5000);
        } catch (InsufficientBalanceException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

class InsufficientBalanceException extends RuntimeException {
    InsufficientBalanceException(String message) { super(message); }
}

Output

Withdrawn 500.0
Error: Need 5000.0 but have 1000.0

What are generics and what is type erasure?

Generics give compile-time type safety (List<String> rejects an Integer) and remove casts. Java implements them with type erasure: type parameters are removed after compilation (List<String> becomes List with casts inserted). That is why you cannot do new T(), T.class, or instanceof List<String>.

What do ? extends T and ? super T mean (PECS)?

Producer Extends, Consumer Super. List<? extends Number> can be read as Number but you cannot add to it (it produces values). List<? super Integer> accepts Integer additions but reads only as Object (it consumes values). Example: Collections.copy(List<? super T> dest, List<? extends T> src).

What are the main features of Java 8?

  • Lambda expressions and functional interfaces (Predicate, Function, Consumer, Supplier).
  • Stream API for declarative processing of collections.
  • Default and static methods in interfaces.
  • Optional to represent a possibly-missing value.
  • Method references (String::length).
  • New Date/Time API (java.time), CompletableFuture.

What is a functional interface?

An interface with exactly one abstract method (it may have default/static methods). It can be implemented by a lambda or method reference. @FunctionalInterface makes the compiler enforce the rule. Examples: Runnable, Comparator, Callable, Function<T,R>.

map() vs flatMap() in streams?

map transforms each element into exactly one element. flatMap transforms each element into a stream and flattens all those streams into one.

Example

Flattening a list of lists.

import java.util.*;
import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        List<List<String>> orders = List.of(
            List.of("phone", "cover"),
            List.of("laptop"),
            List.of("mouse", "keyboard"));

        System.out.println(orders.stream().map(List::size).toList());
        System.out.println(orders.stream().flatMap(List::stream).toList());
    }
}

Output

[2, 1, 2]
[phone, cover, laptop, mouse, keyboard]

What is Optional and how should you use it?

Optional<T> is a container that may or may not hold a value, used mainly as a return type to avoid returning null. Use map, orElse, orElseThrow, ifPresent instead of get(). Do not use it for fields or method parameters.

String city = userRepo.findById(id)          // Optional<User>
        .map(User::getAddress)
        .map(Address::getCity)
        .orElse("Unknown");