10 Java Output Questions That Trip Up Experienced Developers
Integer caching, the String pool, finally blocks that override returns — ten short Java snippets where intuition gives the wrong answer, with the exact reason for each.
"What does this print?" questions look like trivia, but interviewers use them for a reason: each one tests whether you understand a real rule of the language — autoboxing, object identity, evaluation order, overload resolution. Get the rule right and the answer follows.
Try each one before reading the explanation.
1. The Integer cache
Integer a = 127, b = 127;
Integer c = 128, d = 128;
System.out.println(a == b);
System.out.println(c == d);
Output: true, then false.
Autoboxing compiles to Integer.valueOf(...), which returns cached objects for values from -128 to 127. So a and b point to the same object. 128 is outside the cache, so c and d are two different objects — and == on objects compares references.
Rule: compare wrapper values with equals() (or unbox), never ==. Byte, Short, Long and Character (0–127) cache too; Float and Double don't. The Integer cache's upper bound can be raised with -XX:AutoBoxCacheMax.
2. String literals vs new String()
String s1 = "hi";
String s2 = "hi";
String s3 = new String("hi");
System.out.println(s1 == s2);
System.out.println(s1 == s3);
Output: true, then false.
Identical string literals are interned in the String pool, so s1 and s2 are the same object. new String(...) always creates a new object. s1.equals(s3) is true; s1 == s3.intern() is also true.
3. A return in finally
static int test() {
try {
return 1;
} finally {
return 2;
}
}
Output: 2.
The try block's return value is prepared, then finally runs — and its return replaces it. Worse, a return in finally also swallows any exception thrown in the try block. javac -Xlint:finally warns about it. Use finally for cleanup only (or better, try-with-resources).
4. list.remove(1)
List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
list.remove(1);
System.out.println(list);
Output: [1, 3].
List has both remove(int index) and remove(Object o). Overload resolution first looks for a match without boxing, so the int argument picks remove(int index) and removes the element at index 1. To remove the value 1, write list.remove(Integer.valueOf(1)).
5. Adding two chars
System.out.println('a' + 'b');
System.out.println("" + 'a' + 'b');
Output: 195, then ab.
char is a numeric type: 'a' is 97 and 'b' is 98, so 'a' + 'b' is integer addition. Concatenation only starts once a String is involved — and + is evaluated left to right.
6. Mixed +
System.out.println(1 + 2 + "3" + 4 + 5);
Output: 3345.
Left to right: 1 + 2 is 3 (numeric), 3 + "3" is "33" (now a String), and every later + concatenates. "" + (1 + 2) + 3 + (4 + 5) would give "339".
7. i = i++
int i = 0;
i = i++;
System.out.println(i);
Output: 0.
i++ evaluates to the old value (0) and then increments i to 1 — but the assignment then writes the old value 0 back. Never assign a post-increment back to the same variable.
8. split() and trailing empty strings
System.out.println("a,b,,".split(",").length);
Output: 2.
String.split(regex) removes trailing empty strings. Use split(",", -1) to keep them (length 4) — essential for CSV parsing. Also remember the argument is a regex: split(".") splits on every character.
9. Long.equals(1)
Long id = 1L;
System.out.println(id.equals(1));
System.out.println(id == 1);
Output: false, then true.
1 autoboxes to an Integer, and Long.equals() returns false for anything that isn't a Long. id == 1 unboxes id and compares numbers. This bites real code as Map<Long, User>.get(1) returning null.
10. Math.abs() returning a negative number
int x = Integer.MIN_VALUE;
System.out.println(Math.abs(x) < 0);
Output: true.
int ranges from -2,147,483,648 to 2,147,483,647 — the minimum has no positive counterpart, so Math.abs(MIN_VALUE) overflows and returns itself. The classic production bug is Math.abs(hash) % buckets producing a negative index. Use Math.floorMod(hash, buckets), or Math.absExact(x) to fail loudly.
The rules behind all ten
| Trap | Underlying rule |
|---|---|
| 1, 2, 9 | == compares references for objects; wrappers and Strings need equals() |
| 1, 9 | Autoboxing uses valueOf() — caches, and type-specific equals() |
| 3 | finally always runs and can override the result |
| 4 | Overload resolution prefers matches without boxing |
| 5, 6, 7 | Evaluation order and numeric promotion |
| 8 | Library defaults (split drops trailing empties) |
| 10 | Fixed-width integer overflow |
Follow-up questions this topic invites — and their answers
Q: Why does Java cache Integer values at all? A: Small integers are used constantly (loop counters, collection sizes, keys). Reusing objects for -128..127 saves allocation and memory. The Java Language Specification requires caching at least that range for boxing conversions.
Q: Is == ever correct for objects?
A: Yes — when you really mean identity: enum constants, singletons, or checking whether two references point to the same instance. For values, use equals().
Q: What's the safest way to compare two possibly-null objects?
A: Objects.equals(a, b) — it handles nulls and delegates to equals().
Q: How do I practise these? A: Read the code, state the rule, then predict. Our Java Interview Prep courses have hundreds of questions like these, grouped by experience level.
Related Posts
Java Garbage Collection Explained: G1, ZGC and How to Choose
How the JVM finds garbage, why generations matter, what G1 and ZGC actually do, and a practical way to pick and tune a collector for your service.
Virtual Threads in Java 21: When They Help and When They Don't
Virtual threads make blocking code scale to hundreds of thousands of concurrent tasks — but only for I/O-bound work. How they work, how to use them in Spring Boot, and the pitfalls.
HashMap Internals: How put() and get() Really Work
Buckets, hash spreading, collisions, treeification and resizing — a step-by-step look inside java.util.HashMap, and why equals() and hashCode() must agree.
Java Concurrency: The Interview Questions That Trip People Up
volatile, synchronized, ReentrantLock, happens-before — these concepts trip up even experienced engineers. Here's a clear explanation of each.