Java Interview Questions for Developers

Use our engineer-created to interview and hire the most qualified Java developers for your organization.

Java

Despite its decades-long history, Java remains one of the go-to development languages for everything from server-side enterprise applications to big data software because of its dedication to object-oriented principles, extensive community support, and developed security guidelines. 

According to the CoderPad 2023 Developer survey, Java is the 2nd most in-demand language among technical recruiters and hiring managers.

To evaluate the Java skills of developers during coding interviews, we’ve provided realistic coding exercises and interview questions below.

Additionally, we’ve outlined a set of best practices to ensure that your interview questions accurately assess the candidates’ Java skills.

Java example coding exercise

Reverse engineer this Java code

We found this mysterious Java code. It looks like a quicksort algorithm, but it’s not – can you figure out what it does? Bonus points if you can evaluate its complexity!

Junior Java interview questions

Question: What is a NullPointerException in Java, and how do you prevent it? Write an example code snippet that could result in a NullPointerException and modify it to prevent the exception from occurring.

Answer: A NullPointerException occurs when a variable that is expected to contain an object reference is null, and an operation is performed on that variable as if it contained a valid object reference. To prevent it, you can add a null check before performing any operations on the variable. Here’s an example code snippet:

String name = null;

// This would cause a NullPointerException
System.out.println(name.length());

// To prevent the exception, add a null check
if (name != null) {
    System.out.println(name.length());
}Code language: Java (java)

Question: What is the difference between an interface and an abstract class in Java? Write an example code snippet that uses both an interface and an abstract class to demonstrate their differences.

Answer: An interface defines a contract that a class must implement, while an abstract class provides a partially implemented class that cannot be instantiated directly. Here’s an example code snippet:

// Interface example
interface Vehicle {
    void drive();
}

class Car implements Vehicle {
    public void drive() {
        System.out.println("Driving a car");
    }
}

// Abstract class example
abstract class Shape {
    int x;
    int y;

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

    abstract void draw();
}

class Circle extends Shape {
    int radius;

    Circle(int x, int y, int radius) {
        super(x, y);
        this.radius = radius;
    }

    void draw() {
        System.out.println("Drawing a circle");
    }
}Code language: Java (java)

Question: What is the purpose of the finally block in a try-catch-finally statement in Java? Write an example code snippet that demonstrates the use of a finally block.

Answer: The finally block is used to specify a code block that will be executed regardless of whether an exception was thrown or not. Here’s an example code snippet:

try {
    // Some code that may throw an exception
} catch (Exception e) {
    // Handle the exception
} finally {
    // Code that will be executed regardless of whether an exception was thrown or not
}Code language: Java (java)

Question: Explain the difference between the == operator and the equals() method in Java. Write an example code snippet that demonstrates the use of both.

Answer: The == operator tests for object equality, while the equals() method tests for value equality. Here’s an example code snippet:

String str1 = "hello";
String str2 = "hello";
String str3 = new String("hello");

// This will print true, because str1 and str2 refer to the same object in memory
System.out.println(str1 == str2);

// This will print false, because str1 and str3 refer to different objects in memory
System.out.println(str1 == str3);

// This will print true, because the values of str1 and str2 are equal
System.out.println(str1.equals(str2));

// This will also print true, because the values of str1 and str3 are equal
System.out.println(str1.equals(str3));Code language: Java (java)

Question: What is a Java package, and why is it useful? Write an example code snippet that demonstrates the use of a package.

Answer: A Java package is a way to group related classes, interfaces, and sub-packages together. It is useful for organizing code and avoiding naming conflicts, as well as making it easier to locate and reuse code. Here’s an example code snippet that demonstrates the use of a package:

package com.example;

public class MyClass {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}Code language: Java (java)

In this example, the class MyClass belongs to the com.example package. To run this code, you would need to save it in a file called MyClass.java and compile it using the javac command. You would also need to specify the package name when running the code using the java command: java com.example.MyClass.

Question: What is the difference between a checked and an unchecked exception in Java? Write an example code snippet that throws both types of exceptions.

