Lesson 2 of 4
Core Java: strings, equality, exceptions and memory
2 min read
Strings
Stringis immutable: every "change" creates a new object. That makes strings safe to share and cache (the string pool), and safe as map keys."a" + "b"in a loop creates many objects; useStringBuilder(not thread-safe, fast) orStringBuffer(synchronized, slower).==compares references;.equals()compares content.new String("hi") == "hi"isfalse.
equals and hashCode
If two objects are equals, they must have the same hashCode. Hash-based collections (HashMap, HashSet) use hashCode to find the bucket and equals to find the exact key. Override both together, or use a record:
public record Point(int x, int y) {} // equals, hashCode, toString generatedIf you override equals but not hashCode, two "equal" objects land in different buckets and set.contains(...) returns false.
Exceptions
Throwable
├── Error (OutOfMemoryError, StackOverflowError: don't catch)
└── Exception
├── checked (IOException, SQLException: must be caught or declared)
└── RuntimeException (unchecked: NullPointerException, IllegalArgumentException,
ArrayIndexOutOfBoundsException)try (BufferedReader r = Files.newBufferedReader(path)) { // try-with-resources closes r
return r.readLine();
} catch (IOException e) {
throw new UncheckedIOException("Could not read " + path, e); // keep the cause
} finally {
log.debug("done");
}throwraises an exception;throwsdeclares one in a method signature.final/finally/finalizeis a classic trick question: a keyword, a block that always runs, and a deprecated GC hook.
Memory and the JVM
- Stack: one per thread; method frames, local primitives and references. Freed automatically when a method returns.
- Heap: all objects; shared by threads; cleaned by the garbage collector when objects are unreachable.
- JDK (tools + JRE) → JRE (JVM + libraries) → JVM (runs bytecode). Java is "write once, run anywhere" because
.javacompiles to platform-independent.classbytecode, which the JVM interprets and JIT-compiles. - Java is pass-by-value always; for objects, the value passed is a copy of the reference. So a method can modify an object's fields but can't make the caller's variable point to a new object.
Wrapper classes and autoboxing
int ↔ Integer. Watch for NullPointerException when unboxing a null Integer, and for Integer caching: Integer a = 127, b = 127; a == b is true, but with 128 it's false. Use .equals.
Java 8+ features
Lambdas, functional interfaces, streams, Optional, the new date/time API (LocalDate), var (Java 10), records (16), switch expressions and text blocks.
Map<String, Long> byCity = students.stream()
.filter(s -> s.gradYear() == 2026)
.collect(Collectors.groupingBy(Student::city, Collectors.counting()));Check yourself
- Why is
Stringimmutable, and why does it matter forHashMapkeys? - What breaks if you override
equalswithouthashCode? - Checked vs unchecked exceptions: give two examples of each.
Sign up free to save your progress.