20 Essential Java Interview Questions
Tags: programming, java
Published: 2021-09-13 11:52:13

Hello, fellow developers, I have compiled a list of essential Java interview questions that I felt every developer should know.

Do drop your thoughts in the comments section below. Also, feel free to comment in case you find any content to be incorrect.

## 1. How do you reverse a string in Java without using the reverse() methods?
Java does not come out of the box with the reverse() method although the reverse() method does exist in a few libraries such as StringBuffer or StringBuilder. Hence, reversing an array has become a common interview question.

Following is a simple algorithm that can be used to reverse an array.
```java
public class StringReverse {

	public static void main(String[] args) {

		String str = "Flexiple";
		System.out.println(reverse(str));
	}

	public static String reverse(String in) {
		if (in == null)
			throw new IllegalArgumentException("Null is not valid”);

		StringBuilder out = new StringBuilder();

		char[] chars = in.toCharArray();

		for (int i = chars.length - 1; i >= 0; i--)
			out.append(chars[i]);

		return out.toString();
	}
}
```
## 2. Write a code snippet to implement a Fibonacci series using recursion?
The code snippet below implements the Fibonacci series using recursion which is a common Java interview question.
```java
public class FibonacciNumbers {
	public static int fibonacci(int n) {
		if (n <= 1)
			return n;
		return fibonacci(n - 1) + fibonacci(n - 2);
	}

	public static void main(String args[]) {
		int n = 10;
		System.out.println(fibonacci(n));
	}
}
```
## 3. How are whitespaces removed from a string in Java?
The Java strip() is a string method that removes all leading and trailing whitespaces. Strip() uses the Character.isWhitespace() method internally to check for whitespaces.

This method identifies whitespaces using Unicodes and hence it is the recommended method to remove whitespaces.

stripLeading() and stripTrailing() are alternatives in case you are only looking to remove leading or trailing whitespaces respectively.

The code below is an example of the Java strip() method
```java
String s = "  flexiple ";
		
s = s.strip();
		
System.out.println(s);
```
## 4. What causes a deadlock scenario? Write code to create a deadlock.
A deadlock scenario is caused when two threads require the same locks to execute.

These scenarios occur when both threads have obtained one lock and are waiting to obtain the other lock. However, since both threads wait for the other to execute they block each other causing a deadlock.

Multi Threaded programs suffer from deadlocks because the synchronized keyword is used to make the methods thread-safe. This means that only one thread can lock and use the synchronized method. Other threads have to wait for the current thread to complete.

The code below creates two threads that are in a deadlock.
```java
class Util
{
	static void sleep(long millis)
	{
		try
		{
			Thread.sleep(millis);
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		}
	}
}
class Shared
{
	synchronized void test1(Shared s2)
	{
		System.out.println("test1-begin");
		Util.sleep(1000);

		s2.test2();
		System.out.println("test1-end");
	}

	synchronized void test2()
	{
		System.out.println("test2-begin");
		Util.sleep(1000);

		System.out.println("test2-end");
	}
}

class Thread1 extends Thread
{
	private Shared s1;
	private Shared s2;

	public Thread1(Shared s1, Shared s2)
	{
		this.s1 = s1;
		this.s2 = s2;
	}

	@Override
	public void run()
	{
		s1.test1(s2);
	}
}

class Thread2 extends Thread
{
	private Shared s1;
	private Shared s2;

	public Thread2(Shared s1, Shared s2)
	{
		this.s1 = s1;
		this.s2 = s2;
	}

	@Override
	public void run()
	{
		s2.test2(s1);
	}
}

public class Deadlock
{
	public static void main(String[] args)
	{
		Shared s1 = new Shared();

		Shared s2 = new Shared();

		Thread1 t1 = new Thread1(s1, s2);
		t1.start();

		Thread2 t2 = new Thread2(s1, s2);
		t2.start();

		Util.sleep(2000);
	}
}
```
## 5. Write Java code to print the date in a particular format?
The Java SimpleDateFormat class helps convert dates from one format to another. The method also allows users to take a string date format and modify it to the desired format.