Answer: A checked exception is a type of exception that must be either caught or declared in the method signature using the throws keyword, while an unchecked exception is a type of exception that does not have to be caught or declared. Here’s an example code snippet that throws both types of exceptions:

// Checked exception example
public void readFile() throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
    // Some code to read the file
}

// Unchecked exception example
public void divide(int a, int b) {
    if (b == 0) {
        throw new IllegalArgumentException("Cannot divide by zero");
    }
    int result = a / b;
    // Some code to use the result
}Code language: Java (java)

Question: What is the difference between a static method and an instance method in Java? Write an example code snippet that uses both types of methods.

Answer: A static method belongs to the class itself, rather than to a specific instance of the class, and can be called using the class name. An instance method, on the other hand, belongs to a specific instance of the class and can only be called using that instance. Here’s an example code snippet that uses both types of methods:

class MyClass {
    static void staticMethod() {
        System.out.println("This is a static method");
    }

    void instanceMethod() {
        System.out.println("This is an instance method");
    }
}

// Call the static method using the class name
MyClass.staticMethod();

// Create an instance of MyClass and call the instance method
MyClass obj = new MyClass();
obj.instanceMethod();Code language: JavaScript (javascript)

Question: What is the purpose of the super keyword in Java? Write an example code snippet that uses the super keyword.

Answer: The super keyword is used to call a method or constructor in the superclass. Here’s an example code snippet:

class Animal {
    void makeSound() {
        System.out.println("Some animal sound");
    }
}

class Dog extends Animal {
    void makeSound() {
        super.makeSound();
        System.out.println("Bark");
    }
}

// Create an instance of Dog and call its makeSound method
Dog dog = new Dog();
dog.makeSound();Code language: Java (java)

In this example, the Dog class extends the Animal class and overrides its makeSound() method. The super.makeSound() call in the Dog class calls the makeSound() method of the superclass, and the System.out.println("Bark") statement adds the specific sound of the Dog class.

Question: What is the difference between public, protected, and private access modifiers in Java? Write an example code snippet that uses all three access modifiers.

Answer: public means that the method or variable is accessible from any other class, protected means that the method or variable is accessible from within the same package and from subclasses, and private means that the method or variable is only accessible from within the same class. Here’s an example code snippet that uses all three access modifiers:

package com.example;

public class MyClass {
    public int publicVar = 1;
    protected int protectedVar = 2;
    private int privateVar = 3;

    public void publicMethod() {
        System.out.println("This is a public method");
    }

    protected void protectedMethod() {
        System.out.println("This is a protected method");
    }

    private void privateMethod() {
        System.out.println("This is a private method");
    }
}

// Another.java
package com.example.other;

import com.example.MyClass;

public class OtherClass extends MyClass {
    public void accessMyClass() {
        // Access public members
        int a = publicVar;
        publicMethod();

        // Access protected members
        int b = protectedVar;
        protectedMethod();

        // Cannot access private members
        // int c = privateVar;
        // privateMethod();
    }
}Code language: Java (java)

In this example, the MyClass class has three instance variables with different access modifiers and three methods with different access modifiers. The OtherClass class extends MyClass and can access the public and protected members of MyClass from within the same package or from a subclass, but cannot access the private members.

Question: What is polymorphism in Java? Write an example code snippet that demonstrates polymorphism.

Answer: Polymorphism in Java refers to the ability of objects of different classes to be used interchangeably, as long as they share a common interface or superclass. Here’s an example code snippet that demonstrates polymorphism:

interface Animal {
    void makeSound();
}

class Dog implements Animal {
    public void makeSound() {
        System.out.println("Bark");
    }
}

class Cat implements Animal {
    public void makeSound() {
        System.out.println("Meow");
    }
}

public class MyClass {
    public static void main(String[] args) {
        Animal[] animals = new Animal[2];
        animals[0] = new Dog();
        animals[1] = new Cat();

        for (Animal animal : animals) {
            animal.makeSound();
        }
    }
}Code language: Java (java)

