Menu
CoddyTech

Java Interview Questions and Answers

Java questions grouped by topic and level, from core Java to collections, concurrency and Java 8 streams. Runnable examples were run on Java 24, and coding questions link to problems on Coddy's judge.

89 questions19 output quizzesRunnable code checked on Java 24By Kevin Spektor, Co-founder & CTO

Java interview questions for freshers

Campus placement basics: the JDK and JVM, data types, operators and their output puzzles.

What is the difference between JDK, JRE and JVM?

Fresherjvm

The JVM runs bytecode, the JRE is the JVM plus the standard library, and the JDK is the JRE plus tools such as javac and jar. Since Java 11 Oracle ships no separate JRE: you install a JDK, or build a trimmed runtime with jlink.

Why is the main method public static void main(String[] args)?

Fresherbasics

It is the exact signature the JVM calls: public so it is reachable from outside, static because no object exists yet, void because exit codes go through System.exit, and String[] args for the command line arguments.

Overloads are allowed, but the JVM never calls them. Instance main methods (void main()) were a preview in Java 21 to 24 and became final in Java 25 with JEP 512.

What are the primitive data types in Java?

Fresherdata types

Eight: byte (8 bits), short (16), int (32), long (64), float (32), double (64), char (16, one UTF-16 unit) and boolean. Everything else, including String and arrays, is a reference type.

Java
public class Main {
    public static void main(String[] args) {
        System.out.println("int max:  " + Integer.MAX_VALUE);
        System.out.println("long max: " + Long.MAX_VALUE);
        System.out.println("char 'A' as int: " + (int) 'A');
        System.out.println("byte range: " + Byte.MIN_VALUE + " to " + Byte.MAX_VALUE);
    }
}

The sizes are fixed by the language spec, unlike in C. See the Java data types guide.

What does this print: Integer.MAX_VALUE incremented by one?

Fresherdata types
Java
public class Main {
    public static void main(String[] args) {
        int x = Integer.MAX_VALUE;
        x++;
        System.out.println(x);
    }
}

Predict the output

It prints -2147483648. int arithmetic is 32-bit two's complement, so MAX_VALUE + 1 silently wraps to Integer.MIN_VALUE.

Use Math.addExact to throw ArithmeticException on overflow, or switch to long or BigInteger.

What does this print: / and % on ints and on a double?

Fresheroperators
Java
public class Main {
    public static void main(String[] args) {
        System.out.println(7 / 2 + " " + 7 % 2 + " " + 7 / 2.0);
    }
}

Predict the output

It prints 3 1 3.5. 7 / 2 is int division and truncates toward zero, 7 % 2 is the remainder, and 7 / 2.0 widens to double. For an average of ints, write (double) sum / count.

What does this print: + mixing numbers and a string?

Fresherstrings
Java
public class Main {
    public static void main(String[] args) {
        System.out.println(1 + 2 + "3" + 4 + 5);
    }
}

Predict the output

It prints 3345. + runs left to right: 1 + 2 is addition, 3 + "3" is concatenation, and every + after a string concatenates. Write "sum: " + (4 + 5) to add first.

What does this print: a colon-style switch with no break?

Freshercontrol flow
Java
public class Main {
    public static void main(String[] args) {
        int x = 2;
        switch (x) {
            case 1: System.out.print("one ");
            case 2: System.out.print("two ");
            case 3: System.out.print("three ");
            default: System.out.print("other");
        }
        System.out.println();
    }
}

Predict the output

It prints two three other. Colon-style cases fall through: after a match, execution runs into every following case until a break. The arrow form from Java 14 (case 2 -> ...) never falls through.

What is type casting in Java? What is widening and narrowing?

Fresherdata types

Casting converts a value to another type. Widening (int to long or double) is automatic and safe; narrowing (double to int) needs an explicit cast and can lose data.

Java
public class Main {
    public static void main(String[] args) {
        int i = 100;
        long l = i;            // widening, automatic
        double d = 3.99;
        int truncated = (int) d;   // narrowing drops the fraction
        byte b = (byte) 200;       // keeps the low 8 bits
        System.out.println(l + " " + truncated + " " + b);
    }
}

It prints 100 3 -56: the cast truncates 3.99 instead of rounding, and (byte) 200 keeps only the low 8 bits.

What are wrapper classes and autoboxing in Java?

Fresherdata types

Wrapper classes (Integer, Double, Character and the rest) let primitives be used as objects, for example in collections. Autoboxing is the compiler converting int to Integer with Integer.valueOf; unboxing is the reverse.

Two traps: unboxing a null throws NullPointerException, and == on two Integers compares references.

What is the difference between final, finally and finalize in Java?

Fresherkeywords

They are unrelated. final blocks reassigning a variable, overriding a method or extending a class. finally runs after try/catch whether or not an exception was thrown. finalize() was a garbage collector hook, deprecated in Java 9 and for removal in Java 18; use try-with-resources or Cleaner.

What does the static keyword mean in Java?

Fresherkeywords

A static member belongs to the class, so all objects share one copy.

Java
class Counter {
    static int created = 0;   // shared by all objects
    int id;                   // one per object

    Counter() {
        created++;
        id = created;
    }
}

public class Main {
    public static void main(String[] args) {
        Counter a = new Counter();
        Counter b = new Counter();
        System.out.println(a.id + " " + b.id + " " + Counter.created);
    }
}

It prints 1 2 2. Static methods cannot use this and are hidden, not overridden. More in static members.

What is a constructor in Java? Can a constructor be private?

Fresheroop

A constructor initializes a new object: it has the class's name and no return type, and the compiler adds a no-argument one only if you write none.

Yes, it can be private, which blocks new from other classes: that is how singletons, utility classes like Math and factories like List.of work. Until Java 25, when JEP 513 relaxed the rule, this(...) or super(...) had to be the first statement.

Core Java interview questions

Strings, equality, wrappers, initialization order and argument passing, where small samples hide many mistakes.

What is the difference between == and equals() in Java?

Fresherstrings

== compares references for objects (values for primitives); equals() compares content, as the class defines it.

Java
public class Main {
    public static void main(String[] args) {
        String a = new String("java");
        String b = new String("java");
        System.out.println(a == b);       // two different objects
        System.out.println(a.equals(b));  // same characters
    }
}

It prints false then true. Compare strings with equals(), and override hashCode() whenever you override equals().

What does this print: a literal, a constant concatenation and new String compared with ==?

Experiencedstrings
Java
public class Main {
    public static void main(String[] args) {
        String a = "java";
        String b = "ja" + "va";
        String c = new String("java");
        System.out.println((a == b) + " " + (a == c) + " " + a.equals(c));
    }
}

Predict the output

It prints true false true. "ja" + "va" is a compile-time constant, folded into the same pooled literal as a. new String always makes a new object, so a == c is false, while equals compares characters.

With a variable (s + "va") the concatenation runs at runtime and == is false; c.intern() returns the pooled instance.

Why is String immutable in Java?

Fresherstrings

