What changed in Java 7
5 changes across 3 questions — each with the behaviour it replaced, because “and how did it work before?” is the follow-up.
What is the contract between hashCode() and equals()?
java.util.Objects arrives: Objects.hash(...) and Objects.equals(a, b) remove the null-checking boilerplate from both methods.
Before: Every equals() opened with a hand-rolled null and type check, and every hashCode() was a hand-written 31 * result + field loop. Both were copy-pasted, and both were where the bugs lived.
Why is String immutable, and what is the string pool?
The string pool moved out of PermGen and onto the normal heap, so interned strings became collectable and the pool could grow with the heap.
Before (now gone): The pool lived in PermGen at a fixed maximum size. Interning user-supplied input was a documented way to produce OutOfMemoryError: PermGen space, and interned strings were effectively never collected.
substring() copies the characters it needs. Arrived in 7u6, along with the removal of String's offset and count fields.
Before (now gone): substring() shared the parent's char[] and stored an offset and length. It was O(1), but a three-character substring of a 10 MB string kept all 10 MB alive — a memory leak that looked like correct code.
What is the difference between checked and unchecked exceptions?
try-with-resources, plus suppressed exceptions: if close() throws while an exception is already in flight, the original survives and the close failure is attached to it.
Before (now gone): You closed in a finally block. If close() threw, its exception replaced the real one entirely — the actual cause was destroyed, and this was the single most common source of undiagnosable production failures in Java.
Multi-catch (catch (A | B e)) and precise rethrow, so a method can rethrow the specific checked types it caught rather than declaring throws Exception.
Before: Duplicated catch bodies, or one catch (Exception e) that swallowed types you never meant to handle.