Chapter 7 Flashcards — Methods
flashcards effective-java methods api-design
What does Item 49 say you should do with method parameters, and when?
?
Check parameters for validity at the start of the method body, before any logic runs. Throw an appropriate exception immediately — NullPointerException, IllegalArgumentException, or IndexOutOfBoundsException. The fail-fast principle: catch errors at their source so the stack trace points directly to the bad call site.
What is the standard Java 7+ idiom for null-checking a parameter and storing it?
?
this.field = Objects.requireNonNull(param, "param must not be null"); — requireNonNull returns the reference if non-null, so it can be used inline in assignment. Throws NullPointerException with your message if null.
What Java 9 methods replaced manual index range checks?
?
Objects.checkIndex(index, length)— validates0 <= index < length, throwsIndexOutOfBoundsException.Objects.checkFromToIndex(fromIndex, toIndex, length)— validates a range for subList-style ops.Objects.checkFromIndexSize(fromIndex, size, length)— validates an offset+size range.
When should you use assert for parameter validation instead of throwing an exception?
?
Use assert only in private or package-private methods where the caller is code you control. Asserts are only enforced when the JVM is launched with -ea (enable assertions); they are disabled in production by default. Public APIs must use explicit exception throws — never rely on asserts for public contract enforcement.
What is the TOCTOU problem in Item 50, and how do you avoid it?
?
Time-of-Check/Time-of-Use: if you validate a mutable parameter before copying it, an attacker can mutate the object between validation and copy, defeating your check. Avoid it by copying mutable parameters before validating them — validate the copy, not the original.
Why should you NOT use clone() to make defensive copies of constructor parameters?
?
clone() can be overridden by a subclass of the parameter’s type to return a hostile object — one that appears valid but behaves maliciously. Use a copy constructor or factory method instead: e.g., new Date(original.getTime()) rather than original.clone().
What is the best long-term solution to the defensive-copy problem in Item 50?
?
Use immutable types from java.time (e.g., Instant, LocalDate, ZonedDateTime) instead of mutable Date. Immutable objects cannot be modified after creation, so there is nothing to defensively copy — neither on the way in nor on the way out.
Item 50: When must you make a defensive copy of a field before returning it?
?
Whenever the field is a mutable object and you are returning it from a public accessor. Example: public Date end() { return new Date(end.getTime()); }. Returning the field directly gives callers a reference to the object’s internal state, letting them mutate it from outside.
What is the “parameter object” pattern and when does Item 51 recommend it?
?
When a method has more than 3-4 parameters, group related parameters into a helper class (or record in Java 16+) that represents the combined argument. Example: record UserQuery(String nameFilter, SortField sortBy, int page, int pageSize) {}. This reduces cognitive load, enables reuse, and makes call sites self-documenting.
Why does Item 51 say to prefer two-element enums over boolean parameters?
?
A boolean parameter at the call site is meaningless: new Thermometer(true) — true what? An enum is self-documenting: new Thermometer(TemperatureScale.CELSIUS). Enums also make it easier to add a third option later without breaking callers.
Why does Item 51 say to accept the most general useful interface type for parameters?
?
Accepting Map<K, V> instead of HashMap<K, V> allows callers to pass any Map implementation — TreeMap, LinkedHashMap, ConcurrentHashMap, etc. — without unnecessary coupling to a concrete class. Maximum flexibility; minimum constraint.
What is the core problem with Java method overloading (Item 52)?
?
Overloading is resolved at compile time based on the static declared type of the argument — not the runtime type. Overriding is resolved at runtime. Callers expect overloading to behave like overriding; when it doesn’t, silent bugs result. Example: a Collection<?> variable holding a HashSet will call classify(Collection<?>), not classify(Set<?>).
What is the safe rule for designing overloaded methods (Item 52)?
?
Never export two overloads with the same number of parameters where an argument could legally be passed to either. If you must provide multiple overloads, ensure they all delegate to a single canonical implementation so they always behave identically.
How does Java 8 lambda/method reference usage make overloading more dangerous?
?
A lambda can satisfy multiple functional interfaces simultaneously (e.g., Runnable and Callable<Void> when the body returns void). If overloads exist for both, the compiler may pick the unexpected one. Casting makes the intent explicit: executor.submit((Runnable) () -> doWork()).
What is the List.remove() autoboxing overloading trap?
?
List<Integer> has two remove methods: remove(int index) removes by position; remove(Object o) removes by value. list.remove(1) calls remove(int) — removes index 1. list.remove((Integer) 1) calls remove(Object) — removes the value 1. Autoboxing makes the difference subtle and error-prone.
What is the key rule for varargs with a minimum of 1 argument (Item 53)?
?
Declare the first required argument explicitly before the vararg: static int min(int firstArg, int... remainingArgs). This enforces the minimum-1 constraint at compile time rather than throwing at runtime. The vararg then naturally represents “zero or more additional args.”
What is the performance pattern for varargs-heavy methods used by List.of()?
?
Provide overloads for each common arity (0, 1, 2, 3 args) that do not use varargs, then one final overload with varargs for higher arities. List.of() has overloads for 0-10 elements without varargs. Only calls with 11+ elements allocate an array. This eliminates array allocation for the vast majority of call sites.
When is @SafeVarargs appropriate and when is it not?
?
Apply @SafeVarargs to a generic varargs method when the method only reads from the varargs array and does not expose it or store it in a less-typed variable (which would cause heap pollution). It must be applied to static, final, or private methods (or constructors) — not to methods that can be overridden. Overriding methods could introduce heap pollution that the annotation promised would not exist.
Why should you never return null for an empty collection or array (Item 54)?
?
Returning null transfers a null-check burden to every caller. Callers routinely forget to null-check, causing NullPointerException in production. The “performance” argument for null is debunked by Collections.emptyList() — a singleton with zero allocation. Null means “unknown/not applicable,” not “zero results.”
What are the correct zero-cost ways to return empty collections (Item 54)?
?
Collections.emptyList()/Collections.emptySet()/Collections.emptyMap()— immutable singletons, zero allocation.List.of()/Set.of()/Map.of()(Java 9+) — immutable singletons, zero allocation.- For arrays: store
private static final T[] EMPTY_ARRAY = new T[0]and return the constant. collection.toArray(new T[0])— JIT-optimized, faster thantoArray(new T[size]).
What three approaches existed before Optional for “no result” return values, and what are their problems?
?
- Return null: every caller must null-check; NPE-prone when forgotten.
- Throw exception: appropriate only for truly exceptional conditions; forces callers to use try/catch for normal flow.
- Sentinel value (e.g.,
-1for index): not always available; semantics are implicit and easy to misinterpret.
Optional<T>makes the “might be empty” contract explicit in the return type, forcing callers to consider the absent case.
What are the correct ways to consume an Optional (Item 55)?
?
.orElse(defaultValue)— constant default..orElseGet(supplier)— lazy computed default (Java 8+)..orElseThrow(exceptionSupplier)— throw a domain exception if absent..ifPresent(consumer)— run action only if present..ifPresentOrElse(consumer, runnable)— handle both cases (Java 9+)..or(supplier)— chain to another Optional (Java 9+)..isEmpty()— check for absence (Java 11+)..stream()— convert to 0-or-1 Stream for flatMap (Java 9+).
When should you NOT use Optional (Item 55)? List all the anti-patterns.
?
- As a field type — not designed for this, not serializable, adds unnecessary overhead.
- As a parameter type — callers should pass null or use overloads; Optional params are awkward.
- In collections —
Map<K, Optional<V>>is almost always wrong; just omit the key. - For performance-critical return values — Optional allocates an object per non-empty return.
- For primitive types — use
OptionalInt,OptionalLong,OptionalDoubleto avoid boxing. - When null has always been acceptable — don’t retrofit Optional just for style.
What do OptionalInt, OptionalLong, and OptionalDouble solve that Optional<Integer> does not?
?
Optional<Integer> boxes the primitive int into an Integer object — two allocations (the Optional wrapper and the boxed integer). OptionalInt stores the primitive int directly inside the OptionalInt object — one allocation, no boxing. For methods returning primitive values frequently, this is a measurable performance improvement.
What Java 9 Optional method allows you to chain two Optionals without nesting?
?
Optional.or(Supplier<Optional<T>> supplier) — if the first Optional is present, returns it; otherwise evaluates the supplier and returns its Optional. Example: Optional<String> name = getPrimaryName().or(() -> getSecondaryName()); — flat, readable, no nesting.
What must every public method’s Javadoc comment contain (Item 56)?
?
- Summary sentence (first sentence — becomes the summary in generated docs and IDE tooltips).
@paramfor every parameter.@returnfor non-void methods.@throwsfor every checked exception and every unchecked exception a caller might want to handle.- Preconditions and postconditions in the body text.
- Side effects (e.g., starts a thread, modifies shared state).
- Thread safety at the class level.
What is the difference between {@code} and {@literal} in Javadoc?
?
{@code text}— renders text in monospace font and escapes HTML special characters (<,>,&). Use for actual code snippets inline.{@literal text}— escapes HTML special characters but does not change the font. Use for non-code text that happens to contain characters that would be interpreted as HTML.
How should you document a thread-safe class vs a non-thread-safe class (Item 56)?
?
Thread-safe: state in the class-level doc that all methods are safe for concurrent use without external synchronization.
Conditionally thread-safe: document exactly which method sequences require external locking and which lock to use.
Not thread-safe: explicitly state that instances must not be shared between threads without external synchronization.
Immutable: state that instances are immutable and therefore inherently thread-safe.
How should you document enum constants and annotation members (Item 56)?
?
- Enum constants: each constant should have its own Javadoc comment explaining what it represents.
- Annotation members: each member (method in the annotation type) should be documented with a description of what it represents and what the default value means.
Example:/** The exception the annotated method must throw to pass. */ Class<? extends Throwable> value();
What does Objects.requireNonNullElse(obj, defaultValue) do, and when should you use it instead of requireNonNull?
?
requireNonNullElse(obj, defaultValue) returns obj if non-null, otherwise returns defaultValue (which must itself be non-null). Use it when null is an acceptable input that should be silently replaced with a sensible default — e.g., initializing optional configuration fields. Use requireNonNull when null should be rejected with an exception.
What is the difference between Optional.isPresent() and Optional.isEmpty(), and which should you prefer?
?
Both check Optional’s state: isPresent() returns true if a value is present; isEmpty() (Java 11+) returns true if no value is present. Prefer isEmpty() over !isPresent() for readability — double negation is harder to parse. Both are equivalent to negating each other; isEmpty is the more fluent idiom in Java 11+.
Total Cards: 31
Review Time: ~20 minutes
Priority: HIGH
Last Updated: 2026-05-10