A String never changes; methods like toUpperCase() return a new one. Immutability makes the string pool safe to share, keeps a checked file path or class name from changing, lets threads share strings without locks, and lets String cache its hash code.

Build strings in loops with StringBuilder. More in the Java strings guide.

What is the difference between String, StringBuilder and StringBuffer?

Fresherstrings

String is immutable; StringBuilder and StringBuffer are mutable. StringBuffer synchronizes every method and is legacy, so use StringBuilder.

Java
public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= 5; i++) {
            sb.append(i).append(',');
        }
        sb.setLength(sb.length() - 1);   // drop the last comma
        System.out.println(sb.reverse());
    }
}

It prints 5,4,3,2,1, and reverse() is also the shortest way to reverse a string.

What does this print: == on boxed Integer values 127 and 128?

Experienceddata types
Java
public class Main {
    public static void main(String[] args) {
        Integer a = 127, b = 127;
        Integer c = 128, d = 128;
        System.out.println((a == b) + " " + (c == d));
    }
}

Predict the output

It prints true false. Autoboxing calls Integer.valueOf(), which always caches -128 to 127 (see the Integer.valueOf docs), so the two 127s are one object while each 128 is, by default, a new one, and == compares references.

Compare wrappers with equals(). The bug passes every test that uses small IDs.

Is Java pass by value or pass by reference?

Experiencedmethods

Always by value. For objects the value is a copy of the reference, so a method can change the object but not which object the caller's variable points to.

Java
import java.util.ArrayList;
import java.util.List;

public class Main {
    static void modify(List<String> list) {
        list.add("added");          // changes the shared object
        list = new ArrayList<>();   // only changes the local copy
        list.add("lost");
    }

    public static void main(String[] args) {
        List<String> items = new ArrayList<>();
        modify(items);
        System.out.println(items);
    }
}

It prints [added], and it is why a swap(a, b) method cannot work in Java.

What is serialization in Java? What does the transient keyword do?

Experiencedio

Serialization turns an object of a Serializable class into bytes and back; a transient field is skipped and comes back with its default value.

Java
import java.io.*;

class User implements Serializable {
    private static final long serialVersionUID = 1L;
    String name;
    transient String password;   // never written to the stream
    User(String name, String password) { this.name = name; this.password = password; }
}

public class Main {
    public static void main(String[] args) throws Exception {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        try (ObjectOutputStream out = new ObjectOutputStream(bytes)) {
            out.writeObject(new User("asha", "secret"));
        }
        try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
            User u = (User) in.readObject();
            System.out.println(u.name + " " + u.password);
        }
    }
}

It prints asha null. Declare serialVersionUID yourself, or a changed class makes old data fail with InvalidClassException.

What does this print: 0.1 + 0.2 as doubles?

Fresherdata types
Java
public class Main {
    public static void main(String[] args) {
        System.out.println(0.1 + 0.2);
    }
}

Predict the output

It prints 0.30000000000000004. 0.1 and 0.2 have no exact binary form, so their double sum is slightly off; Python and JavaScript print the same.

Compare doubles with a tolerance, and use BigDecimal built from strings for money.

What does this print: a static block, an instance block and a constructor over two objects?

Experiencedoop
Java
class A {
    static { System.out.print("S "); }
    { System.out.print("I "); }
    A() { System.out.print("C "); }
}

public class Main {
    public static void main(String[] args) {
        new A();
        new A();
        System.out.println();
    }
}

Predict the output

It prints S I C I C. The static block runs once, when the class is first initialized; the instance block runs on every new, before the constructor body.

With a parent class: both static blocks once, parent first, then per object the parent's initializers and constructor before the child's.

What is the contract between equals() and hashCode()?

Experiencedcollections

Equal objects must have equal hash codes; unequal ones may collide. HashMap picks the bucket by hash before calling equals(), so overriding only equals() breaks lookups:

Java
import java.util.HashSet;
import java.util.Set;

class Point {
    final int x, y;
    Point(int x, int y) { this.x = x; this.y = y; }

    @Override
    public boolean equals(Object o) {
        return o instanceof Point p && p.x == x && p.y == y;
    }
    // hashCode() not overridden: equal points land in different buckets
}

public class Main {
    public static void main(String[] args) {
        Set<Point> set = new HashSet<>();
        set.add(new Point(1, 2));
        System.out.println(set.contains(new Point(1, 2)));
    }
}

It prints false. Add a hashCode() returning Objects.hash(x, y), or use a record, which generates both.

OOPs in Java interview questions

Inheritance, polymorphism, abstraction and encapsulation, plus the field and static method traps.

What are the four pillars of OOP in Java?

Fresheroop

