Integer a = 127, b = 127;
Integer c = 128, d = 128;
System.out.println((a == b) + " " + (c == d));
Answer: true false
Integer caches boxed values from -128 to 127, so `a` and `b` are the same object and `==` is true. Above that range autoboxing creates new objects, so reference comparison fails. Always compare boxed types with `equals`.
2. This class breaks when used in a HashSet — duplicates appear. Which line is the cause?
Advanced
java
1 class User {
2 final String email;
3 User(String e) { this.email = e; }
4 @Override public boolean equals(Object o) {
5 return o instanceof User u && u.email.equals(email);
6 }
7 }
Answer: The class overrides equals but not hashCode
HashSet finds the bucket by hashCode first and only then calls equals. Two equal Users inherit different identity hash codes, land in different buckets, and are never compared — so both are stored. The contract is absolute: if you override equals you must override hashCode.
String a = "hi";
String b = "hi";
String c = new String("hi");
System.out.println((a == b) + " " + (a == c) + " " + a.equals(c));
Answer: true false true
String literals are interned, so `a` and `b` reference the same pooled object. `new String(...)` forces a distinct object, so `==` fails while `equals` compares contents and succeeds. Calling `c.intern()` would return the pooled instance.
List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
list.remove(1);
System.out.println(list);
Answer: [1, 3]
`remove(int)` removes by index and `remove(Object)` removes by value — the int overload wins here, so index 1 (the value 2) is dropped. To remove the *value* 1 you must box it: `list.remove(Integer.valueOf(1))`. A genuinely nasty overload trap.
5. This throws ConcurrentModificationException. Which line is responsible?
Advanced
java
1 List<String> items = new ArrayList<>(List.of("a", "b", "c"));
2 for (String s : items) {
3 if (s.equals("b")) {
4 items.remove(s);
5 }
6 }
Answer: Line 4 — structurally modifying the list during iteration invalidates the iterator
The iterator tracks a modification count and fails fast when the list changes underneath it. Use `Iterator.remove()`, or `items.removeIf(s -> s.equals("b"))`, which handles the bookkeeping correctly.
Doubles are binary and cannot hold 0.1 exactly. BigDecimal built from *strings* is exact — passing a double to its constructor would inherit the same error. Note also that `equals` on BigDecimal compares scale, so 0.30 does not equal 0.3; use `compareTo`.
7. Fill in the blank so the field's writes are visible to other threads immediately.
Advanced
java
private ____ boolean running = true;
public void stop() { running = false; }
public void run() { while (running) { work(); } }
Answer: volatile
Without `volatile` the JIT may cache `running` in a register, so the loop never observes the write from another thread and spins forever. `volatile` guarantees visibility and prevents reordering — but not atomicity, so it is not enough for compound operations like `i++`.
Map<String, Integer> m = new HashMap<>();
m.put("a", 1);
System.out.println(m.get("b") + " " + m.getOrDefault("b", 0));
Answer: null 0
A missing key returns null, and printing null is fine. The danger is assigning it to a primitive — `int x = m.get("b")` unboxes null and throws NullPointerException. `getOrDefault` avoids the whole problem.
`List.of` returns an immutable list, so mutating it throws at runtime rather than compile time — the type is still `List`. `Arrays.asList` is a different trap: it is fixed-size, so `set` works but `add` throws.
A stream can be traversed once. After a terminal operation it is closed, and reusing it throws IllegalStateException. Create a new stream from the source each time, or collect to a List if you need the results more than once.
11. What is the complexity of building a string this way for n iterations?
Advanced
java
String s = "";
for (int i = 0; i < n; i++) {
s += i;
}
Answer: O(n²) — each concatenation copies the whole string
Strings are immutable, so each `+=` allocates a new StringBuilder, copies everything, and discards it. The compiler optimises a single concatenation expression but cannot hoist the builder out of a loop. Use a StringBuilder explicitly for O(n).
12. Two threads calling increment() concurrently lose updates. Which line explains it?
Advanced
java
1 class Counter {
2 private volatile int count = 0;
3 public void increment() {
4 count++;
5 }
6 }
Answer: Line 4 — count++ is read-modify-write, and volatile gives visibility but not atomicity
`count++` is three operations, and two threads can interleave between the read and the write. `volatile` only guarantees each read sees the latest value. Use `AtomicInteger.incrementAndGet()`, or synchronize the method.
List<String> l = new ArrayList<>(List.of("b", "a", "c"));
Collections.sort(l);
System.out.println(l + " " + l.getClass().getSimpleName());
Answer: [a, b, c] ArrayList
Wrapping in `new ArrayList<>(...)` produces a mutable copy, so sorting in place works. Sorting the `List.of` result directly would throw UnsupportedOperationException — the defensive-copy step is what makes this safe.
Optional<String> o = Optional.ofNullable(null);
System.out.println(o.isPresent() + " " + o.orElse("fallback"));
Answer: false fallback
`ofNullable` accepts null and yields an empty Optional, whereas `Optional.of(null)` throws immediately. Prefer `map`/`orElse` chains over `isPresent()` followed by `get()` — the latter reintroduces exactly the null check Optional was meant to remove.
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
System.out.println(a.equals(b) + " " + Arrays.equals(a, b));
Answer: false true
Arrays do not override equals, so they fall back to Object's reference comparison. `Arrays.equals` compares contents, and `Arrays.deepEquals` handles nested arrays. The same applies to `toString` — printing an array directly gives a type tag and hash code.
Streams preserve encounter order for ordered sources, so filtering and mapping keep the original sequence. `Collectors.joining` builds the delimited string. Intermediate operations are lazy — nothing runs until the terminal `collect`.
17. Declaring a field `final` makes the object it references immutable.
Advanced
java
final List<String> items = new ArrayList<>();
items.add("x");
Answer: False
`final` fixes the reference, not the object — the add succeeds, while `items = new ArrayList<>()` would not compile. For an immutable view use `List.copyOf(items)` or `Collections.unmodifiableList`, and remember those are shallow.
18. Fill in the blank so both resources are closed automatically, even on exception.
Advanced
java
try (____ BufferedReader r = new BufferedReader(new FileReader(f))) {
return r.readLine();
}
Answer: (nothing — try-with-resources needs no keyword)
Try-with-resources takes the declaration directly in the parentheses; any resource implementing AutoCloseable is closed in reverse order when the block exits. It also suppresses secondary exceptions properly, which a manual finally block usually gets wrong.
Map<String, List<String>> m = new HashMap<>();
m.computeIfAbsent("k", k -> new ArrayList<>()).add("v1");
m.computeIfAbsent("k", k -> new ArrayList<>()).add("v2");
System.out.println(m);
Answer: {k=[v1, v2]}
`computeIfAbsent` creates the list only on the first call and returns the existing one afterwards, so both values land in the same list. It replaces the classic get-check-put-add dance and is atomic on ConcurrentHashMap.
Answer: Lines 2-3 — two threads transferring in opposite directions acquire the locks in opposite order
`transfer(x, y)` and `transfer(y, x)` running concurrently each hold one lock and wait for the other — a classic deadlock. The fix is a consistent global lock ordering, for example by comparing account ids and always locking the lower one first.
class A { static String who() { return "A"; } }
class B extends A { static String who() { return "B"; } }
A ref = new B();
System.out.println(ref.who());
Answer: A
Static methods are hidden, not overridden — they are resolved at compile time from the declared type, which is `A`. Only instance methods are dispatched dynamically. This is why calling a static method through an instance reference is discouraged.
StringBuilder sb = new StringBuilder("ab");
modify(sb);
System.out.println(sb);
static void modify(StringBuilder s) {
s.append("c");
s = new StringBuilder("zz");
}
Answer: abc
Java passes references by value. Mutating the object through the parameter is visible to the caller; reassigning the parameter only rebinds the local copy of the reference. This is the cleanest demonstration that Java is not pass-by-reference.
`+` is left-associative. Once one operand is a String the result is a String, so the first line concatenates throughout. The second adds 5 + 3 numerically first and only then concatenates, giving "82".
24. This leaks a thread pool and the JVM never exits. Which line should change?
Advanced
java
1 ExecutorService ex = Executors.newFixedThreadPool(4);
2 for (Task t : tasks) {
3 ex.submit(t);
4 }
5 System.out.println("submitted");
Answer: Line 5 — the executor is never shut down, so its non-daemon threads keep the JVM alive
A fixed pool creates non-daemon threads that live until shut down. Call `ex.shutdown()` and then `awaitTermination`, ideally in a finally block — or use try-with-resources, since ExecutorService is AutoCloseable from Java 19.