This code converts a date to the standard format: DD/MM/YYYY
```java
import java.text.SimpleDateFormat;  
import java.util.Date;  
public class CurrentDateTimeExample2 {  
public static void main(String[] args) {  
    SimpleDateFormat formatter = new SimpleDateFormat("DD/MM/YYYY HH:mm:ss");  
    Date date = new Date();  
    System.out.println(formatter.format(date));  
}  
} 
``` 
Code snippet to convert the date into MM/DD/YYYY
```java
import java.text.SimpleDateFormat;  
import java.util.Date;  
public class CurrentDateTimeExample2 {  
public static void main(String[] args) {  
    SimpleDateFormat formatter = new SimpleDateFormat("MM/DD/YYYY HH:mm:ss");  
    Date date = new Date();  
    System.out.println(formatter.format(date));  
}  
}
```
## 6. How to sort a HashMap by its values?
HashMaps are used to implement map interfaces. They allow users to store key-value pairs, however, the keys must be unique.

HashMaps are not ordered collections, and sorting them would not make sense but since sorting hashmaps can be quite tricky they are a common Java interview question.

The code below is the implementation of the same.
```java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class SortHashMap {

	public static void main(String[] args) {
		Map scores = new HashMap<>();

		scores.put("John", 6);
		scores.put("Carol", 8);
		scores.put("Martin", 9);
		scores.put("Mona", 7);
		scores.put("Eric", 5);

		System.out.println(scores);

		scores = sortByValue(scores);

		System.out.println(scores);

	}

	private static Map sortByValue(Map scores) {
		Map sorted = new LinkedHashMap<>();

		Set> entrySet = scores.entrySet();
		System.out.println(entrySet);

		List> entryList = new ArrayList<>(entrySet);
		System.out.println(entryList);

		entryList.sort((x, y) -> x.getValue().compareTo(y.getValue()));
		System.out.println(entryList);

		for (Entry e : entryList)
			sorted.put(e.getKey(), e.getValue());

		return sorted;
	}

}
```

## 7. What does the forEach() method do? Explain with an example.
forEach() is a method that is used to iterate over objects in Java. However, unlike other loops, a loop counter is not declared or initialized but rather a variable is passed as an iterable.

Hence, forEach() is commonly used with arrays or collection classes.

Syntax
```java
for (type var : array) 
{ 
    statements using var;
}
```
Example Using forEach():
```java
class ExampleForEach	
{
	public static void main(String[] arg)
	{
		{
			int[] scores = { 10, 13, 9, 11, 11};
			
			int highest_score = maximum(scores);
			System.out.println(highest_scores);
		}
	}
	public static int maximum(int[] numbers)
	{
		int max = numbers[0];
		
		// for each loop
		for (int n : numbers)
		{
			if (n > max)
			{
				max = n;
			}
		}
	return max;
	}
}
```

## 8. What are Functional Interfaces and how are they created?
An interface that contains only one abstract method is called a functional interface. Subsequently, functional interfaces can have only one functionality, however, they could contain multiple default methods.

With Java 8, lambda expressions can be used to instantiate functional interfaces making it much easier.

Examples of functional interfaces include - ActionListener, Comparable

Here is the code used to define a functional interface.
```java
@FunctionalInterface
interface Foo {
	void test();
}
```
## 9. Describe Overloading with an example.
Overloading is the process of allowing multiple methods with the same name, but differing based on their signatures, data type, or the number of parameters.

This allows the user to reuse a single method rather than creating and remembering multiple methods. In short, overloading is linked to compiler time polymorphism.

Code example of overloading a method:
```java
public class Sum {

	public int sum(int x, int y)
	{
		return (x + y);
	}

	public int sum(int x, int y, int z)
	{
		return (x + y + z);
	}

	public double sum(double x, double y)
	{
		return (x + y);
	}

	public static void main(String args[])
	{
		Sum s = new Sum();
		System.out.println(s.sum(10, 20));
		System.out.println(s.sum(10, 20, 30));
		System.out.println(s.sum(10.5, 20.5));
	}
}
```

## 10. Describe Overriding with an example.
Overriding is a feature in Java that allows subclasses or child classes to provide a distinct implementation for an existing method in the parent class.