Encapsulation (private fields behind methods), inheritance (extends to reuse a class), polymorphism (Animal a = new Dog(); a.sound() runs Dog's method) and abstraction (interfaces and abstract classes hide how things work).

Back each with one example from your own code.

What is the difference between method overloading and overriding?

Fresherpolymorphism

Overloading is one name with different parameter lists, chosen at compile time. Overriding is a subclass replacing an inherited method with the same signature, chosen at runtime.

Java
class Shape {
    double area() { return 0; }
}

class Circle extends Shape {
    double r;
    Circle(double r) { this.r = r; }
    @Override
    double area() { return Math.PI * r * r; }   // overriding
}

public class Main {
    static String describe(int n) { return "int " + n; }       // overloading
    static String describe(String s) { return "String " + s; }

    public static void main(String[] args) {
        Shape s = new Circle(1);
        System.out.printf("%.2f%n", s.area());
        System.out.println(describe(5) + ", " + describe("five"));
    }
}

It prints 3.14 and int 5, String five. Changing only the return type is not overloading and does not compile. See method overloading.

What does this print: creating a subclass when both constructors print?

Fresherinheritance
Java
class Parent {
    Parent() { System.out.print("Parent "); }
}

class Child extends Parent {
    Child() { System.out.print("Child"); }
}

public class Main {
    public static void main(String[] args) {
        new Child();
        System.out.println();
    }
}

Predict the output

It prints Parent Child. A constructor first calls a superclass constructor; without an explicit super(...), the compiler inserts super().

If Parent had only a constructor with parameters, Child would need super(args) to compile.

What does this print: a field and a method redeclared in a subclass?

Experiencedpolymorphism
Java
class Animal {
    String name = "animal";
    String sound() { return "..."; }
}

class Dog extends Animal {
    String name = "dog";
    @Override
    String sound() { return "woof"; }
}

public class Main {
    public static void main(String[] args) {
        Animal a = new Dog();
        System.out.println(a.name + " " + a.sound());
    }
}

Predict the output

It prints animal woof. Methods dispatch on the object's runtime class (Dog), but fields resolve at compile time from the reference type (Animal), so the subclass field only hides the parent's. Keep fields private.

What does this print: a static method called through a parent-typed reference?

Experiencedpolymorphism
Java
class P {
    static String who() { return "P"; }
}

class C extends P {
    static String who() { return "C"; }
}

public class Main {
    public static void main(String[] args) {
        P p = new C();
        System.out.println(p.who());
    }
}

Predict the output

It prints P. Static methods are hidden, not overridden: the call binds at compile time to the declared type, so this is P.who(). Call static methods through the class name.

What is the difference between an abstract class and an interface in Java?

Experiencedabstraction

Use an interface for a capability unrelated classes share, and an abstract class to share state and code among related ones.

An abstract class can have instance fields and constructors, and a class extends only one. An interface holds only constants, but a class implements many, and since Java 8 interfaces can carry default and static methods. See abstract classes.

Why does Java not support multiple inheritance of classes? How do default methods handle the diamond problem?

Seniorinheritance

To avoid the diamond problem: if two parent classes had the same method, the child's version would be ambiguous. Default methods can still clash between interfaces, so Java forces an override, which can pick one with Interface.super.method():

Java
interface Walker {
    default String move() { return "walk"; }
}

interface Swimmer {
    default String move() { return "swim"; }
}

class Duck implements Walker, Swimmer {
    @Override
    public String move() {             // required, or it does not compile
        return Walker.super.move() + " and " + Swimmer.super.move();
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println(new Duck().move());
    }
}

It prints walk and swim. A method from a class always beats an interface default.

What are the access modifiers in Java?

Fresheroop

From most to least open: public (everywhere), protected (package and subclasses), default with no keyword (package only) and private (the class only).

A top-level class can only be public or package-private. More in access modifiers.

What is composition and why is it often preferred over inheritance?

Seniordesign

Composition means a class holds another object and delegates to it ("has-a": a Car has an Engine) instead of extending it ("is-a").

Prefer it because inheritance ties the child to the parent's implementation and exposes every inherited public method, as with Stack extends Vector in the JDK; a composed field can also be swapped at runtime. Keep inheritance for true subtypes.

How do you create an immutable class in Java?

Senioroop

Make the class final and its fields private final, add no setters, and copy mutable inputs and outputs.

Java
import java.util.ArrayList;
import java.util.List;

final class Team {
    private final String name;
    private final List<String> members;

    Team(String name, List<String> members) {
        this.name = name;
        this.members = List.copyOf(members);   // defensive, unmodifiable copy
    }

    List<String> members() { return members; }
}

public class Main {
    public static void main(String[] args) {
        List<String> input = new ArrayList<>(List.of("Asha", "Ben"));
        Team t = new Team("core", input);
        input.add("Eve");                     // does not affect the team
        System.out.println(t.members());
    }
}

It prints [Asha, Ben]; the defensive copy is what most candidates forget. A record (Java 16) covers the rest, but copy its mutable components in a compact constructor.

Java collections interview questions

How HashMap, ArrayList and the other collections work, which to pick, and their iteration bugs.

Explain the Java Collections Framework hierarchy.

Freshercollections

Collection branches into List (ordered, duplicates allowed: ArrayList), Set (no duplicates: HashSet, TreeSet) and Queue/Deque (ArrayDeque, PriorityQueue). Map (HashMap, TreeMap) stores key-value pairs and does not extend Collection.

The legacy Vector, Stack and Hashtable are replaced by ArrayList, ArrayDeque and HashMap.

What is the difference between an array and an ArrayList in Java?

Freshercollections

An array has a fixed length and can hold primitives; an ArrayList grows but holds only objects, so int values are boxed.

Java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        int[] arr = {3, 1, 2};
        List<Integer> list = new ArrayList<>(List.of(3, 1, 2));
        list.add(4);            // an array cannot grow
        Arrays.sort(arr);
        list.sort(null);
        System.out.println(Arrays.toString(arr) + " length " + arr.length);
        System.out.println(list + " size " + list.size());
    }
}

It prints [1, 2, 3] length 3 and [1, 2, 3, 4] size 4. In OpenJDK a full ArrayList copies itself into an array about 1.5 times bigger; the spec only promises that appending is O(1) amortized. See ArrayList.

What is the difference between ArrayList and LinkedList?

Freshercollections

ArrayList is a resizable array with O(1) get(i); LinkedList is a doubly linked list with O(n) get(i) and two pointers per node. Use ArrayList by default.

Inserting in the middle is O(n) for both, because the linked list must first walk to the position, and arrays are far more cache friendly. For queues and stacks use ArrayDeque.

What does this print: remove(1) on a List<Integer>?

Experiencedcollections
Java
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
        list.remove(1);
        System.out.println(list);
    }
}

Predict the output

It prints [1, 3]. List<Integer> has remove(int index) and remove(Object o), and the literal 1 is an int, so the call removes index 1, the value 2.

To remove the value 1, write list.remove(Integer.valueOf(1)).

How does HashMap work internally in Java?

Experiencedcollectionshashmap

A HashMap is an array of buckets. put spreads hashCode() (h ^ (h >>> 16)), picks bucket hash & (capacity - 1) and chains colliding entries; lookups walk the chain with equals().

The table (16 buckets by default) doubles when it passes 75% full. Since Java 8 a chain longer than 8 becomes a red-black tree once the table has 64 buckets (a smaller table resizes instead). One null key is allowed, in bucket 0. See the hash map visualization.

What is the difference between HashMap, Hashtable and ConcurrentHashMap?

Seniorcollectionsconcurrency

HashMap is not thread safe and allows one null key. Hashtable locks the whole table on every method and is legacy. ConcurrentHashMap reads without locks and locks single bins on writes; it allows no nulls, and its iterators never throw ConcurrentModificationException.

Use its atomic merge or compute: a get followed by a put is still a race.

How does HashSet work internally?

Experiencedcollections

A HashSet is a HashMap whose keys are the elements and whose values are one shared dummy object; add returns false when the key already exists.

So it has O(1) average add and contains, no order, and needs consistent equals() and hashCode(). LinkedHashSet keeps insertion order, TreeSet sorted order.

What does this print: equal points as a class and as a record in a HashSet?

Experiencedcollections
Java
import java.util.HashSet;
import java.util.Set;

class PointClass {
    int x, y;
    PointClass(int x, int y) { this.x = x; this.y = y; }
}

record PointRecord(int x, int y) {}

public class Main {
    public static void main(String[] args) {
        Set<PointClass> a = new HashSet<>();
        a.add(new PointClass(1, 2));
        a.add(new PointClass(1, 2));

        Set<PointRecord> b = new HashSet<>();
        b.add(new PointRecord(1, 2));
        b.add(new PointRecord(1, 2));

        System.out.println(a.size() + " " + b.size());
    }
}

Predict the output

It prints 2 1. PointClass keeps Object's identity-based equals() and hashCode(), so both objects stay in the set. A record generates both from its components, so the second add is a duplicate.

What is the difference between HashMap, LinkedHashMap and TreeMap?

Experiencedcollectionshashmap

Iteration order: HashMap guarantees none, LinkedHashMap keeps insertion order, and TreeMap keeps keys sorted.

Java
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;

public class Main {
    public static void main(String[] args) {
        String[] keys = {"banana", "apple", "cherry"};
        Map<String, Integer> hash = new HashMap<>();
        Map<String, Integer> linked = new LinkedHashMap<>();
        Map<String, Integer> tree = new TreeMap<>();
        for (String k : keys) {
            hash.put(k, k.length());
            linked.put(k, k.length());
            tree.put(k, k.length());
        }
        System.out.println("linked: " + linked.keySet());
        System.out.println("tree:   " + tree.keySet());
        System.out.println("hash has " + hash.size() + " keys, order not guaranteed");
    }
}

linked prints [banana, apple, cherry] and tree prints [apple, banana, cherry]. TreeMap costs O(log n) instead of O(1), but adds floorKey() and range views.

What is a fail-fast iterator? How do you remove elements while iterating?

Seniorcollections

A fail-fast iterator throws ConcurrentModificationException when the collection changes structurally other than through the iterator; it checks a modCount counter on each next(). It detects bugs and gives no thread safety. Remove with removeIf or Iterator.remove():

Java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> a = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
        a.removeIf(n -> n % 2 == 0);
        System.out.println(a);

        List<Integer> b = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
        Iterator<Integer> it = b.iterator();
        while (it.hasNext()) {
            if (it.next() > 3) it.remove();
        }
        System.out.println(b);
    }
}

It prints [1, 3, 5] and [1, 2, 3]. Concurrent collections have weakly consistent iterators that never throw.

What does this print: removing the middle element inside a for-each loop?

Seniorcollections
Java
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
        for (Integer x : list) {
            if (x == 2) list.remove(x);
        }
        System.out.println(list);
    }
}

Predict the output

It prints [1, 3] with no exception. After removing 2, the size and the iterator's cursor are both 2, so hasNext() is false and the modCount check in next() never runs.

Removing 1 or 3 throws ConcurrentModificationException, so a passing test proves nothing here; use removeIf.

What is the difference between Comparable and Comparator?

Experiencedcollections

Comparable is a class's own natural order (compareTo); a Comparator is an external order, so one class can have many.

Java
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

record Student(String name, int marks) implements Comparable<Student> {
    @Override
    public int compareTo(Student other) {
        return name.compareTo(other.name);   // natural order: by name
    }
}

public class Main {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>(List.of(
            new Student("Ravi", 82), new Student("Anu", 91), new Student("Kiran", 82)));

        list.sort(null);   // natural order
        System.out.println(list.stream().map(Student::name).toList());

        list.sort(Comparator.comparingInt(Student::marks).reversed()
                            .thenComparing(Student::name));
        System.out.println(list.stream().map(Student::name).toList());
    }
}

It prints [Anu, Kiran, Ravi] twice: Anu has the top mark and the two 82s tie-break by name. Avoid a - b comparators, which can overflow; use Integer.compare.

Java exception handling interview questions

Checked versus unchecked exceptions, finally, try-with-resources and custom exceptions.

What is the difference between checked and unchecked exceptions?

Fresherexceptions

Checked exceptions (Exception subclasses outside RuntimeException, like IOException) must be caught or declared with throws. Unchecked ones (RuntimeException subclasses like NullPointerException, plus Error) need neither.

Checked usually means a condition the caller can recover from, unchecked a bug. An Error such as OutOfMemoryError should normally not be caught. More in the exceptions guide.

What is the difference between throw and throws?

Fresherexceptions

throw throws one exception object; throws in a signature declares what a method may pass up, and is required only for checked exceptions.

Java
public class Main {
    static int parseAge(String s) throws NumberFormatException {   // declares
        int age = Integer.parseInt(s);
        if (age < 0) {
            throw new IllegalArgumentException("age < 0: " + age);  // throws
        }
        return age;
    }

    public static void main(String[] args) {
        for (String input : new String[] {"30", "-4", "abc"}) {
            try {
                System.out.println("ok " + parseAge(input));
            } catch (IllegalArgumentException e) {
                System.out.println(e.getClass().getSimpleName() + ": " + e.getMessage());
            }
        }
    }
}

It prints ok 30, IllegalArgumentException: age < 0: -4 and NumberFormatException: For input string: "abc". One catch handles both because NumberFormatException extends IllegalArgumentException.

What does this print: return inside try with a finally that prints?

Experiencedexceptions
Java
public class Main {
    static int f() {
        try {
            return 1;
        } finally {
            System.out.print("finally ");
        }
    }

    public static void main(String[] args) {
        System.out.println(f());
    }
}

Predict the output

It prints finally 1. return 1 computes its value, finally runs, and then the method returns.

Follow-up: does finally always run? Not if the JVM stops inside the try, as with System.exit(), a crash, or a daemon thread at shutdown.

What does this print: a return in both try and finally?

Experiencedexceptions
Java
public class Main {
    static int f() {
        try {
            return 1;
        } finally {
            return 2;
        }
    }

    public static void main(String[] args) {
        System.out.println(f());
    }
}

Predict the output

It prints 2. A return in finally replaces the try's return value and would also swallow an exception from the try, so linters flag it. Use finally only for cleanup.

What is try-with-resources and in what order are resources closed?

Experiencedexceptions

Resources declared in try (...) are closed automatically when the block ends, in reverse order and before any catch runs; anything AutoCloseable works.

Java
class Res implements AutoCloseable {
    private final String name;
    Res(String name) { this.name = name; System.out.println("open " + name); }
    @Override
    public void close() { System.out.println("close " + name); }
}

public class Main {
    public static void main(String[] args) {
        try (Res a = new Res("A"); Res b = new Res("B")) {
            System.out.println("body");
            throw new IllegalStateException("boom");
        } catch (IllegalStateException e) {
            System.out.println("caught " + e.getMessage());
        }
    }
}

It prints open A, open B, body, close B, close A, caught boom. An exception thrown by close() is attached to the main one as suppressed (e.getSuppressed()) instead of replacing it.

How do you create a custom exception in Java?

Experiencedexceptions

Extend Exception (checked) or RuntimeException (unchecked) and pass the message to super.

Java
class InsufficientFundsException extends RuntimeException {
    InsufficientFundsException(int balance, int amount) {
        super("balance " + balance + ", tried to withdraw " + amount);
    }
}

public class Main {
    static int balance = 500;

    static void withdraw(int amount) {
        if (amount > balance) throw new InsufficientFundsException(balance, amount);
        balance -= amount;
    }

    public static void main(String[] args) {
        try {
            withdraw(200);
            withdraw(400);
        } catch (InsufficientFundsException e) {
            System.out.println("Failed: " + e.getMessage());
        }
    }
}

It prints Failed: balance 300, tried to withdraw 400. When wrapping another exception, pass it as the cause (super(message, cause)) to keep its stack trace. See try-catch.

What causes a NullPointerException and how do you avoid it?

Fresherexceptions

A NullPointerException is thrown when a null reference is used as an object: a method call, a field read, an array index or unboxing.

Prevent it with Objects.requireNonNull on inputs, empty collections or Optional instead of null returns, "yes".equals(input), and map.getOrDefault. Since Java 15 the message names the null expression by default (local variable names only when compiled with -g; see JEP 358). More in NullPointerException.

Multithreading in Java interview questions

Threads, synchronization, volatile, executors, CompletableFuture and virtual threads.

What are the ways to create a thread in Java?

Fresherconcurrency

