Java remains one of the most widely deployed programming languages in the world, powering everything from enterprise banking systems and Android applications to cloud microservices and big data pipelines. For any developer targeting a Java role, java coding interview questions are the definitive test of whether you can translate language knowledge into working programs under pressure and on a whiteboard.
Unlike conceptual Java questions that ask what a feature does, coding interview questions ask you to demonstrate it. Interviewers evaluate how you approach a problem, whether you consider edge cases, how clearly you reason about your solution before writing it, and whether you can optimise when pushed. These skills are what separate developers who know Java from developers who can build with it.
This guide covers the top 30 Java coding interview questions with detailed explanations of the approach, the logic behind each solution, and the key reasoning interviewers want to hear. Each question is drawn from the most frequently tested categories: strings, numbers, arrays, OOP, recursion, sorting, collections, and modern Java features.
Read Next: Top 50 Technical Interview Questions
What Java Coding Interview Questions Actually Test

Java coding interviews are not purely about syntax recall. Interviewers want to see your problem-solving process in real time. Before you write a single line of code, they expect you to restate the problem, identify edge cases, state your approach, and discuss its time and space complexity. Candidates who jump directly to code without verbalising their thinking consistently perform worse than those who take 60 seconds to plan.
The most commonly tested problem categories in Java coding interviews are string manipulation (reversal, palindrome, anagram checks, character frequency), number problems (prime checking, Armstrong numbers, Fibonacci, factorial), array operations (searching, sorting, finding duplicates, second-largest element), object-oriented programming (inheritance, overloading, overriding, interface design), and collections (HashMap usage, sorting, deduplication with LinkedHashSet).
Senior interviews add recursion and algorithm design. Data structure implementations such as reversing a linked list or implementing binary search are staples. Modern Java features including lambda expressions, streams, functional interfaces, and records appear increasingly at mid and senior levels. Knowing what category a question falls into before answering it helps you pick the right tool immediately.
String and Number Coding Questions (Q1 to Q10)
String and number problems are asked in every Java interview at every level. Know the core digit-manipulation techniques using modulo and division, and the String API methods cold.
Q1. How do you reverse a string in Java?
Answer: String reversal is one of the first coding questions asked in Java interviews. There are two main approaches: using StringBuilder (the standard modern approach) and using a character loop (to show you understand string internals).
The StringBuilder approach is concise and leverages the built-in reverse() method. The manual approach iterates from the last character to the first and builds the result character by character. Both have O(n) time complexity.
Approach 1: StringBuilder (preferred in interviews)
String s = "Hello World";
String reversed = new StringBuilder(s).reverse().toString();
System.out.println(reversed); // dlroW olleH
Approach 2: Character loop (demonstrates understanding)
String s = "Hello World";
String res = "";
for (int i = s.length() - 1; i >= 0; i--) {
res = res + s.charAt(i);
}
System.out.println(res); // dlroW olleH
The loop approach concatenates characters from the end to the beginning. Starting at index s.length()-1 and decrementing to 0 captures every character in reverse order. Mention in interviews that string concatenation inside loops creates many intermediate String objects. For production code, use StringBuilder inside the loop for better memory efficiency.
Q2. How do you check whether a string is a palindrome in Java?
Answer: A palindrome is a string that reads the same forward and backward. “madam”, “racecar”, and “121” are palindromes. The most common approach reverses the string and compares it to the original.
Code
String s = "madam";
String rev = new StringBuilder(s).reverse().toString();
if (s.equals(rev)) {
System.out.println("Palindrome");
} else {
System.out.println("Not a palindrome");
}
The key insight is using equals() for string comparison, never ==. The == operator compares object references in Java, not string content. Since reversed produces a new String object, == would return false even for a true palindrome. An optimised two-pointer approach compares characters from both ends inward without creating a reversed copy, which halves the iterations needed.
Q3. How do you check whether a number is even or odd in Java?
Answer: This foundational question tests whether you know the modulo operator and can apply basic conditional logic. Even numbers are perfectly divisible by 2 with no remainder.
Code
int n = 27;
if (n % 2 == 0) {
System.out.println("Even");
} else {
System.out.println("Odd");
}
The modulo operator % returns the remainder of division. For even numbers n % 2 is 0. For odd numbers n % 2 is 1. A follow-up interviewers sometimes ask is to print all odd or even numbers in a range using a for loop, or to count how many odd numbers exist between 1 and 100.
Q4. How do you reverse a number in Java?
Answer: Reversing a number uses the three key digit-manipulation operations: modulo 10 extracts the last digit, multiplication by 10 shifts digits left, and division by 10 removes the last digit. These three operations are the foundation of most number-based Java interview problems.
Code
int num = 12345;
int res = 0;
while (num > 0) {
int rem = num % 10; // extract last digit
res = (res * 10) + rem; // shift result left, add digit
num = num / 10; // remove last digit
}
System.out.println("Reversed: " + res); // 54321
Trace through 12345: first iteration rem=5, res=5, num=1234. Second: rem=4, res=54, num=123. Third: rem=3, res=543, num=12. Fourth: rem=2, res=5432, num=1. Fifth: rem=1, res=54321, num=0. The loop terminates. Mastering this trace is essential because palindrome number and Armstrong number checks both build directly on this pattern.
Q5. How do you check if a number is a palindrome in Java?
Answer: A number is a palindrome if it reads the same forwards and backwards. The approach stores the original number, reverses it using the digit-reversal algorithm, then compares the reversed result to the original.
Code
int num = 121;
int original = num;
int res = 0;
while (num > 0) {
int rem = num % 10;
res = (res * 10) + rem;
num = num / 10;
}
if (original == res) {
System.out.println("Palindrome");
} else {
System.out.println("Not a palindrome");
}
The original value must be stored before the while loop because the loop modifies num to zero. After the loop, original (121) is compared to res (121). They are equal so this is a palindrome. For the number 123, the reversed value would be 321, which does not equal 123, so it is not a palindrome. Negative numbers are never palindromes.
Q6. How do you check if a number is an Armstrong number in Java?
Answer: An Armstrong number (also called a narcissistic number) is one where the sum of its digits each raised to the power of the number of digits equals the original number. 153 is Armstrong because 1 cubed + 5 cubed + 3 cubed = 1 + 125 + 27 = 153.
Code
int num = 153;
int original = num;
int res = 0;
while (num > 0) {
int rem = num % 10;
res = res + (rem * rem * rem); // cube each digit
num = num / 10;
}
if (original == res) {
System.out.println("Armstrong number");
} else {
System.out.println("Not Armstrong");
}
The only change from the palindrome check is in the accumulation step: instead of reversing the number, each extracted digit is cubed and added to the result. Other 3-digit Armstrong numbers include 370 (3 cubed + 7 cubed + 0 cubed = 370), 371, and 407. For a general solution handling any number of digits, calculate the digit count first and use Math.pow(rem, digitCount).
Q7. How do you print the Fibonacci sequence in Java?
Answer: The Fibonacci sequence starts with 0 and 1, and every subsequent number is the sum of the two preceding numbers: 0, 1, 1, 2, 3, 5, 8, 13, 21. This problem can be solved iteratively or recursively.
Iterative approach (preferred for most interviews)
int a = 0, b = 1;
System.out.println(a);
System.out.println(b);
for (int i = 1; i <= 8; i++) {
int c = a + b;
System.out.println(c);
a = b;
b = c;
}
Two variables a and b track the previous two terms. Each iteration computes their sum c, prints it, then slides the window forward: a becomes b, b becomes c. The loop runs n-2 times since the first two numbers are printed before the loop. The iterative approach runs in O(n) time and O(1) space. The recursive approach is more elegant but has exponential time complexity O(2 to the n) without memoisation.
Q8. How do you find the factorial of a number in Java?
Answer: The factorial of n (written n!) is the product of all integers from 1 to n. Factorial of 5 is 5 x 4 x 3 x 2 x 1 = 120. Factorial of 0 is defined as 1.
Iterative approach
int n = 5;
int fact = 1;
for (int i = 1; i <= n; i++) {
fact = fact * i;
}
System.out.println("Factorial: " + fact); // 120
Recursive approach
static int factorial(int n) {
if (n == 0 || n == 1) return 1;
return n * factorial(n - 1);
}
The iterative approach initialises fact to 1 and multiplies each integer from 1 to n. The recursive approach reduces n by 1 on each call until it hits the base case of 0 or 1. The recursive call stack grows to depth n, using O(n) space. For large values of n, int overflows: use long for n up to about 20, or BigInteger for arbitrary precision.
Q9. How do you check if a given number is prime in Java?
Answer: A prime number is greater than 1 and divisible only by 1 and itself. The optimised approach checks divisibility only up to the square root of the number, cutting the number of iterations dramatically.
Code
int n = 17;
boolean isPrime = true;
if (n < 2) {
isPrime = false;
} else {
for (int i = 2; i <= Math.sqrt(n); i++) {
if (n % i == 0) {
isPrime = false;
break;
}
}
}
System.out.println(n + (isPrime ? " is prime" : " is not prime"));
If n has a factor greater than its square root, the corresponding co-factor must be less than the square root, so we would have found it already. This reduces the loop from n iterations to root n iterations. The break statement exits immediately when a divisor is found. Edge cases: numbers less than 2 are not prime. 2 is the only even prime. Always handle these before the loop.
Q10. How do you find the sum and count of digits in a given number?
Answer: Both operations use the same digit-extraction loop. The modulo operator extracts the last digit, which is then added to a running sum or used to increment a counter, and division removes that digit for the next iteration.
Sum of digits
int num = 12345;
int sum = 0;
while (num > 0) {
sum += num % 10;
num /= 10;
}
System.out.println("Sum: " + sum); // 15
Count of digits
int num = 12345;
int count = 0;
while (num > 0) {
count++;
num /= 10;
}
System.out.println("Count: " + count); // 5
For sum: each digit is added to the running total. For count: each iteration removes one digit and increments the counter, regardless of the digit value. The product of digits uses the same structure but initialises a result variable to 1 and multiplies each extracted digit instead of adding it.
Array and Collection Coding Questions (Q11 to Q18)
Array and collection problems are among the most frequently tested categories. HashMap-based frequency counting and LinkedHashSet-based deduplication are standard patterns worth memorising.
Q11. How do you find the second-largest number in an array in Java?
Answer: Finding the second-largest element in a single pass uses two variables: one tracking the largest seen so far and one tracking the second-largest. This avoids sorting, giving O(n) time instead of O(n log n).
Code
int[] arr = {10, 5, 20, 8, 15};
int largest = Integer.MIN_VALUE;
int secondLargest = Integer.MIN_VALUE;
for (int num : arr) {
if (num > largest) {
secondLargest = largest;
largest = num;
} else if (num > secondLargest && num != largest) {
secondLargest = num;
}
}
System.out.println("Second largest: " + secondLargest); // 15
Initialising both variables to Integer.MIN_VALUE handles arrays with negative numbers. The condition num != largest excludes duplicates of the largest value. After one full pass: largest is 20, secondLargest is 15. Edge cases to mention: arrays with fewer than two distinct elements, and arrays where all elements are equal.
Q12. How do you remove duplicates from an array in Java?
Answer: The most efficient approach uses a LinkedHashSet, which eliminates duplicates automatically while preserving insertion order. This gives O(n) time complexity with clean code.
Code
int[] arr = {1, 2, 3, 2, 4, 3, 5};
LinkedHashSet<Integer> set = new LinkedHashSet<>();
for (int num : arr) {
set.add(num);
}
System.out.println("Unique elements: " + set); // [1, 2, 3, 4, 5]
LinkedHashSet maintains insertion order unlike HashSet, so the output preserves the order in which elements first appeared. Because sets do not allow duplicate values, calling add() with a value already in the set simply does nothing. Converting the array to a List first with Arrays.asList() followed by new LinkedHashSet<>(list) achieves the same result in fewer lines.
Q13. How do you find the frequency of each character in a string?
Answer: Character frequency is a classic HashMap problem. The map stores each character as a key and its count as the value. Each character in the string either initialises its count to 1 or increments an existing count.
Code
String str = "programming";
HashMap<Character, Integer> map = new HashMap<>();
for (char c : str.toCharArray()) {
map.put(c, map.getOrDefault(c, 0) + 1);
}
System.out.println(map);
// {p=1, r=2, o=1, g=2, a=1, m=2, i=1, n=1}
getOrDefault(c, 0) returns the current count for character c if it exists in the map, or 0 if it does not. Adding 1 and calling put updates the count. toCharArray() converts the string into a char array for clean iteration. This same pattern with getOrDefault is the standard template for any frequency counting problem in Java.
Q14. How do you check if two arrays contain the same elements?
Answer: Converting both arrays to sets eliminates duplicates and order dependence. If both sets are equal, the arrays contain the same distinct elements. For order-sensitive equality, sort both arrays and compare with Arrays.equals().
Code (set-based for same elements regardless of order)
int[] a = {1, 2, 3, 4};
int[] b = {4, 3, 1, 2};
Set<Integer> setA = new HashSet<>();
Set<Integer> setB = new HashSet<>();
for (int x : a) setA.add(x);
for (int x : b) setB.add(x);
System.out.println(setA.equals(setB)); // true
HashSet.equals() returns true when both sets contain exactly the same elements. This handles different orderings of the same elements. If the requirement is that elements must appear in the same order and with the same frequencies, use Arrays.sort(a); Arrays.sort(b); followed by Arrays.equals(a, b) instead.
Q15. How do you sort an array in Java?
Answer: Java provides the Arrays.sort() method for primitive arrays and object arrays, using a highly optimised dual-pivot Quicksort for primitives and TimSort for objects. Both run in O(n log n) average time.
Code
import java.util.Arrays;
int[] arr = {5, 2, 8, 1, 9, 3};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
// [1, 2, 3, 5, 8, 9]
Arrays.sort() sorts in ascending order by default. For descending order with an Integer array (not int[]), use Arrays.sort(arr, Collections.reverseOrder()). For sorting a portion of an array, use Arrays.sort(arr, fromIndex, toIndex). Be ready to explain merge sort or quicksort from scratch if the interviewer asks you to sort without using the library method, as this tests algorithm knowledge rather than API knowledge.
Q16. How do you find the sum of all elements in an array?
Answer: Array summation is straightforward with a for-each loop and a running total. Java streams offer a one-line alternative using IntStream.of(arr).sum().
Traditional loop
int[] arr = {1, 2, 3, 4, 5};
int sum = 0;
for (int num : arr) {
sum += num;
}
System.out.println("Sum: " + sum); // 15
Streams approach (Java 8+)
int sum = IntStream.of(arr).sum();
System.out.println("Sum: " + sum); // 15
The traditional loop is clear and explicit. The streams approach demonstrates Java 8 knowledge which interviewers increasingly expect. IntStream.of() creates a stream from the primitive array and sum() is a terminal operation that reduces all elements to a single total. Both have O(n) time complexity.
Q17. How do you sort a HashMap by its values in Java?
Answer: HashMap does not maintain sorted order. To sort by values, the standard approach converts the entry set to a list and sorts using a comparator that compares entry values.
Code
HashMap<String, Integer> map = new HashMap<>();
map.put("banana", 3);
map.put("apple", 1);
map.put("mango", 2);
List<Map.Entry<String, Integer>> list = new ArrayList<>(map.entrySet());
list.sort((a, b) -> a.getValue() - b.getValue());
for (Map.Entry<String, Integer> entry : list) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
// apple = 1, mango = 2, banana = 3
entrySet() returns all key-value pairs as a Set of Map.Entry objects. Wrapping it in an ArrayList makes it sortable. The lambda comparator subtracts values to produce ascending order. For descending order, reverse the subtraction: b.getValue() – a.getValue(). If values are strings, use compareTo() instead. This pattern demonstrates knowledge of lambda expressions, generics, and collection manipulation together.
Q18. How do you remove duplicate words from a string?
Answer: LinkedHashSet is again the tool of choice: split the string into words, add them to a LinkedHashSet to remove duplicates while preserving order, then join them back.
Code
String str = "java python java sql python java";
String[] words = str.split(" ");
LinkedHashSet<String> set = new LinkedHashSet<>();
for (String w : words) {
set.add(w);
}
String result = String.join(" ", set);
System.out.println(result); // java python sql
split(” “) divides the string on spaces into an array of words. Each word is added to the LinkedHashSet, which silently ignores duplicates. String.join() reassembles the unique words with a space separator. The result preserves the first occurrence order of each word. This is one of the most elegant demonstrations of LinkedHashSet in Java.
OOP, Recursion, and Modern Java Coding Questions (Q19 to Q26)