When a subclass method has the same name, parameter, and return type as the parent class, then that method overrides the method in the parent class. And the version of the method invoked determines which method will be executed. Overriding is a way to achieve runtime polymorphism.

Code example of Overriding a method:
```java
class Parent {
	void show()
	{
		System.out.println("Parent's show()");
	}
}

class Child extends Parent {
	@Override
	void show()
	{
		System.out.println("Child's show()");
	}
}

class Main {
	public static void main(String[] args)
	{
		Parent obj1 = new Parent();
		obj1.show();

		Parent obj2 = new Child();
		obj2.show();
	}
}
```

## 11. What is binary search? And how is it implemented?
The binary search algorithm is used to search for a value in a sorted array or collection type. This search method is significantly faster than linear search methods.

Binary search splits the array into smaller sets and then applies rules to check for the input key.


**Steps to implement Binary Search:**
- Sort the array in ascending order
- Find the middle value of the array, and compare it with the key
- If the key is equal to the middle value, return true
- If false, check if the key is larger or smaller than the middle value
- Next, based on the result check for the key in the upper or lower half respectively
- Iterate and compare each value with the key
**Code snippet implementation binary search:**
```java
import java.util.Scanner;

public class BinarySearch {

    public static void main(String[] args) {

        Scanner commandReader = new Scanner(System.in);
        System.out.println("Enter total number of elements : ");
        int length = commandReader.nextInt();
        int[] input = new int[length];

        System.out.printf("Enter %d integers %n", length);
        for (int i = 0; i < length; i++) {
            input[i] = commandReader.nextInt();
        }

        System.out.println("Please enter number to be searched in array 
                                    (sorted order)");
        int key = commandReader.nextInt();

        int index = performBinarySearch(input, key);

        if (index == -1) {
            System.out.printf("Sorry, %d is not found in array %n", key);
        } else {
            System.out.printf("%d is found in array at index %d %n", key,
                                                         index);
        }

        commandReader.close();

    }


    public static int performBinarySearch(int[] input, int number) {
        int low = 0;
        int high = input.length - 1;

        while (high >= low) {
            int middle = (low + high) / 2;
            if (input[middle] == number) {
                return middle;
            } else if (input[middle] < number) {
                low = middle + 1;
            } else if (input[middle] > number) {
                high = middle - 1;
            }
        }
        return -1;
    }

}
```

## 12. What are some best practices to avoid deadlocks in Java?
- Nesting Locks: A major cause of deadlocks is when locks are given to multiple threads. Avoiding giving locks to multiple threads in case a thread with a lock already exists can help prevent deadlocks.
- Using the Thread.join(): Deadlocks can also appear when a thread waits for a resource from another thread. However, in such cases the Thread.join() can be used with the maximum execution time.
- Using Lock only when necessary: Practice using locks only on members when it is required. Having unnecessary locks is a major cause of deadlocks.

## 13. Write a code to implement LRU caching in Java?
LRU stands for Least Recently Used cache. LRU caching scheme is used to remove the least recently used cache.

This process takes place when the existing cache is full and the new page referred is not present in the existing cache.

The code below is the implementation of the same.
```java
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Iterator;

public class LRUCache {

	private Deque doublyQueue;

	private HashSet hashSet;

	private final int CACHE_SIZE;

	LRUCache(int capacity) {
		doublyQueue = new LinkedList<>();
		hashSet = new HashSet<>();
		CACHE_SIZE = capacity;
	}

	public void refer(int page) {
		if (!hashSet.contains(page)) {
			if (doublyQueue.size() == CACHE_SIZE) {
				int last = doublyQueue.removeLast();
				hashSet.remove(last);
			}
		}
		else {/* The found page may not be always the last element, even if it's an
			intermediate element that needs to be removed and added to the start
			of the Queue */
			doublyQueue.remove(page);
		}
		doublyQueue.push(page);
		hashSet.add(page);
	}

	public void display() {
		Iterator itr = doublyQueue.iterator();
		while (itr.hasNext()) {
			System.out.print(itr.next() + " ");
		}
	}

	public static void main(String[] args) {
		LRUCache cache = new LRUCache(4);
		cache.refer(1);
		cache.refer(2);
		cache.refer(3);
		cache.refer(1);
		cache.refer(4);
		cache.refer(5);
		cache.refer(2);
		cache.refer(2);
		cache.refer(1);
		cache.display();
	}
}
```