Extend Thread, pass a Runnable to a Thread, or submit a Runnable or Callable to an ExecutorService. Prefer the executor: it reuses threads, and a Callable can return a value. ExecutorService is AutoCloseable since Java 19.

Java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Main {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(() -> System.out.println("runnable in a thread"));
        t.start();
        t.join();   // wait for it to finish

        try (ExecutorService pool = Executors.newFixedThreadPool(2)) {
            Future<Integer> f = pool.submit(() -> 6 * 7);   // a Callable
            System.out.println("callable returned " + f.get());
        }
    }
}

Follow-up: what does calling run() instead of start() do? It runs the code on the current thread.

What are the states of a thread in Java (the thread lifecycle)?

Experiencedconcurrency

Six Thread.State values: NEW, RUNNABLE (running or ready), BLOCKED (waiting for a monitor), WAITING (wait(), join() or park() with no timeout), TIMED_WAITING (with a timeout, or sleep) and TERMINATED.

Java
import java.util.concurrent.CountDownLatch;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);
        Thread t = new Thread(() -> {
            try { latch.await(); } catch (InterruptedException e) { }
        });
        System.out.println(t.getState());
        t.start();
        while (t.getState() != Thread.State.WAITING) Thread.onSpinWait();
        System.out.println(t.getState());
        latch.countDown();
        t.join();
        System.out.println(t.getState());
    }
}

It prints NEW, WAITING and TERMINATED. A thread waiting on a ReentrantLock is WAITING, because BLOCKED is only for monitors.

What is a race condition and how does synchronized or AtomicInteger fix it?

Experiencedconcurrency

A race condition is a result that depends on thread timing: count++ is read, add, write, and two threads can interleave the steps and lose updates. synchronized admits one thread at a time and makes its writes visible to the next lock holder; AtomicInteger does it for one counter with lock-free CAS.

Java
import java.util.concurrent.atomic.AtomicInteger;

public class Main {
    private static int syncCount = 0;
    private static final AtomicInteger atomicCount = new AtomicInteger();

    private static synchronized void increment() { syncCount++; }

    public static void main(String[] args) throws InterruptedException {
        Runnable work = () -> {
            for (int i = 0; i < 10_000; i++) {
                increment();
                atomicCount.incrementAndGet();
            }
        };
        Thread t1 = new Thread(work), t2 = new Thread(work);
        t1.start(); t2.start();
        t1.join(); t2.join();
        System.out.println(syncCount + " " + atomicCount.get());
    }
}

It always prints 20000 20000; with a plain unsynchronized int it usually prints less.

What does volatile do in Java? Does it make count++ thread safe?

Seniorconcurrency

volatile guarantees visibility and ordering: every read sees the latest write, and accesses are not reordered across it. It does not make count++ atomic.

Use it for a stop flag one thread sets and another polls (without it the JIT may hoist the read and loop forever), and on the instance field in double-checked locking. Counters need AtomicInteger.

What is the difference between wait() and sleep()?

Experiencedconcurrency

sleep() pauses the thread and keeps its locks. wait() must be called while holding the object's monitor, releases it, and resumes on notify(), a timeout or an interrupt.

Call wait() in a while loop that rechecks the condition, because spurious wakeups happen. BlockingQueue or CountDownLatch are easier in new code.

What is a deadlock and how do you prevent it?

Seniorconcurrency

A deadlock is threads each holding a lock another needs, so all wait forever: thread 1 holds A and wants B while thread 2 holds B and wants A.

Prevent it by taking locks in one global order (by account id in a transfer), or with tryLock(timeout) and back-off. jstack <pid> reports "Found one Java-level deadlock".

What is CompletableFuture and how is it different from Future?

Seniorconcurrency

Future only has a blocking get(). CompletableFuture (Java 8) chains async steps without blocking: thenApply, thenCompose, thenCombine, exceptionally, handle.

Java
import java.util.concurrent.CompletableFuture;

public class Main {
    public static void main(String[] args) {
        CompletableFuture<Integer> price = CompletableFuture.supplyAsync(() -> 120);
        CompletableFuture<Integer> tax = CompletableFuture.supplyAsync(() -> 18);

        int total = price.thenCombine(tax, Integer::sum)   // combine two
                         .thenApply(t -> t * 2)            // transform
                         .exceptionally(e -> -1)           // fallback on error
                         .join();
        System.out.println("total " + total);

        String failed = CompletableFuture.supplyAsync(() -> {
                    if (true) throw new IllegalStateException("down");
                    return "ok";
                })
                .handle((v, e) -> e == null ? v : "recovered: " + e.getCause().getMessage())
                .join();
        System.out.println(failed);
    }
}

It prints total 276 and recovered: down; handle receives a CompletionException, hence getCause(). Async steps run on the common ForkJoinPool (a new thread per task if its parallelism is below two) unless you pass an executor, which you should for blocking I/O.

What are virtual threads in Java 21?

Seniorconcurrency

Virtual threads (final in Java 21) are JVM-managed threads that unmount from their carrier platform thread while blocked on I/O, so millions can run plain thread-per-request code.

Java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) throws Exception {
        try (ExecutorService ex = Executors.newVirtualThreadPerTaskExecutor()) {
            List<Future<Integer>> results = new ArrayList<>();
            for (int i = 1; i <= 10_000; i++) {
                int n = i;
                results.add(ex.submit(() -> {
                    Thread.sleep(10);     // blocking is cheap here
                    return n;
                }));
            }
            long sum = 0;
            for (Future<Integer> f : results) sum += f.get();
            System.out.println("sum " + sum);
        }
    }
}

It prints sum 50005000, and 10,000 sleeping tasks finish quickly. They help I/O-bound work, not CPU-bound work, and should not be pooled. In Java 21 blocking inside synchronized pins the carrier; JDK 24 removed most of that pinning with JEP 491.

Java 8 interview questions: streams and lambdas

Lambdas, functional interfaces, the Stream API and Optional, including how streams evaluate.

What are the main features introduced in Java 8?

Fresherjava 8

Lambdas, functional interfaces (Function, Predicate, Supplier, Consumer), the Stream API, method references, default and static interface methods, Optional, and java.time (LocalDate, Instant) replacing Date and Calendar. Metaspace also replaced PermGen.

What is a functional interface?

Experiencedjava 8lambdas

An interface with exactly one abstract method, so a lambda or method reference can implement it; default and static methods do not count. @FunctionalInterface makes the compiler enforce that.

Java
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

@FunctionalInterface
interface Discount {
    double apply(double price);
}

public class Main {
    public static void main(String[] args) {
        Discount tenOff = p -> p * 0.9;
        Predicate<String> isEmpty = String::isEmpty;
        Function<String, Integer> len = String::length;
        Supplier<String> hello = () -> "hello";

        System.out.println(tenOff.apply(200));
        System.out.println(isEmpty.test("") + " " + len.apply("java") + " " + hello.get());
    }
}

It prints 180.0 and true 4 hello. See lambda expressions.

How do Java streams work? Show filter, map and reduce.

Experiencedstreams

A stream is a source, lazy intermediate operations (filter, map, sorted) and one terminal operation (collect, reduce, count) that runs the pipeline.

Java
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Integer> nums = List.of(5, 3, 8, 1, 9, 2);

        List<Integer> evensSquared = nums.stream()
                .filter(n -> n % 2 == 0)
                .map(n -> n * n)
                .toList();
        int sum = nums.stream().reduce(0, Integer::sum);
        String joined = nums.stream().sorted().map(String::valueOf)
                .collect(Collectors.joining("-"));

        System.out.println(evensSquared + " " + sum + " " + joined);
    }
}

It prints [64, 4] 28 1-2-3-5-8-9. A stream is single use: a second terminal operation throws IllegalStateException. More in the streams guide.

What does this print: a printing filter with no terminal operation?

Experiencedstreams
Java
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        Stream<Integer> s = Stream.of(1, 2, 3).filter(x -> {
            System.out.print("f" + x + " ");
            return x > 1;
        });
        System.out.println("done");
    }
}

Predict the output

It prints only done. Intermediate operations are lazy: with no terminal operation no element flows, so the filter lambda never runs. The same laziness lets findFirst() stop at the first match.

What does this print: the call order of map and forEach over two elements?

Seniorstreams
Java
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        List<String> log = new ArrayList<>();
        Stream.of("a", "b")
              .map(s -> { log.add("map " + s); return s; })
              .forEach(s -> log.add("each " + s));
        System.out.println(String.join(", ", log));
    }
}

Predict the output

It prints map a, each a, map b, each b. Each element goes through the whole pipeline before the next one enters.

A stateful step changes that: with sorted() before forEach, every element is mapped before any reaches forEach.

What is the difference between map and flatMap in streams?

Experiencedstreams

map gives one output per element; flatMap maps each element to a stream and flattens the results into one stream.

Java
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> lines = List.of("to be", "or not");

        List<Integer> lengths = lines.stream().map(String::length).toList();
        List<String> words = lines.stream()
                .flatMap(line -> Arrays.stream(line.split(" ")))
                .toList();

        System.out.println(lengths);
        System.out.println(words);
    }
}

It prints [5, 6] and [to, be, or, not].

How do you group elements with streams? Explain Collectors.groupingBy.

Experiencedstreams

groupingBy(classifier) collects into a Map from each key to the list of elements with that key; a downstream collector like counting() changes the values.

Java
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> words = List.of("java", "spring", "jvm", "stream", "lambda", "jdk");

        Map<Integer, List<String>> byLength = words.stream()
                .collect(Collectors.groupingBy(String::length, TreeMap::new, Collectors.toList()));
        Map<Character, Long> countByFirst = words.stream()
                .collect(Collectors.groupingBy(w -> w.charAt(0), TreeMap::new, Collectors.counting()));

        System.out.println(byLength);
        System.out.println(countByFirst);
    }
}

It prints {3=[jvm, jdk], 4=[java], 6=[spring, stream, lambda]} and {j=3, l=1, s=2}. The one-argument form promises no map type or order, hence TreeMap::new.

What is Optional? What is the difference between orElse and orElseGet?

Experiencedjava 8

Optional<T> is a return type for a value that may be absent. orElse(x) always evaluates x; orElseGet(supplier) runs the supplier only when the Optional is empty.

Java
import java.util.Optional;

public class Main {
    static String loadDefault() {
        System.out.println("  loadDefault() called");
        return "guest";
    }

    public static void main(String[] args) {
        Optional<String> user = Optional.of("asha");

        System.out.println("orElse:");
        String a = user.orElse(loadDefault());
        System.out.println("orElseGet:");
        String b = user.orElseGet(Main::loadDefault);

        System.out.println(a + " " + b);
        System.out.println(Optional.<String>empty().map(String::toUpperCase).orElse("none"));
    }
}

loadDefault() called appears only after orElse:, and the last two lines are asha asha and none. Do not use Optional for fields or parameters. See Optional.

Java interview questions for 5 years experience

JVM memory, garbage collection, leaks, generics, class loading, locking and design questions.

Explain the JVM memory structure: heap, stack and metaspace.

Seniorjvm

The heap, shared by all threads, holds objects and arrays and is garbage collected. Each thread's stack holds one frame per call with locals and references; recursion that goes too deep gives StackOverflowError. Metaspace (Java 8+, replacing PermGen) holds class metadata in native memory.

In Person p = new Person(), p is on the stack and the object on the heap. Flags: -Xmx, -Xss, -XX:MaxMetaspaceSize.

How does garbage collection work in Java? Which collectors do you know?

Seniorjvm

The GC frees objects no longer reachable from roots such as thread stacks and static fields, so cycles are collected too. Most collectors are generational: most objects die young, so the young generation is collected often and survivors move to the old one.

G1 is the default since Java 9 and aims at a pause-time goal; through JDK 26 the JVM picks Serial instead on one CPU or under 1792 MB of memory, a rule JEP 523 drops in JDK 27. Parallel favors throughput. ZGC and Shenandoah (left out of Oracle's builds) keep pauses very low on large heaps; ZGC gained a generational mode in Java 21, the only mode since Java 24. System.gc() is only a hint.

Can Java have memory leaks? Give examples.

Seniorjvm

Yes. The GC frees only unreachable objects, so a leak is an object you no longer need that is still referenced.

Typical causes are static caches without eviction, listeners never removed, ThreadLocal values in pooled threads never removed, and keys whose hashCode() changes. Find it with a heap dump (jcmd <pid> GC.heap_dump) and its dominator tree in a tool like Eclipse MAT.

What does this print: a HashMap key list changed after put?

Seniorcollectionshashmap
Java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        List<Integer> key = new ArrayList<>(List.of(1));
        Map<List<Integer>, String> map = new HashMap<>();
        map.put(key, "v");
        key.add(2);
        System.out.println(map.get(key) + " " + map.containsKey(List.of(1)));
    }
}

Predict the output

It prints null false. The entry sits where its original hash put it. After key.add(2) the hash changes, so get(key) looks elsewhere; containsKey(List.of(1)) finds the entry, but equals compares [1] with [1, 2].

The entry is lost but still takes memory, so map keys must not change after insertion.

How do you write a thread-safe singleton in Java?

Seniordesign

Use an enum or the holder idiom; both rely on the JVM initializing a class once, thread safely.

Java
enum Config {
    INSTANCE;
    private final String env = "prod";
    String env() { return env; }
}

class Registry {
    private Registry() { System.out.println("Registry created"); }

    private static class Holder {          // initialized on first getInstance()
        static final Registry INSTANCE = new Registry();
    }

    static Registry getInstance() { return Holder.INSTANCE; }
}

public class Main {
    public static void main(String[] args) {
        System.out.println(Config.INSTANCE.env());
        System.out.println(Registry.getInstance() == Registry.getInstance());
    }
}

It prints prod, Registry created once, and true. With double-checked locking the field must be volatile, or another thread can see a half-built object.

Which features from Java 11 to 21 do you use? Show records, sealed classes and pattern matching.

Seniormodern java