These questions test deeper Java knowledge. OOP coding questions are more common in mid-level interviews. Modern Java features including lambdas, streams, and records appear at all levels now.
Q19. How do you demonstrate inheritance in Java?
Answer: Inheritance allows a child class to acquire the properties and methods of a parent class using the extends keyword. The child can use parent methods directly, override them to change behaviour, and add its own new methods.
Code
class Animal {
String name;
Animal(String name) { this.name = name; }
void sound() { System.out.println("Some sound"); }
}
class Dog extends Animal {
Dog(String name) { super(name); }
@Override
void sound() { System.out.println(name + " says: Woof"); }
}
Dog d = new Dog("Rex");
d.sound(); // Rex says: Woof
The super(name) call in the Dog constructor invokes the Animal constructor to initialise the inherited name field. The @Override annotation tells the compiler that sound() is intentionally replacing the parent implementation. If the annotation is present but the method signature does not match a parent method, the compiler flags an error, preventing accidental method name typos.
Q20. How do you demonstrate method overloading and overriding in Java?
Answer: Overloading and overriding are both forms of polymorphism but they work very differently. Overloading happens at compile time (static polymorphism). Overriding happens at runtime (dynamic polymorphism).
Overloading (same class, different parameter list)
class Calculator {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
int add(int a, int b, int c) { return a + b + c; }
}
Overriding (child class changes parent method behaviour)
class Shape {
void draw() { System.out.println("Drawing shape"); }
}
class Circle extends Shape {
@Override
void draw() { System.out.println("Drawing circle"); }
}
Shape s = new Circle();
s.draw(); // Drawing circle
Overloading requires methods with the same name but different number or types of parameters. The return type alone cannot distinguish overloaded methods. Overriding requires the same method name, same parameter list, and same or covariant return type. The example of Shape s = new Circle() calling the Circle draw() method demonstrates runtime polymorphism: the reference type is Shape but the actual object type is Circle, so the JVM dispatches to Circle’s implementation at runtime.
Q21. How do you create and use a functional interface with a lambda expression in Java?
Answer: A functional interface has exactly one abstract method. Lambda expressions provide a concise way to implement functional interfaces without creating an anonymous class. The @FunctionalInterface annotation enforces the single-method contract at compile time.
Code
@FunctionalInterface
interface Greeting {
void greet(String name);
}
// Lambda implements the abstract greet method
Greeting g = name -> System.out.println("Hello, " + name + "!");
g.greet("Alice"); // Hello, Alice!
Built-in functional interfaces from Java 8
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // true
Function<String, Integer> strLen = s -> s.length();
System.out.println(strLen.apply("Java")); // 4
Built-in functional interfaces in java.util.function include Predicate<T> for boolean tests, Function<T,R> for transforming T to R, Consumer<T> for operations that consume a value without returning, and Supplier<T> for producing values. Lambdas are the standard way to use these in stream pipelines, making functional interfaces central to modern Java development.
Q22. How do you use the Stream API to filter and transform a list in Java?
Answer: Java Streams provide a functional pipeline for processing collections. The pipeline consists of a source, zero or more intermediate operations (lazy), and one terminal operation that triggers execution.
Code
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Filter even numbers, square them, collect to list
List<Integer> result = numbers.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.collect(Collectors.toList());
System.out.println(result); // [4, 16, 36, 64, 100]
stream() creates a stream from the list. filter() is an intermediate operation that keeps only elements matching the predicate. map() transforms each remaining element. Both filter and map are lazy: they do not execute until a terminal operation is reached. collect(Collectors.toList()) is the terminal operation that triggers the pipeline and collects results. Other useful terminal operations include count(), sum(), findFirst(), anyMatch(), and forEach().
Q23. How do you reverse a linked list in Java?
Answer: Reversing a linked list is done iteratively by maintaining three pointers: previous, current, and next. In each iteration, the current node’s next pointer is redirected to point at the previous node, reversing the direction of the link.
Node class definition
class Node {
int data;
Node next;
Node(int data) { this.data = data; }
}
Reversal logic
static Node reverse(Node head) {
Node prev = null;
Node curr = head;
while (curr != null) {
Node next = curr.next; // save next
curr.next = prev; // reverse link
prev = curr; // advance prev
curr = next; // advance curr
}
return prev; // new head
}
Starting with prev=null and curr=head: save curr.next before overwriting it, set curr.next to prev to reverse the pointer, then advance prev to curr and curr to the saved next. When the loop ends, curr is null and prev points to the original tail which is now the new head. This runs in O(n) time and O(1) space.
Q24. How do you implement binary search in Java?
Answer: Binary search finds a target value in a sorted array by repeatedly halving the search space. It compares the target to the middle element and discards the half that cannot contain the target, achieving O(log n) time.
Iterative binary search
static int binarySearch(int[] arr, int target) {
int low = 0, high = arr.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) low = mid + 1;
else high = mid - 1;
}
return -1; // not found
}
The mid calculation uses low + (high – low) / 2 rather than (low + high) / 2 to prevent integer overflow when low and high are both large. If the middle element equals the target, return its index. If the target is larger, search the right half by setting low = mid + 1. If smaller, search the left half by setting high = mid – 1. Return -1 if the loop exits without finding the target. The array must be sorted for binary search to work correctly.
Q25. How do you create a record in Java?
Answer: Records are a concise way to create immutable data classes introduced in Java 16 as a standard feature. They automatically generate the constructor, getters (named after the fields), equals(), hashCode(), and toString() methods.
Code
record Person(String name, int age) {}
Person p = new Person("Alice", 30);
System.out.println(p.name()); // Alice
System.out.println(p.age()); // 30
System.out.println(p); // Person[name=Alice, age=30]
The single line record Person(String name, int age) replaces a full class with fields, constructor, getters, equals, hashCode, and toString. Records are implicitly final and their fields are implicitly private and final, making them naturally immutable. They are ideal for data transfer objects, configuration holders, and return types from methods that need to return multiple values. Custom compact constructors can add validation.
Q26. How do you use switch expressions in Java 14+?
Answer: Modern switch expressions (finalised in Java 14) eliminate the fall-through risk of classic switch statements, support multiple labels per case, and can return a value directly.
Classic switch statement (pre-Java 14, error-prone)
int day = 3;
String type;
switch (day) {
case 1: case 7: type = "Weekend"; break;
default: type = "Weekday"; break;
}
Switch expression (Java 14+, preferred)
int day = 3;
String type = switch (day) {
case 1, 7 -> "Weekend";
default -> "Weekday";
};
System.out.println(type); // Weekday
The arrow syntax eliminates fall-through entirely: each case handles only its branch and no break statement is needed. Multiple values can be matched in a single case with commas: case 1, 7. The switch expression produces a value directly, which can be assigned or returned. The yield keyword provides a value from a block case when multiple statements are needed inside a branch.
Exception Handling and Advanced Pattern Questions (Q27 to Q30)
Exception handling and try-catch patterns appear at all levels. Understanding the difference between checked and unchecked exceptions, and how to design null-safe code, demonstrates production maturity.
Q27. How do you handle exceptions with try-catch-finally in Java?
Answer: Java’s exception handling mechanism separates normal code flow from error handling. The try block contains code that might throw. The catch block handles the exception. The finally block always executes regardless of whether an exception occurred, making it ideal for resource cleanup.
Code
try {
int[] arr = {1, 2, 3};
System.out.println(arr[5]); // throws ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Index out of bounds: " + e.getMessage());
} finally {
System.out.println("Finally always runs");
}
The try block is entered and arr[5] throws ArrayIndexOutOfBoundsException because the array only has indices 0 to 2. The catch block catches this specific exception and prints the message. The finally block runs regardless, even if the catch block rethrows the exception or returns early. Multiple catch blocks can handle different exception types. The most specific exception type should come first. A single catch block can handle multiple types using the pipe operator: catch (IOException | SQLException e).
Q28. How do you prove that a String is immutable in Java?
Answer: String immutability is a fundamental Java concept. When a String is created, its value cannot be changed. Any method that appears to modify a String actually returns a new String object while the original remains unchanged.
Code
String s1 = "Hello";
String s2 = s1;
s1 = s1.concat(" World");
System.out.println(s1); // Hello World
System.out.println(s2); // Hello
When s2 is assigned s1, both variables point to the same “Hello” object in the String pool. When concat() is called, it does not modify the original “Hello” object. It creates a brand new String “Hello World” and assigns it to s1. The variable s2 still points to the original “Hello” because the object it references was never changed. This proves immutability: the original String object is untouched. This design is intentional: immutability makes Strings thread-safe, eligible for String pool interning, and safe to use as HashMap keys.
Q29. How do you swap two numbers without using a third variable in Java?
Answer: Swapping without a temporary variable can be done using arithmetic (addition and subtraction) or using XOR bitwise operations. The arithmetic approach is more readable.
Arithmetic approach
int a = 5, b = 10;
a = a + b; // a = 15
b = a - b; // b = 15 - 10 = 5
a = a - b; // a = 15 - 5 = 10
System.out.println("a=" + a + ", b=" + b); // a=10, b=5
XOR approach
a = a ^ b;
b = a ^ b;
a = a ^ b;
The arithmetic approach stores the sum in a, then recovers the original a by subtracting the original b from the sum, and recovers the original b similarly. The XOR approach exploits the property that x XOR x equals 0 and x XOR 0 equals x. Both approaches fail for very large numbers where integer overflow is possible, which is worth mentioning to show awareness of edge cases.
Q30. How do you find the first non-repeating character in a string in Java?
Answer: This is a two-pass HashMap problem. The first pass builds a frequency map. The second pass iterates the string in order to find the first character with a count of exactly one.
Code
String str = "programming";
LinkedHashMap<Character, Integer> map = new LinkedHashMap<>();
// First pass: count frequencies
for (char c : str.toCharArray()) {
map.put(c, map.getOrDefault(c, 0) + 1);
}
// Second pass: find first with count 1
for (Map.Entry<Character, Integer> entry : map.entrySet()) {
if (entry.getValue() == 1) {
System.out.println("First non-repeating: " + entry.getKey());
break;
}
}
// First non-repeating: p
LinkedHashMap is used instead of HashMap to preserve insertion order, which matches the order characters first appear in the string. The second pass iterates the map entries in insertion order and stops at the first entry with value 1. For “programming”: p appears 1 time, r appears 2 times, o appears 1 time but p comes first in the string, so p is the answer. This is O(n) time and O(k) space where k is the distinct character count.
How to Prepare for Java Coding Interview Questions
Must-Practice Problem Categories in Order
- Number manipulation: even/odd, reverse, palindrome, Armstrong, prime, factorial, Fibonacci
- String operations: reverse, palindrome, anagram, character frequency, first non-repeating
- Array problems: sort, search, find duplicates, second-largest, sum
- HashMap patterns: frequency counting, sorting by value, grouping
- LinkedHashSet patterns: deduplication with order preservation
- OOP code: inheritance, overloading vs overriding, interface and abstract class
- Recursion: factorial, Fibonacci, binary search (recursive version)
- Linked list: reversal, cycle detection
- Java 8+ features: lambda, stream filter/map/collect, functional interfaces
- Modern Java: records, switch expressions, text blocks
Best Practice Resources
- DigitalOcean Java Coding Interview Guide: Comprehensive coverage of 50 real Java coding questions with working solutions and explanations.
- Greens Technologies Java Programs: Practical Java program examples covering all classic patterns tested in Indian tech company interviews.
- LeetCode (Java filter): The standard platform for practicing algorithmic problems with a large library of Java-tagged problems.
- GeeksforGeeks Java Programming Examples: Topic-wise Java coding examples organised from basic through advanced with explanations.
- Effective Java by Joshua Bloch: The authoritative book on Java best practices that senior-level interviews expect you to understand.
Interview Day Tips
- Always state the approach and time complexity before writing a single line of code
- Trace through your code with a small example on paper before claiming it is correct
- Mention edge cases before the interviewer asks: empty input, null values, negative numbers, duplicates
- When using HashMap or LinkedHashSet, explain why you chose that structure over an array or list
- Know the difference between equals() and == for String comparison cold as this trips up many candidates
- Be ready to optimise: if your first solution is O(n squared), ask if the interviewer wants a better approach
Frequently Asked Questions (FAQ)
What Java coding problems are most commonly asked in interviews?
The most consistently asked coding problems across all Java interview levels are: reverse a string, check palindrome (both string and number), print Fibonacci series, find factorial, check prime number, find the second-largest element in an array, find frequency of characters using HashMap, sort a HashMap by value, find duplicate elements, and reverse a linked list. These twelve problems cover the vast majority of what freshers and mid-level candidates face.
Do I need to know Java 8 features for coding interviews?
Yes, Java 8 features are now expected at all levels. Lambda expressions, stream operations (filter, map, collect), functional interfaces (Predicate, Function, Consumer), and the Optional class appear regularly in coding rounds. Senior-level interviews also test method references, Collectors, and parallel streams. For modern roles, knowledge of Java 14 to Java 21 features like records, switch expressions, text blocks, pattern matching, and sealed classes is increasingly valuable.
Should I memorise all these programs?
Do not memorise programs. Understand the patterns. The digit-manipulation pattern (modulo to extract, multiplication to build, division to remove) is the one algorithm behind reverse, palindrome, Armstrong, digit sum, digit count, and digit product. The HashMap frequency pattern is the algorithm behind character count, word count, first non-repeating character, and duplicate detection. Understanding six to eight core patterns gives you the tools to solve dozens of variations you have never seen before.
How important is time complexity in Java coding interviews?
Very important. For every solution you write, state the time and space complexity without being asked. The difference between O(n squared) and O(n) using a HashSet for duplicate detection is exactly the kind of optimisation interviewers are watching for. Candidates who proactively discuss complexity demonstrate algorithmic maturity. Those who wait to be asked suggest they only consider correctness, not scalability.
How long should I spend preparing Java coding questions?
With two to three hours of active daily coding practice (not reading but actually writing and running code), most candidates feel confident for junior Java coding interviews within four to six weeks. For mid-level roles requiring OOP design, collections, and Java 8 streams, plan for eight to ten weeks. For senior roles at product companies adding system design and advanced algorithmic thinking, allow three to four months. Practice by writing code by hand on paper, not only in an IDE, because many coding rounds are whiteboard-based.
Conclusion
This guide has covered 30 carefully selected Java coding interview questions across the complete spectrum: number manipulation, string operations, array and collection problems, OOP demonstrations, recursion, linked list reversal, binary search, modern Java features including lambdas, streams, records, and switch expressions, and exception handling. The approach, logic, and edge cases are explained for every question, not just the code.
Java coding interviews reward developers who think before they type, communicate their reasoning clearly, and understand why their solution works rather than just that it works. The digit-manipulation pattern, the HashMap frequency pattern, and the LinkedHashSet deduplication pattern appear across dozens of different question framings. Master those patterns and you have mastered the category.