Interview
Effective Java & Best Practices — Interview Questions (82+)
Idioms inspired by Joshua Bloch's Effective Java and modern Java style.
Detailed Questions
1. Prefer static factory methods over constructors?
- Short: Named methods (
valueOf,of) clarify intent; can cache, return subtypes. - Detailed:
Integer.valueOfcaches;Collections.emptyList()returns singleton. Constructors must beneweach time unless private for factories. Can't add names to constructors easily. - Example:
List.of()vsnew ArrayList<>(Arrays.asList(...)).
2. Builder pattern for many optional parameters?
- Short: Telescoping constructors are unreadable; Builder scales with fluency and validation.
- Detailed: Validate in
build(). Immutable object from builder. Lombok@Buildergenerates boilerplate. Consider records + factory for simple cases. - Example:
new Pizza.Builder().cheese(true).build();
3. Enforce singleton with enum?
- Short:
enum Instanceis best singleton — one instance, serialization-safe, reflection-safe. - Detailed: JVM guarantees single instance.
readResolvenot needed. Avoid double-checked locking unless you understand memory model. - Example:
enum Config { INSTANCE; void load() {} }
4. Eliminate obsolete references?
- Short: Null out or remove entries so objects aren't accidentally retained (memory leaks).
- Detailed: Static collections, listeners,
ThreadLocal, caches hold objects alive. Weak references for caches; remove listeners on destroy. - Example:
element = nullafter pop from custom stack (usually GC handles; matters if reused array).
5. Obey equals/hashCode contract?
- Short: Equal objects → equal hash codes; consistent with
equals. - Detailed: Use same fields in both.
Objects.equals/hashhelpers. For entities, business key vs surrogate ID decision affects ORM. - Example:
Objects.hash(name, dob)with matchingequals.
6. Always override toString?
- Short: Helps logging and debugging; keep concise, no secrets.
- Detailed: Records auto-generate. Include identifying fields. Don't throw from
toString. - Example:
User[id=42, email=masked].
7. Minimize mutability?
- Short: Immutable classes are simpler, thread-safe, freely shareable.
- Detailed:
finalfields, no setters, defensive copies on getters for mutable components.List.copyOfin constructor. - Example:
recordwithList.copyOf(items)in compact ctor.
8. Prefer composition to inheritance?
- Short: Inheritance couples to superclass implementation; composition is flexible.
- Detailed: Inheritance is "is-a" when true subtype behavior holds (LSP). Otherwise wrap (
ForwardingSetdelegating to innerSet). - Example:
class InstrumentedSet implements Setwrapping delegate.
9. Design for inheritance or prohibit it?
- Short:
@Finalor document hooks; subclasses can break invariants. - Detailed: If allowing subclassing, make self-use of overridable methods safe or make methods
final. Prefersealedfor controlled hierarchies. - Example:
AbstractCollectioncarefully documents override points.
10. Prefer interfaces to abstract classes?
- Short: Multiple inheritance of type; easier mocking; default methods bridge gap.
- Detailed: Abstract class when shared state/implementation needed. Interface for capability contracts (
Comparable,Runnable). - Example:
Listinterface + multiple implementations.
11. Check parameters validity?
- Short: Fail fast with
Objects.requireNonNull,IllegalArgumentException. - Detailed: Validate in constructors and public methods. Document in javadoc
@throws. Don't rely on assert for public API. - Example:
Objects.requireNonNull(name, "name").
12. Return empty collections, not null?
- Short:
Collections.emptyList()orList.of()— callers skip null checks. - Detailed: Null return forces defensive code everywhere. Optional for truly absent single values. Empty is not absent semantically for collections.
- Example:
return matches.isEmpty() ? List.of() : matches;
Rapid-Fire (Q → A)
- Private constructor + static factory? → Hide construction.
- Utility class pattern? → Private ctor, static methods only.
- Constant interface anti-pattern? → Don't implement constants interface.
- Use interface only for types? → Yes; not constant holder.
- Favor immutability in public API? → Yes.
- Defensive copy on getter? → For mutable internal state.
- Defensive copy on setter/ctor? → Before storing mutable param.
- Date class legacy? → Use java.time.
- Instant vs ZonedDateTime? → Instant = UTC point; Zoned = timezone rules.
- Period vs Duration? → Period calendar-based; Duration time-based.
- Don't use float for money? → BigDecimal.
- BigDecimal from String? → Yes; from double imprecise.
- RoundingMode HALF_UP? → Common commercial rounding.
- try-with-resources item 9? → Always for Closeable.
- Close failure handling? → Suppressed exception.
- Prefer standard exceptions? → IAE, ISE, NPE (requireNonNull).
- Document unchecked exceptions? → @throws in javadoc anyway.
- Include failure-capture in detail message? → Key ids/context.
- Override annotate @Override? → Catches typos.
- Override hashCode when equals? → Mandatory contract.
- Compare floats? → Float.compare / epsilon.
- Compare doubles? → Double.compare.
- Avoid strings for enums switches? → Use enum constants.
- Enum singleton vs static field? → Enum preferred.
- EnumSet for enum collections? → Bit vector fast.
- EnumMap? → Array-backed by ordinal.
- WeakHashMap use? → Cache with GC-friendly keys.
- IdentityHashMap when? → Reference equality semantics.
- Collections.sort mutates? → Yes, in-place.
- List.sort vs Collections.sort? → List.sort default method.
- Arrays.sort objects? → TimSort stable.
- Arrays.parallelSort when? → Large arrays, comparable.
- Prefer for-each? → Unless need remove via Iterator.
- Iterable custom? → Implement iterator.
- Stream not reusable? → New stream per pipeline.
- Optional return from method? → Not for fields/params usually.
- Optional.get without check? → NoSuchElementException.
- Optional.orElse vs orElseGet? → orElseGet lazy supplier.
- Optional stream flatMap? → Chaining optional steps.
- Don't use Optional as field? → Nullable or absent sentinel debate.
- Lazy initialization holder? → Static holder idiom.
- Double-checked locking volatile? → Required for correctness.
- Prefer java.util.concurrent? → Over wait/notify hand-rolled.
- Concurrent utilities over synchronized? → When higher-level fits.
- Document thread safety? → State in class javadoc.
- Synchronize entire method? → Same as sync(this) instance method.
- Avoid excessive sync? → Lock contention.
- ReadWriteLock when? → Read-heavy mutable structure.
- Stale data vs consistency? → Trade-off document.
- Serialization proxy pattern? → Control deserialized instance.
- readResolve? → Replace deserialized object.
- Avoid serialize inner class? → static nested preferred.
- Custom serialized form? → writeReplace/readResolve.
- Consider copy constructor? → Alternative to clone.
- Cloneable broken? → Prefer factories/copy methods.
- toString for debugging only? → Not parseable contract.
- compareTo consistent with equals? → Strongly recommended.
- Comparator natural order? → compareTo.
- TimSort requirement? → Stable sort needs stability.
- List.of immutable? → No add/remove/set.
- copyOf defensive? → Immutable snapshot.
- Map.entry? → Immutable entry pair.
- Factory List.of null? → NPE.
- Prefer integration tests scope? → Test behavior not implementation.
- Test one concept per test? → Clear failure diagnosis.
- Given-when-then? → Arrange-act-assert structure.
- Don't test private methods? → Test public contract.
- Parameterized tests? → JUnit5 @ParameterizedTest.
- Property-based testing? → jqwik random inputs.
- Avoid magic numbers? → Named constants.