var (10), switch expressions (14), text blocks (15), records and instanceof patterns (16), sealed classes (17), and pattern matching for switch with record patterns (21). LTS releases: 8, 11, 17, 21 and 25.

Java
sealed interface Shape permits Circle, Rect {}
record Circle(double r) implements Shape {}
record Rect(double w, double h) implements Shape {}

public class Main {
    static double area(Shape s) {
        return switch (s) {                      // exhaustive: no default needed
            case Circle c -> Math.PI * c.r() * c.r();
            case Rect(double w, double h) -> w * h;   // record pattern
        };
    }

    public static void main(String[] args) {
        var shapes = java.util.List.of(new Circle(1), new Rect(2, 3));
        for (Shape s : shapes) {
            System.out.printf("%s -> %.2f%n", s, area(s));
        }
    }
}

It prints Circle[r=1.0] -> 3.14 and Rect[w=2.0, h=3.0] -> 6.00. Because Shape is sealed, the switch needs no default, and adding a subtype makes every non-exhaustive switch a compile error.

What is type erasure in Java generics?

Seniorgenerics

Generic type arguments exist only at compile time: the compiler checks them, inserts casts and erases them, so List<String> and List<Integer> share one runtime class.

Java
import java.util.ArrayList;
import java.util.List;

public class Main {
    static double sum(List<? extends Number> nums) {   // producer: extends
        double total = 0;
        for (Number n : nums) total += n.doubleValue();
        return total;
    }

    public static void main(String[] args) {
        List<String> a = new ArrayList<>();
        List<Integer> b = new ArrayList<>();
        System.out.println(a.getClass() == b.getClass());
        System.out.println(sum(List.of(1, 2.5, 3L)));
    }
}

It prints true and 6.5. Hence no new T(), no instanceof List<String> and no generic arrays. Wildcards follow PECS: producer extends, consumer super. More in generics.

How does class loading work in Java?

Seniorjvm

Classes load lazily through a chain of loaders using parent delegation, each asking its parent first: bootstrap (core modules such as java.base), platform (other modules such as java.sql) and application (your classpath). That is why you cannot replace java.lang.String.

A class is a separate type per loader, so the same class loaded by two loaders gives ClassCastException: X cannot be cast to X in app servers.

What is the difference between synchronized and ReentrantLock?

Seniorconcurrency

Both give mutual exclusion, visibility and reentrancy. synchronized releases the lock automatically; ReentrantLock needs unlock() in a finally block but adds tryLock with a timeout, interruptible waits, fairness and several Conditions.

Use synchronized by default, and ReadWriteLock or StampedLock for read-heavy data.

How would you design a simple LRU cache in Java?

Seniordesignhashmap

Extend LinkedHashMap in access order and override removeEldestEntry; get and put stay O(1).

Java
import java.util.LinkedHashMap;
import java.util.Map;

class LruCache<K, V> extends LinkedHashMap<K, V> {
    private final int capacity;

    LruCache(int capacity) {
        super(16, 0.75f, true);   // true = access order
        this.capacity = capacity;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > capacity;
    }
}

public class Main {
    public static void main(String[] args) {
        LruCache<String, Integer> cache = new LruCache<>(2);
        cache.put("a", 1);
        cache.put("b", 2);
        cache.get("a");          // a is now most recently used
        cache.put("c", 3);       // evicts b
        System.out.println(cache.keySet());
    }
}

It prints [a, c]. Without LinkedHashMap, use a HashMap of keys to nodes plus a doubly linked list: move a node to the head on access and drop the tail on overflow.

Java coding interview questions

Short coding-round programs, each with a runnable solution and a matching judge problem.

How do you reverse a string in Java without using StringBuilder.reverse()?

Freshercodingstrings

Swap characters of a char[] from both ends toward the middle: O(n) time, and O(n) space for the copy.

Java
public class Main {
    static String reverse(String s) {
        char[] c = s.toCharArray();
        for (int i = 0, j = c.length - 1; i < j; i++, j--) {
            char tmp = c[i];
            c[i] = c[j];
            c[j] = tmp;
        }
        return new String(c);
    }

    public static void main(String[] args) {
        System.out.println(reverse("interview"));
        System.out.println(reverse("a"));
        System.out.println("[" + reverse("") + "]");
    }
}

It prints weivretni, a and []. new StringBuilder(s).reverse() is shorter and also keeps emoji (surrogate pairs) intact.

Write a Java program to check whether a string is a palindrome, ignoring case and non-letters.

Freshercodingstrings

Use two pointers: skip characters that are not letters or digits, compare the rest case-insensitively, and stop when the pointers meet. O(n) time, O(1) space.

Java
public class Main {
    static boolean isPalindrome(String s) {
        int i = 0, j = s.length() - 1;
        while (i < j) {
            if (!Character.isLetterOrDigit(s.charAt(i))) { i++; continue; }
            if (!Character.isLetterOrDigit(s.charAt(j))) { j--; continue; }
            if (Character.toLowerCase(s.charAt(i)) != Character.toLowerCase(s.charAt(j))) {
                return false;
            }
            i++;
            j--;
        }
        return true;
    }

    public static void main(String[] args) {
        System.out.println(isPalindrome("A man, a plan, a canal: Panama"));
        System.out.println(isPalindrome("race a car"));
    }
}

It prints true then false.

How do you count the occurrences of each character in a string in Java?

Freshercodinghashmap

Count with merge into a LinkedHashMap<Character, Integer>, which keeps first-seen order.

Java
import java.util.LinkedHashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        String s = "programming";
        Map<Character, Integer> counts = new LinkedHashMap<>();
        for (char c : s.toCharArray()) {
            counts.merge(c, 1, Integer::sum);
        }
        System.out.println(counts);

        for (char c : s.toCharArray()) {
            if (counts.get(c) == 1) {
                System.out.println("first non-repeated: " + c);
                break;
            }
        }
    }
}

It prints {p=1, r=2, o=1, g=2, a=1, m=2, i=1, n=1} and first non-repeated: p. For lowercase letters only, an int[26] is faster.

Write a Java program to check if two strings are anagrams.

Freshercodingstrings

Anagrams have the same characters with the same counts. For lowercase letters, count up for one string and down for the other in an int[26], then check for zeros: O(n).

Java
public class Main {
    static boolean isAnagram(String a, String b) {
        if (a.length() != b.length()) return false;
        int[] count = new int[26];
        for (int i = 0; i < a.length(); i++) {
            count[a.charAt(i) - 'a']++;
            count[b.charAt(i) - 'a']--;
        }
        for (int c : count) {
            if (c != 0) return false;
        }
        return true;
    }

    public static void main(String[] args) {
        System.out.println(isAnagram("listen", "silent"));
        System.out.println(isAnagram("rat", "car"));
    }
}

It prints true then false. Sorting both is O(n log n); Unicode input needs a HashMap.

Solve Two Sum in Java: find two indices whose values add up to a target.

Experiencedcodinghashmap

One pass with a HashMap from value to index: if target - num was already seen, return both indices. O(n) time and space.