In this example, the Animal interface defines the makeSound() method that is implemented by the Dog and Cat classes. The MyClass class creates an array of Animal objects and adds one Dog object and one Cat object. The for loop then calls the makeSound() method of each object in the array, resulting in the output “Bark” and “Meow”. This demonstrates polymorphism, as the Animal objects are able to be used interchangeably with their specific Dog and Cat implementations.

Intermediate Java interview questions

Question: Fix the following code to properly implement a binary search algorithm:

public static int binarySearch(int[] arr, int target) {
    int low = 0;
    int high = arr.length;
    while (low <= high) {
        int mid = (low + high) / 2;
        if (arr[mid] < target) {
            low = mid + 1;
        } else if (arr[mid] > target) {
            high = mid - 1;
        } else {
            return mid;
        }
    }
    return -1;
}Code language: Java (java)

Answer:
The issue with the code is that the high index should start at arr.length - 1 instead of arr.length. Here’s the corrected code:

public static int binarySearch(int[] arr, int target) {
    int low = 0;
    int high = arr.length - 1;
    while (low <= high) {
        int mid = (low + high) / 2;
        if (arr[mid] < target) {
            low = mid + 1;
        } else if (arr[mid] > target) {
            high = mid - 1;
        } else {
            return mid;
        }
    }
    return -1;
}Code language: Java (java)

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

Answer:
Both interfaces and abstract classes are used to define common behavior and functionality, but they differ in several ways. An interface is a collection of abstract methods and constants that can be implemented by any class that implements the interface. An abstract class is a class that cannot be instantiated and can contain both abstract and non-abstract methods.

One key difference is that a class can implement multiple interfaces, but can only extend one abstract class. Another difference is that an abstract class can have instance variables and non-abstract methods, while an interface cannot.

Question: Fix the following code to correctly sort an array of strings in alphabetical order:

public static void sortStrings(String[] arr) {
    for (int i = 0; i < arr.length; i++) {
        for (int j = 1; j < arr.length; j++) {
            if (arr[j-1].compareTo(arr[j]) > 0) {
                String temp = arr[j-1];
                arr[j-1] = arr[j];
                arr[j] = temp;
            }
        }
    }
}Code language: Java (java)

Answer:
The issue with the code is that the inner loop should start at i+1 instead of 1. Here’s the corrected code:

public static void sortStrings(String[] arr) {
    for (int i = 0; i < arr.length; i++) {
        for (int j = i+1; j < arr.length; j++) {
            if (arr[j-1].compareTo(arr[j]) > 0) {
                String temp = arr[j-1];
                arr[j-1] = arr[j];
                arr[j] = temp;
            }
        }
    }
}Code language: Java (java)

Question: What is the difference between a HashMap and a TreeMap in Java?

Answer:
Both HashMap and TreeMap are implementations of the Map interface in Java, but they differ in several ways. HashMap is an unordered collection of key-value pairs, while TreeMap is a sorted collection of key-value pairs based on the natural ordering of the keys or a specified Comparator.

HashMap allows null keys and values, and has constant-time average case performance for key-value operations. TreeMap does not allow null keys and has logarithmic-time performance for key-value operations. HashMap is generally faster for most operations, but TreeMap can be useful when the keys need to be

sorted or when iterating over the keys in a specific order.

Question: Fix the following code to correctly add elements to a HashSet:

Set<String> set = new Set<String>();
set.add("apple");
set.add("banana");
set.add("orange");Code language: Java (java)

Answer:
The issue with the code is that Set is an interface and cannot be directly instantiated. Instead, you should use a concrete implementation of the Set interface, such as HashSet. Here’s the corrected code:

Set<String> set = new HashSet<String>();
set.add("apple");
set.add("banana");
set.add("orange");Code language: Java (java)

Question: What is the difference between a stack and a queue in Java?

Answer:
Both stacks and queues are data structures used to store and retrieve elements, but they differ in several ways. A stack is a Last-In-First-Out (LIFO) data structure, where elements are added and removed from the same end. A queue is a First-In-First-Out (FIFO) data structure, where elements are added to the back and removed from the front.

In Java, you can implement a stack using the Stack class or the Deque interface with the push() and pop() methods. You can implement a queue using the LinkedList class or the Queue interface with the offer() and poll() methods.

Question: Fix the following code to correctly calculate the factorial of a number:

public static int factorial(int n) {
    if (n == 0) {
        return 1;
    }
    for (int i = n; i > 1; i--) {
        n *= i;
    }
    return n;
}Code language: Java (java)

Answer:
The issue with the code is that the loop is multiplying n by i instead of i-1. Here’s the corrected code:

public static int factorial(int n) {
    if (n == 0) {
        return 1;
    }
    int result = 1;
    for (int i = n; i > 1; i--) {
        result *= i;
    }
    return result;
}Code language: Java (java)

Question: What is the difference between an ArrayList and a LinkedList in Java?

Answer:
Both ArrayList and LinkedList are implementations of the List interface in Java, but they differ in several ways. ArrayList is backed by an array and provides constant-time random access to elements based on their index. LinkedList is backed by a doubly-linked list and provides constant-time insertion and deletion of elements at the beginning or end of the list.

ArrayList has better performance for random access operations, while LinkedList has better performance for insertion and deletion operations. ArrayList uses more memory than LinkedList for small lists but uses less memory for large lists.

Question: Fix the following code to correctly check if a string is a palindrome:

public static boolean isPalindrome(String s) {
    String reversed = "";
    for (int i = s.length() - 1; i >= 0; i--) {
        reversed += s.charAt(i);
    }
    return s == reversed;
}Code language: Java (java)

Answer:
The issue with the code is that it is comparing the original string s with the reversed string using the == operator, which compares object references rather than their contents. Instead, you should use the equals() method to compare the contents of the strings. Here’s the corrected code:

public static boolean isPalindrome(String s) {
    String reversed = "";
    for (int i = s.length() - 1; i >= 0; i--) {
        reversed += s.charAt(i);
    }
    return s.equals(reversed);
}Code language: Java (java)

Question: What is the difference between a HashSet and a TreeSet in Java?

Answer:
Both HashSet and TreeSet are implementations of the Set interface in Java, but they differ in several ways. HashSet uses a hash table to store its elements, which provides constant-time performance for basic operations such as add, remove, and contains. However, HashSet does not guarantee the order of its elements.

TreeSet uses a red-black tree to store its elements, which provides log-time performance for basic operations. TreeSet guarantees that its elements are sorted in natural order or in the order specified by a Comparator, which allows for efficient searching and iteration. However, TreeSet may have higher overhead than HashSet due to the use of a tree structure.

To summarize, use HashSet when you need fast add, remove, and contains operations and don’t care about the order of elements. Use TreeSet when you need elements sorted in a specific order and don’t mind sacrificing some performance for this feature.

Senior Java interview question

Question: There is a bug in the following code that is causing a NullPointerException. Can you identify and fix it?

public class MyClass {
    private List<String> myList;

    public MyClass(List<String> list) {
        myList.addAll(list);
    }

    public int getSize() {
        return myList.size();
    }
}Code language: Java (java)

Answer:
The bug in the code is that myList is never initialized, so when addAll is called on it, a NullPointerException is thrown. To fix this, myList needs to be initialized in the constructor before calling addAll. Here’s the corrected code:

public class MyClass {
    private List<String> myList;

    public MyClass(List<String> list) {
        myList = new ArrayList<>(list);
    }

    public int getSize() {
        return myList.size();
    }
}Code language: Java (java)

Question: What is the difference between a stack and a queue, and when would you use one over the other?

Answer:
A stack and a queue are both data structures that store and manipulate collections of elements. The main difference between them is the order in which elements are added and removed.

A stack uses a Last-In-First-Out (LIFO) ordering, meaning that the last element added to the stack is the first one to be removed. A queue, on the other hand, uses a First-In-First-Out (FIFO) ordering, meaning that the first element added to the queue is the first one to be removed.