## 14. Rotate an array based on K’s position, Eg k = 2?
The code snippet rotates an array based on a specified position. Although it appears straightforward it tests your understanding of loops and arrays and hence is a common Java interview question.
```java
public static int[] rotateBruteForce(int[] nums, int k) {
 for (int i = 0; i < k; i++) { 
 for (int j = nums.length - 1; j > 0; j--) {
 // move each number by 1 place
 int temp = nums[j];
 nums[j] = nums[j - 1];
 nums[j - 1] = temp;
 }
 System.out.println("Array rotation after "+(i+1)+" step");
 printArray(nums);
 System.out.println();
 }
 return nums;
 }
```

## 15. What are Queues in Java? Implement them using arrays.
Queues are linear structures that demonstrate the First In First Out order of operations.

Java does provide easier implementations for abstract data types such as queues, stacks, etc. However, implementing them using an array is a question that tests your understanding of the concept.

Remember that array implementation of a Queue is not dynamic.
```java
package org.arpit.java2blog;
 
public class QueueUsingArrayMain {
 
    private int capacity;
    int queueArr[];
    int front;
    int rear;
    int currentSize = 0;
 
    public QueueUsingArrayMain(int sizeOfQueue) {
        this.capacity = sizeOfQueue;
        front = 0;
        rear = -1;
        queueArr = new int[this.capacity];
    }
```

## 16. Describe HeapSort? Write the code to implement it.
HeapSort is a sorting technique based on the binary heap data structure.

A binary heap is a binary tree where items are stored such that the values in the parent node are either greater (max-heap) or smaller (min-heap) than the values in a child node.

The former is known as max-heap and the latter is min-heap.

The code to implement HeapSort is as follows:
```java
public class HeapSort {
	public void sort(int arr[])
	{
		int n = arr.length;

		// Build heap (rearrange array)
		for (int i = n / 2 - 1; i >= 0; i--)
			heapify(arr, n, i);

		// One by one extract an element from heap
		for (int i = n - 1; i > 0; i--) {
			// Move current root to end
			int temp = arr[0];
			arr[0] = arr[i];
			arr[i] = temp;

			// call max heapify on the reduced heap
			heapify(arr, i, 0);
		}
	}

	// To heapify a subtree rooted with node i which is
	// an index in arr[]. n is size of heap
	void heapify(int arr[], int n, int i)
	{
		int largest = i; // Initialize largest as root
		int l = 2 * i + 1; // left = 2*i + 1
		int r = 2 * i + 2; // right = 2*i + 2

		// If left child is larger than root
		if (l < n && arr[l] > arr[largest])
			largest = l;

		// If right child is larger than largest so far
		if (r < n && arr[r] > arr[largest])
			largest = r;

		// If largest is not root
		if (largest != i) {
			int swap = arr[i];
			arr[i] = arr[largest];
			arr[largest] = swap;

			// Recursively heapify the affected sub-tree
			heapify(arr, n, largest);
		}
	}

	/* A utility function to print array of size n */
	static void printArray(int arr[])
	{
		int n = arr.length;
		for (int i = 0; i < n; ++i)
			System.out.print(arr[i] + " ");
		System.out.println();
	}

	// Driver code
	public static void main(String args[])
	{
		int arr[] = { 12, 11, 13, 5, 6, 7 };
		int n = arr.length;

		HeapSort ob = new HeapSort();
		ob.sort(arr);

		System.out.println("Sorted array is");
		printArray(arr);
	}
}
```
## 17. What is Memoization?
Memoization is an approach that helps solve problems caused by dynamic programming. This process ensures that a given method does not execute more than once for the same inputs.

The return values are stored in Hashtables or Hashmaps and reused whenever required.

