Skip to content
spot_the_ai_bug

Java debugging interview questions

Java code-review questions reward knowing the difference between references and values, and who is responsible for closing what. Each snippet below is short, compiles cleanly and contains exactly one real bug that would ship to production.

Java gotchas interviewers love

  • == compares references; use equals() for Strings and boxed numbers.
  • Optional.get() throws on empty; prefer map/orElse.
  • Use try-with-resources for connections, statements and streams.
  • Valid indexes are 0..length - 1.
  • String += in a loop is quadratic; use StringBuilder.

5 Java spot-the-bug questions

Each snippet has exactly one bug. Find the line before you open the answer.

Summing an array

total() adds up a cart's line items. Why does it throw on every call?

public static long total(long[] lineItemsCents) {    long sum = 0;    for (int i = 0; i <= lineItemsCents.length; i++) {        sum += lineItemsCents[i];    }    return sum;}
Show answer

line 3 · Off-by-one

Valid indexes run from 0 to length - 1. With <= the loop reads index length on its last pass and throws ArrayIndexOutOfBoundsException.

Fix
    for (int i = 0; i < lineItemsCents.length; i++) {

Interview follow-up: An enhanced for loop (for (long c : lineItemsCents)) removes the index, and the bug, entirely.

Calling Optional.get()

greetingFor() builds the email greeting for the password-reset flow. What happens for an email that isn't registered?

public String greetingFor(String email) {    Optional<User> user = userRepository.findByEmail(email);    return "Hi " + user.get().getFirstName() + ",";}
Show answer

line 3 · Null / undefined handling

findByEmail returns Optional.empty() for unknown emails, and get() on an empty Optional throws NoSuchElementException. The reset endpoint returns a 500, which also tells attackers which emails exist.

Fix
    return userRepository.findByEmail(email)            .map(u -> "Hi " + u.getFirstName() + ",")            .orElse("Hi there,");

Interview follow-up: Optional exists to force you to handle absence; get() without isPresent() defeats the point.

JDBC connection never closed

emailExists() is called on every signup. After some traffic, all requests hang waiting for a database connection. Why?

public boolean emailExists(String email) throws SQLException {    Connection conn = dataSource.getConnection();    PreparedStatement ps = conn.prepareStatement("SELECT 1 FROM users WHERE email = ?");    ps.setString(1, email);    ResultSet rs = ps.executeQuery();    return rs.next();}
Show answer

line 2 · Resource leak

The connection, statement and result set are never closed, so every call keeps a pooled connection checked out. Once the pool is exhausted, new requests block until they time out.

Fix
    try (Connection conn = dataSource.getConnection();         PreparedStatement ps = conn.prepareStatement("SELECT 1 FROM users WHERE email = ?")) {        ps.setString(1, email);        try (ResultSet rs = ps.executeQuery()) {            return rs.next();        }    }

Interview follow-up: Explain why try-with-resources beats a finally block: it closes in reverse order and keeps suppressed exceptions.

Comparing strings with ==

isAdmin() gates the admin dashboard. Why are real admins being locked out?

public boolean isAdmin(HttpServletRequest request) {    String role = request.getHeader("X-Role");    return role == "admin";}
Show answer

line 3 · Wrong API usage

== compares object references, not contents. The header value is a new String built at runtime, so it is never the same object as the "admin" literal and the check is always false.

Fix
    return "admin".equals(role);

Interview follow-up: Putting the literal first also avoids a NullPointerException when the header is missing. (And never trust a client-supplied role header for authorization in real code.)

Building a CSV with +=

toCsv() exports 200k rows. It takes minutes and churns the garbage collector. Why?

public static String toCsv(List<String[]> rows) {    String csv = "";    for (String[] row : rows) {        csv += String.join(",", row) + "\n";    }    return csv;}
Show answer

line 4 · Performance trap

Strings are immutable, so each += copies everything built so far into a new string. Over n rows that is O(n²) copying and a huge amount of garbage.

Fix
    StringBuilder csv = new StringBuilder();    for (String[] row : rows) {        csv.append(String.join(",", row)).append('\n');    }    return csv.toString();

Interview follow-up: Mention that the compiler's StringBuilder optimization applies within a single expression, not across loop iterations.

Every day, everyone gets the same pull request written by AI. It looks clean. It has comments. It has exactly one real bug.

  1. 1

    Find the line

    Tap the buggy line, then hit Submit. You get 3 attempts.

  2. 2

    Read the hints

    A miss within 2 lines is 🔥 Warm. Anything further is ❄️ Cold.

  3. 3

    Name the bug

    Found it? Bonus round: pick the bug type from 4 options. It doesn't affect your win, just your bragging rights.

// your share card

found in 3/3

🟥 cold miss · 🟨 warm miss · 🟩 found · ⬛ unused

Keyboard: ↑ ↓ to move between lines, Enter to submit. A new bug drops every day at midnight IST.

0
Played
0
Win %
0
Streak
0
Max

Attempts distribution