You would use a stack when you need to keep track of elements in reverse order, such as when parsing and evaluating expressions or when implementing undo/redo functionality. You would use a queue when you need to process elements in the order they were added, such as when implementing a message queue or a task scheduler.

Question: There is a bug in the following code that is causing a ConcurrentModificationException. Can you identify and fix it?

public class MyClass {
    private List<String> myList;

    public MyClass(List<String> list) {
        myList = list;
    }

    public void removeElement(String element) {
        for (String str : myList) {
            if (str.equals(element)) {
                myList.remove(str);
            }
        }
    }
}Code language: Java (java)

Answer:
The bug in the code is that the remove method is called on myList while iterating over it using a for-each loop, which causes a ConcurrentModificationException to be thrown. To fix this, use an iterator to remove the element instead. Here’s the corrected code:

public class MyClass {
    private List<String> myList;

    public MyClass(List<String> list) {
        myList = list;
    }

    public void removeElement(String element) {
        Iterator<String> iterator = myList.iterator();
        while (iterator.hasNext()) {
            String str = iterator.next();
            if (str.equals(element)) {
                iterator.remove();
            }
        }
    }
}Code language: Java (java)

Question: What is the difference between an abstract class and an interface in Java, and when would you use one over the other?

Answer:
An abstract class is a class that cannot be instantiated and is typically used as a base class for other classes to inherit from. An abstract class can contain both abstract and non-abstract methods, and it can also have instance variables and constructors.

An interface, on the other hand, is a contract that specifies a set of methods that a class must implement. An interface cannot have instance variables or constructors, and all of its methods are implicitly abstract.

You would use an abstract class when you want to provide a default implementation for some

of the methods and/or when you need to declare instance variables or constructors. You would use an interface when you want to define a set of methods that multiple unrelated classes can implement, or when you want to define a type that a class can implement along with other types (since Java does not support multiple inheritance of classes).

Question: There is a bug in the following code that is causing a deadlock. Can you identify and fix it?

public class MyClass {
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();

    public void method1() {
        synchronized (lock1) {
            synchronized (lock2) {
                // do something
            }
        }
    }

    public void method2() {
        synchronized (lock2) {
            synchronized (lock1) {
                // do something
            }
        }
    }
}Code language: Java (java)

Answer:
The bug in the code is that the method1 and method2 methods are both acquiring locks in different order, which can lead to a deadlock if they are called concurrently. To fix this, make sure that both methods always acquire the locks in the same order. Here’s the corrected code:

public class MyClass {
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();

    public void method1() {
        synchronized (lock1) {
            synchronized (lock2) {
                // do something
            }
        }
    }

    public void method2() {
        synchronized (lock1) {
            synchronized (lock2) {
                // do something
            }
        }
    }
}Code language: Java (java)

Question: What is the difference between a HashSet and a TreeSet, and when would you use one over the other?

Answer:
Both HashSet and TreeSet are implementations of the Set interface in Java, but they have different characteristics.

HashSet stores elements in a hash table, which provides O(1) time complexity for add, remove, and contains operations on average. However, it does not preserve the order of elements, so iterating over a HashSet does not guarantee any specific order.

TreeSet, on the other hand, stores elements in a red-black tree, which provides O(log n) time complexity for add, remove, and contains operations on average. It also maintains the elements in sorted order, so iterating over a TreeSet will give you the elements in ascending order.

You would use a HashSet when you need fast access to elements and do not care about the order in which they were added. You would use a TreeSet when you need the elements to be sorted and/or need to perform range queries (such as finding the smallest or largest element)

Question: What is the purpose of the SOLID principles in software development, and how do they help developers build better systems?