The code below is an example of memoization in a Fibonacci series.
```java
import java.io.*;

class GFG
{
	
// Fibonacci Series
// using Recursion
static int fib(int n)
{

	// Base case
	if (n <= 1)
		return n;

	// recursive calls
	return fib(n - 1) +
		fib(n - 2);
}

// Driver Code
public static void main (String[] args)
{
	int n = 6;
	System.out.println(fib(n));
}
}
```

## 18. Write a code snippet to implement bubble sort?
The code below is the solution for bubble sort which is a common Java interview question.
```java
public class BubbleSortExample {  
    static void bubbleSort(int[] arr) {  
        int n = arr.length;  
        int temp = 0;  
         for(int i=0; i < n; i++){  
                 for(int j=1; j < (n-i); j++){  
                          if(arr[j-1] > arr[j]){  
                                 //swap elements  
                                 temp = arr[j-1];  
                                 arr[j-1] = arr[j];  
                                 arr[j] = temp;  
                         }  
                 }  
         }  
    }  
    public static void main(String[] args) {  
                int arr[] ={3,60,35,2,45,320,5};  
                System.out.println("Array Before Bubble Sort");  
                for(int i=0; i < arr.length; i++){  
                        System.out.print(arr[i] + " ");  
                }  
                System.out.println();  
                bubbleSort(arr);//sorting array elements using bubble sort
                System.out.println("Array After Bubble Sort");  
                for(int i=0; i < arr.length; i++){  
                        System.out.print(arr[i] + " ");  
                }  
   
        }  
}
```

## 19. What are trie data structures in Java?
A trie is a data structure that stores data in an ordered tree structure, taking advantage of the keys that it stores. The node's position in a tree defines the key which is associated with the node and the descendants of the node have a common prefix.

Because of this structure, trie’s offer better performance and are also significantly faster at retrieving data.

However, the only disadvantage of using a trie, is that it requires more storage space.

## 20. Write a code snippet to convert a HashMap into an ArrayList?
The code below is used to convert a HashMap into an ArrayList.
```java
import java.util.ArrayList; 
import java.util.Collection; 
import java.util.HashMap; 
import java.util.Map.Entry; 
import java.util.Set; 
public class Java8MapToListExamples 
{ 
    public static void main(String[] args) 
    { 
        //Creating a HashMap object 
         
        HashMap studentPerformanceMap = new HashMap(); 
         
        //Adding elements to HashMap 
         
        studentPerformanceMap.put("John Kevin", "Average"); 
         
        studentPerformanceMap.put("Rakesh Sharma", "Good"); 
         
        studentPerformanceMap.put("Prachi D", "Very Good"); 
         
        studentPerformanceMap.put("Ivan Jose", "Very Bad"); 
         
        studentPerformanceMap.put("Smith Jacob", "Very Good"); 
         
        studentPerformanceMap.put("Anjali N", "Bad"); 
         
        //Getting Set of keys 
         
        Set keySet = studentPerformanceMap.keySet(); 
         
        //Creating an ArrayList of keys 
         
        ArrayList listOfKeys = new ArrayList(keySet); 
         
        System.out.println("ArrayList Of Keys :"); 
         
        for (String key : listOfKeys) 
        { 
            System.out.println(key); 
        }
         
        System.out.println("--------------------------"); 
         
        //Getting Collection of values 
         
        Collection values = studentPerformanceMap.values(); 
         
        //Creating an ArrayList of values 
         
        ArrayList listOfValues = new ArrayList(values); 
         
        System.out.println("ArrayList Of Values :"); 
         
        for (String value : listOfValues) 
        { 
            System.out.println(value); 
        } 
         
        System.out.println("--------------------------"); 
         
        //Getting the Set of entries 
         
        Set> entrySet = studentPerformanceMap.entrySet(); 
         
        //Creating an ArrayList Of Entry objects 
         
        ArrayList> listOfEntry = new ArrayList>(entrySet); 
         
        System.out.println("ArrayList of Key-Values :"); 
         
        for (Entry entry : listOfEntry) 
        { 
            System.out.println(entry.getKey()+" : "+entry.getValue()); 
        } 
    } 
}
```