Java
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Main {
    static int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> seen = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            Integer j = seen.get(target - nums[i]);
            if (j != null) return new int[] {j, i};
            seen.put(nums[i], i);
        }
        return new int[0];
    }

    public static void main(String[] args) {
        System.out.println(Arrays.toString(twoSum(new int[] {2, 7, 11, 15}, 9)));
        System.out.println(Arrays.toString(twoSum(new int[] {3, 2, 4}, 6)));
    }
}

It prints [0, 1] and [1, 2]. Checking before inserting stops an element pairing with itself.

Find the second largest number in an array in Java.

Freshercodingarrays

One O(n) pass tracking the largest and second largest, ignoring repeats of the largest, so [5, 5, 3] gives 3.

Java
public class Main {
    static Integer secondLargest(int[] a) {
        Integer first = null, second = null;
        for (int x : a) {
            if (first == null || x > first) {
                second = first;
                first = x;
            } else if (x < first && (second == null || x > second)) {
                second = x;
            }
        }
        return second;   // null if there is no second distinct value
    }

    public static void main(String[] args) {
        System.out.println(secondLargest(new int[] {12, 35, 1, 10, 34, 1}));
        System.out.println(secondLargest(new int[] {5, 5, 3}));
        System.out.println(secondLargest(new int[] {7, 7}));
    }
}

It prints 34, 3 and null. Starting from Integer.MIN_VALUE instead of null fails when the array contains that value.

Reverse a singly linked list in Java.

Experiencedcodinglinked lists

Walk the list once and point each next back at the previous node, keeping prev, curr and the saved next. O(n) time, O(1) space.

Java
public class Main {
    static class Node {
        int val;
        Node next;
        Node(int val, Node next) { this.val = val; this.next = next; }
    }

    static Node reverse(Node head) {
        Node prev = null, curr = head;
        while (curr != null) {
            Node next = curr.next;   // save the rest
            curr.next = prev;        // flip the pointer
            prev = curr;
            curr = next;
        }
        return prev;
    }

    public static void main(String[] args) {
        Node head = new Node(1, new Node(2, new Node(3, new Node(4, null))));
        StringBuilder out = new StringBuilder();
        for (Node n = reverse(head); n != null; n = n.next) out.append(n.val).append(' ');
        System.out.println(out.toString().trim());
    }
}

It prints 4 3 2 1. See the linked list visualization.

Check whether a string of brackets is balanced in Java.

Experiencedcodingstacks

Push each opener's matching closer on an ArrayDeque; every closing bracket must equal the popped top, and the stack must end empty. O(n) time.

Java
import java.util.ArrayDeque;
import java.util.Deque;

public class Main {
    static boolean isValid(String s) {
        Deque<Character> stack = new ArrayDeque<>();
        for (char c : s.toCharArray()) {
            switch (c) {
                case '(' -> stack.push(')');
                case '[' -> stack.push(']');
                case '{' -> stack.push('}');
                default -> {
                    if (stack.isEmpty() || stack.pop() != c) return false;
                }
            }
        }
        return stack.isEmpty();
    }

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

It prints true false false.

Implement binary search in Java.

Freshercodingsearching

Compare the middle of the sorted range with the target and drop the half that cannot hold it: O(log n).

Java
public class Main {
    static int binarySearch(int[] a, int target) {
        int lo = 0, hi = a.length - 1;
        while (lo <= hi) {
            int mid = lo + (hi - lo) / 2;   // avoids int overflow of lo + hi
            if (a[mid] == target) return mid;
            if (a[mid] < target) lo = mid + 1;
            else hi = mid - 1;
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] a = {2, 5, 8, 12, 16, 23, 38};
        System.out.println(binarySearch(a, 23) + " " + binarySearch(a, 7));
    }
}

It prints 5 -1. Use lo + (hi - lo) / 2, because (lo + hi) / 2 can overflow, a bug the JDK's own Arrays.binarySearch had for years. See the binary search visualization.

Write a Java program to print the Fibonacci series. Why is the naive recursive version slow?

Freshercodingrecursion

Loop with two variables: O(n) time, O(1) space. Naive recursion recomputes the same values and takes exponential time.

Java
public class Main {
    static long fib(int n) {
        long a = 0, b = 1;
        for (int i = 0; i < n; i++) {
            long next = a + b;
            a = b;
            b = next;
        }
        return a;
    }

    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10; i++) sb.append(fib(i)).append(' ');
        System.out.println(sb.toString().trim());
        System.out.println("fib(90) = " + fib(90));
    }
}

It prints 0 1 1 2 3 5 8 13 21 34 and fib(90) = 2880067194370816120. Use long: int overflows after fib(46).

Write a Java program to check whether a number is prime.

Freshercodingmath

A number n > 1 is prime if nothing from 2 to √n divides it, because a larger factor pairs with a smaller one. O(√n).

Java
public class Main {
    static boolean isPrime(int n) {
        if (n < 2) return false;
        if (n % 2 == 0) return n == 2;
        for (int i = 3; (long) i * i <= n; i += 2) {
            if (n % i == 0) return false;
        }
        return true;
    }

    public static void main(String[] args) {
        StringBuilder primes = new StringBuilder();
        for (int i = 0; i <= 30; i++) if (isPrime(i)) primes.append(i).append(' ');
        System.out.println(primes.toString().trim());
        System.out.println(isPrime(2147483647));
    }
}

It prints 2 3 5 7 11 13 17 19 23 29 and true; (long) i * i avoids overflow. For all primes up to a limit, use the Sieve of Eratosthenes.

Preparing for the interview

How should I prepare for a Java interview?
Learn the language first: data types, strings, OOP, exceptions and collections, until you can explain HashMap and predict the output of small programs. Then add Java 8 streams, basic multithreading and 30 to 50 coding problems in Java. Practise each answer aloud in two or three sentences.
What Java topics are asked for freshers compared with experienced candidates?
Freshers get definitions and small programs: JDK vs JVM, OOP pillars, == vs equals, String immutability, ArrayList vs LinkedList, reversing a string. With two or more years of experience the focus moves to how things work: HashMap internals, concurrency, streams, JVM memory and GC, and design questions such as a thread-safe singleton or an LRU cache.
Do I need data structures and algorithms for a Java developer interview?
For most product companies and campus placements, yes: expect at least one coding round in Java. Service companies and some experienced-hire roles lean on core Java, frameworks and projects, but easy array, string and hash map problems still come up.
Which Java version should I prepare with?
Prepare on a current LTS release such as Java 21 or 25, but know which version introduced each feature, since many teams still run Java 8, 11 or 17. Java 8 features (lambdas, streams, Optional) are still common topics.
How long does it take to prepare for a Java interview?
If you already program in Java, two to four weeks of daily practice. Learning the language from scratch, expect two to three months.
Is Spring Boot asked in core Java interviews?
Only for roles that use it, which for experienced backend Java is most of them: expect questions on dependency injection, REST controllers and JPA. Fresher interviews usually stay with core Java, OOP, SQL basics and coding problems.
Coddy programming languages illustration

Learn to code with Coddy

GET STARTED