Answer:
The SOLID principles are a set of design principles intended to help developers create systems that are easier to maintain, extend, and modify over time.

  • Single Responsibility Principle (SRP) – each class should have only one responsibility or reason to change.
  • Open-Closed Principle (OCP) – software entities should be open for extension but closed for modification.
  • Liskov Substitution Principle (LSP) – objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program.
  • Interface Segregation Principle (ISP) – clients should not be forced to depend on methods they do not use.
  • Dependency Inversion Principle (DIP) – high-level modules should not depend on low-level modules; both should depend on abstractions.

By adhering to these principles, developers can create systems that are more modular, easier to test, and less brittle. This, in turn, leads to systems that are easier to maintain, extend, and modify over time. The SOLID principles help to reduce technical debt and create systems that are more robust, scalable, and maintainable.

Question: What is the purpose of design patterns in software development, and how can they be used effectively?

Answer:
Design patterns are common solutions to recurring problems in software design. They provide a standardized way to solve common problems and can save developers time and effort by providing a proven solution that has already been vetted and tested by the community.

Design patterns can be used effectively by first understanding the problem you are trying to solve and then selecting the appropriate design pattern that addresses that problem. It’s important to use design patterns judiciously, however, as overusing them can lead to overly complex code that is difficult to understand and maintain.

Design patterns can be organized into categories, such as creational, structural, and behavioral patterns. Each category addresses a different set of problems and provides a different set of solutions. By familiarizing yourself with the various design patterns and their use cases, you can become a more effective and efficient developer, able to build more maintainable, scalable, and robust systems.

Question: What is the purpose of the Factory design pattern, and how does it work in Java?

Answer:
The Factory design pattern is a creational pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created. The Factory pattern is used when we want to create objects based on some input or condition, but we want to abstract away the details of object creation from the rest of the code.

In Java, we can implement the Factory pattern using an interface or abstract class that defines the factory method, and then create concrete factory classes that implement this interface or extend the abstract class. The concrete factory classes can then be used to create specific instances of objects based on some input or condition.

Question: The following code is an implementation of the Observer design pattern in Java, but there is a problem. Can you identify and fix the issue?

import java.util.Observable;
import java.util.Observer;

public class MyObservable extends Observable {
   private int value;

   public MyObservable() {
      value = 0;
   }

   public int getValue() {
      return value;
   }

   public void setValue(int newValue) {
      value = newValue;
      setChanged();
      notifyObservers(value);
   }
}

public class MyObserver implements Observer {
   private int value;

   @Override
   public void update(Observable observable, Object arg) {
      value = (int) arg;
   }

   public int getValue() {
      return value;
   }
}Code language: Java (java)

Answer:

The issue with the above code is that the value field in the MyObserver class is not being updated properly when the update() method is called. This is because the update() method is called asynchronously when the observed object’s state changes, and the value field may be updated by multiple threads.

To fix this, we can use a synchronized block in the update() method to ensure that only one thread can access the value field at a time:

public void update(Observable observable, Object arg) {
   synchronized(this) {
      value = (int) arg;
   }
}Code language: Java (java)

In this version, we synchronize on the this object to ensure that only one thread can access the value field at a time, and we update the field with the new value passed in as an argument.

1,000 Companies use CoderPad to Screen and Interview Developers

Best practices to Interview Java Developers

When carrying out Java interviews, it is crucial to take into account various interviewing aspects — such as the applicant’s experience and the specific engineering position — to create an effective interview experience. To optimize the results of your Java interview questions, we suggest implementing the following best practices with applicants:

  • Develop technical inquiries that correspond to real-world business scenarios within your company. This approach will not only engage the applicant more effectively but also help you better evaluate their fit for your team.
  • Promote a sense of collaboration by inviting the candidate to ask questions throughout the interview.
  • Since Java is built around object-oriented principles, make sure you’re assessing their ability to utilize these principles in their coding.
  • If you are hiring Java EE engineers, state clearly the specific technologies you require (JDBC, EJB, …), as they are quite numerous.

Moreover, it is essential to observe standard interview practices when conducting Java interviews. This involves tailoring the complexity of the questions to match the candidate’s development skillset, offering prompt updates on their application status, and giving them the opportunity to inquire about the evaluation process or working alongside you and your team.