Java Module 3
Control flow, methods and recursion interview questions
Interview questions on control flow, methods and recursion: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
Why does if (stock = 5) not compile in Java, while if (paid = true) does?
-
Fresher
What is the difference between a switch statement and a switch expression in Java?
Answered in the lesson switch statements and switch expressions
-
Fresher
What can't the enhanced for loop do that a classic for loop can?
Answered in the lesson Loops: while, do-while, for and for-each
-
Fresher
What is the difference between break and continue in a Java loop?
-
Fresher
Is Java pass-by-value or pass-by-reference?
Answered in the lesson Methods, parameters, return and overloading
-
Fresher
What is a base case in recursion, and what happens if a recursive method has none?
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Fresher to mid
A courier charges by weight band: up to 500 g, up to 2 kg, up to 5 kg, up to 10 kg, and above 10 kg. A parcel of exactly 2 kg was charged the 5 kg rate. How do you find the bug, fix the else-if chain, and choose test values so that no boundary slips through again?
- What it tests
- Reading an else-if chain at its edges, choosing between < and <=, and designing boundary tests for bands.
- First step
- Write the bands as ranges with explicit edges, then run the chain by hand at 2,000 g: a test written as grams < 2000 sends exactly 2,000 g on to the next band. Fix the comparison, then list the values every edge needs: the edge itself and the value just past it.
- Follow-ups
-
- How many test values do five bands need, and which ones?
- When would you replace the chain with a lookup table?
- The weight arrives as a double in kilograms. What changes?
From the lesson if, else and boolean logic
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A permission check reads if (!(!isAdmin && (!isOwner || isLocked))). Rewrite it so that a teammate can read it at a glance, prove that the rewrite means the same, and say what could still change behaviour if the three operands were method calls instead of variables.
- What it tests
- De Morgan's laws, double negation, exhaustive truth-table checks, and short-circuit order when operands have side effects.
- First step
- Remove the outer negation with De Morgan's law: !(!A && (!B || C)) becomes A || !(!B || C), which becomes A || (B && !C). Read it back as a rule, "admins, or owners of a document that is not locked", then compare all 8 combinations of the three inputs with the original.
- Follow-ups
-
- How many cases does an exhaustive check need for 3 inputs, and for 6?
- What changes if isLocked() queries a database and isOwner() writes an audit line?
- Would you move the condition into a method of its own, and what would you call it?
From the lesson if, else and boolean logic
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
An enum DeliveryMode is switched on in about 30 places across a service and two client libraries. Product adds a new constant, SAME_DAY. How do you make sure that every switch handles it, and what happens in a library that was compiled against the old enum and not rebuilt?
- What it tests
- Exhaustive switch expressions, why default hides new constants, statements against expressions, and what separately compiled code does at run time.
- First step
- Let the compiler find the switches. A switch expression over the enum with no default stops compiling when SAME_DAY appears, while a switch statement, or any switch with a default, compiles silently. So convert the statements to expressions, drop defaults that exist only "to be safe", rebuild everything and fix each error.
- Follow-ups
-
- What exactly happens at run time in the library that was not recompiled?
- When is a default label in a switch over an enum the right choice?
- How do you catch a missed case in a switch you cannot turn into an expression?
From the lesson switch statements and switch expressions
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid
A pricing method is a 60-case switch on a product code string, and the business now wants to change prices every week without a release. Would you keep the switch, use an enum with a price field, or load a map from configuration? Justify the choice, including what happens with unknown and null codes.
- What it tests
- Separating data from code, compile-time checks against run-time flexibility, unknown and null keys, and how javac compiles a switch on strings.
- First step
- Separate what changes weekly from what changes with a release. The prices are data that change without a release, and a switch is compiled into the class, so the prices belong in a map loaded from configuration and checked at start-up. The codes and the rules around them stay in code.
- Follow-ups
-
- How does javac compile a switch on strings, and does that matter for 60 cases?
- What should the method do for a code that is not in the map, or for null?
- When is an enum with a price field the better design?
From the lesson switch statements and switch expressions
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
for (double x = 0.0; x != 1.0; x += 0.1) { … } was meant to run 10 times, and it never ends. Explain why, fix it, and say how you would notice and locate a loop like this in a running service.
- What it tests
- Floating-point accumulation, loop termination conditions, integer counters, and finding a spinning thread from outside the process.
- First step
- 0.1 has no exact binary value, so ten additions give 0.9999999999999999, not 1.0, and x != 1.0 stays true for ever. Count with an int instead, for (int i = 0; i < 10; i++), and compute x = i / 10.0 inside the loop.
- Follow-ups
-
- Is x < 1.0 a correct fix? How many times does it run?
- Why does the same loop with a float counter behave differently?
- How do you confirm from outside the process that a thread is stuck in this loop?
From the lesson Loops: while, do-while, for and for-each
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A report prints records in pages of 20. With 41 records the last record never appears, and with 40 records an empty last page appears. Write the page count and the loop bounds correctly, and choose the totals you would test.
- What it tests
- Ceiling division, half-open ranges, off-by-one errors at both ends of a loop, and choosing boundary test values.
- First step
- Count pages with ceiling division, (total + size - 1) / size, which gives 3 for 41 records and 2 for 40. Page p, counted from 0, covers the half-open range from p * size up to but not including Math.min(total, (p + 1) * size), so the loop test is i < end, never i <= end.
- Follow-ups
-
- Which totals would you test, and why those?
- What should happen with 0 records?
- How do the bounds change when the address of a page counts from 1?
From the lesson Loops: while, do-while, for and for-each
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
After a deploy, one worker thread of a service sits at 100 % of a CPU core and its queue stops draining. You suspect a loop that never ends. How do you confirm it, find the line, stop the damage and prevent this kind of bug?
- What it tests
- Thread dumps with jcmd or jstack, reading repeated samples, loop progress arguments, and tests with time limits.
- First step
- Take two or three thread dumps a few seconds apart with jcmd <pid> Thread.print and find the worker. If it is RUNNABLE in every dump, with the same top frame and a cpu= value that keeps climbing, it is spinning, and the line number in that frame points at the loop.
- Follow-ups
-
- The loop is a while loop with a continue near the top. What is the likely bug?
- How would a test have caught it before the deploy?
- What do you do in production while the fix is prepared?
From the lesson break, continue and labelled loops
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
Reading a colleague's change, you find a method that searches a stadium plan (levels × rows × seats) for the first block of k adjacent empty seats, using three nested loops, two boolean flags and a labelled break. How would you restructure it, and what does the search cost in the worst case?
- What it tests
- Replacing flags and labels with methods that return, splitting a search into named steps, and counting the work of nested loops.
- First step
- Name the pieces. One method returns where the first run of k empty seats starts in a single row, or -1. A second loops over levels and rows and returns the first hit. Each return replaces a flag and the labelled break, and the run check can be tested on its own.
- Follow-ups
-
- How many seat checks happen in the worst case for 3 levels of 40 rows of 60 seats, and can you avoid checking a seat twice?
- When would you keep a labelled break instead?
- How do you return three coordinates from one method?
From the lesson break, continue and labelled loops
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
After List<Integer> ids = new ArrayList<>(List.of(10, 20, 30, 1)); ids.remove(1); what does ids hold, and why? How would you remove the value 1, and what does this teach about designing overloads?
- What it tests
- The phases of overload resolution (widening before boxing), the two remove methods of List, and overload design that avoids surprises.
- First step
- Two overloads apply: remove(int index) and remove(Object o). The argument 1 is an int, and the first phase of overload resolution, which allows no boxing, already finds remove(int). So the element at index 1, the value 20, is removed, and ids holds [10, 30, 1].
- Follow-ups
-
- How do you remove the value 1?
- Does the same call behave the same way on a List<Long>?
- How would you name these two methods if you designed the API today?
From the lesson Methods, parameters, return and overloading
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior
A logging method void debug(String format, Object... args) is called about 10 million times a minute, almost always with debug logging switched off, and a profiler shows a lot of garbage coming from those calls. Where does the garbage come from, and how would you remove it without changing the callers?
- What it tests
- What a varargs call allocates, boxing of primitive arguments, fixed-arity overloads, and when the JIT can or cannot remove the allocation.
- First step
- Each call builds a new Object[] for args before debug runs, and boxes every int or long argument into a wrapper object, all before the method can even check whether debug logging is on. Count it: two arguments mean one array and up to two boxes per call.
- Follow-ups
-
- Which overload does debug("x={}", a) pick once fixed-arity overloads exist, and why does that help?
- Can the JIT remove the allocation by itself?
- What can callers do if the library cannot be changed?
From the lesson Methods, parameters, return and overloading
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A recursive method walks the nested folders of an uploaded archive. It passes every test, but one customer's upload is nested 50,000 levels deep and the method throws StackOverflowError. What are your options, what does each one cost, and which would you ship?
- What it tests
- How stack depth grows with the input, stack size settings, an explicit stack, depth limits as input validation, and why catching the error is unsafe.
- First step
- Estimate first. On JDK 25 a trivial interpreted frame took about 112 bytes, and a real method's frame is larger, so 50,000 levels need several megabytes, more than the default 2 MiB thread stack on macOS on Apple silicon. Then ask whether such depth is a real use or an attack on the service.
- Follow-ups
-
- Why is catching StackOverflowError and carrying on not acceptable?
- What does a version with an explicit stack look like, and where does its memory go?
- How deep would you allow, and what does the user see beyond that?
From the lesson Recursion and the call stack
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A plain recursive fib(40) takes about a fifth of a second on a laptop. Estimate how long fib(50) takes, explain why, and compare memoisation, a bottom-up table and a loop that keeps only two values. What changes once n passes 92?
- What it tests
- Exponential growth of calls, memoisation against tabulation, time and space of each version, and long overflow after fib(92).
- First step
- Count calls, not seconds. The plain version makes 2 × fib(n + 1) − 1 calls, 331,160,281 for n = 40, and each step of n multiplies that by about 1.618. Ten more steps multiply it by about 123, so fib(50) takes around half a minute.
- Follow-ups
-
- How many calls does the memoised version make, and how deep does it go?
- Write the loop that keeps two values. Why is it faster than memoisation in practice?
- How would you compute fib(1000) exactly?
From the lesson Recursion and the call stack
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes