Java SE 11 Developer study materials
Java SE 11 Developer study resources

Java SE 11 Developer common mistakes

Java SE 11 Developer · Understand the traps and how to avoid them.

Mistake 1

Assuming that a `switch` on a `String` or enum with a `default` label removes the need for a `break`, so execution falls through into later labels and produces unexpected output.

Candidates transfer habits from arrow-form switch expressions (Java 14+) or from languages with implicit break, and they forget that the classic colon-form switch statement in Java 11 always falls through unless break or return is present.

What to do instead

Trace every colon-form switch case by case, writing down the labels entered and where each break exits. When reviewing, ask explicitly: 'if this case matches, what is the next statement executed?' Practise rewriting a fall-through example into an if/else chain to confirm the intended semantics.

Mistake 2

Declaring a `var` local from a lambda, method reference, array initializer, or `null`, or expecting `var` to change the compile-time type of an expression (for example, expecting `var x = 1;` to be assignable to a `long` reference variable without widening rules).

The candidate treats var as dynamic typing rather than local variable type inference. The compiler still infers a single static type, and initializers that have no standalone type (lambdas, method references, null, array initializers without a target type) are rejected.

What to do instead

Memorise the exclusion list: var cannot be used for fields, method parameters, catch parameters, or with null, lambdas, method references, or array initializers. Remember the inferred type is the exact type of the initializer, so var i = 1; is int, not long. Practise declaring the same variable with an explicit type and with var and comparing what compiles.

Mistake 3

Mixing up method overriding and overloading rules: using a narrower access modifier when overriding, throwing broader checked exceptions, or expecting a covariant return type to allow an unrelated class.

Candidates remember 'same signature' but forget the full contract: access cannot be reduced, checked exceptions cannot be broadened, return type must be covariant (a subtype), and static methods are hidden rather than overridden. Overload resolution by most-specific applicable method is also frequently misjudged.

What to do instead

For each override, check four things in order: signature, access modifier, checked exceptions, and return type covariance. Then check whether the call site is resolved by static type. Build a table of legal and illegal override pairs and classify each failure; do the same for overloads where one parameter type is a subtype of another.

Mistake 4

Believing that a `finally` block always executes, or that a `return` inside `finally` is harmless; also expecting `catch` blocks to catch checked exceptions that the try body never declares.

The candidate learns 'finally always runs' as a slogan. In fact System.exit prevents it, and a return or throw in finally discards the original result or exception. Separately, the compiler rejects catching a checked exception the try block cannot throw.

What to do instead

State the rules precisely: finally runs unless the JVM exits or the thread is killed; a control-transfer statement in finally overrides any pending return or exception. Practise predicting output for try/catch/finally with returns in each block, and for try-with-resources where close() throws while the body also throws (the close exception is suppressed).

Mistake 5

Assuming `Arrays.asList` returns a fully mutable `ArrayList`, or that `List.of` and `Collections.unmodifiableList` behave the same, then calling `add` or `set` and being surprised by the exception.

Arrays.asList returns a fixed-size list backed by the array: set works, add/remove throw UnsupportedOperationException. List.of is truly immutable, rejects null, and throws on any modification. Candidates conflate the three.

What to do instead

Learn the three behaviours as a grid: backing array, size fixed or not, mutation allowed or not, nulls allowed or not. When a question shows a modification call, first identify which factory created the list, then predict the exact exception type. Practise new ArrayList<>(Arrays.asList(...)) as the standard way to get a mutable copy.

Mistake 6

Writing a lambda body that returns a value inside a functional interface whose abstract method is `void`, or omitting `return` in a block-bodied lambda that must return a value; also confusing `Function` and `BiFunction` or `Predicate` and `Consumer` in stream pipelines.

The candidate focuses on the lambda syntax and not on the target type. A lambda is compatible only if its parameter count and return behaviour match the single abstract method. Stream methods such as map require a value-returning function, while forEach requires a consumer.

What to do instead

Before writing a lambda, name the target functional interface and write its abstract method signature. Check parameter count, then check whether the method returns void or a value. For streams, recite the signatures of map, flatMap, filter, forEach, peek, and reduce, and note which return Stream and which return a terminal result.

Mistake 7

Placing a `module-info.java` in the wrong directory, exporting a package that does not exist, or forgetting `requires` for a module whose types are used, then blaming the classpath.

The module system is new to most candidates. Compilation errors such as 'package is not visible' or 'module not found' arise from missing requires, missing exports, or a source layout that does not match the module root expected by javac --module-source-path.

What to do instead

Adopt a fixed checklist: module declaration present, requires for every consumed module, exports for every package used by other modules, and services declared with uses/provides. Compile with explicit --module-path and --module-source-path and read the first error only, since later errors are often cascades.

Mistake 8

Assuming that starting a thread guarantees immediate execution, that `synchronized` on a static method locks the instance, or that `wait()` can be called without holding the monitor.

Candidates reason about concurrency sequentially. Thread scheduling is not guaranteed, synchronized static locks the Class object rather than this, and wait/notify throw IllegalMonitorStateException unless the calling thread owns the object's monitor. Visibility of shared mutable state without volatile or synchronization is also overlooked.

What to do instead

Write down, for each concurrency example, which lock is held by which thread at each line. Distinguish instance locks from class locks. Remember wait releases the monitor while sleep does not. For visibility questions, ask whether there is a happens-before edge; if not, treat the read as potentially stale.

Mistake 9

Mixing up byte streams and character streams, or forgetting that `Files.newBufferedReader` uses UTF-8 by default while `FileReader` uses the platform default charset; also failing to close resources or to use try-with-resources.

The candidate learns InputStream/OutputStream and Reader/Writer as parallel hierarchies but does not connect them to encoding. Charset mismatches produce mojibake rather than exceptions, so the error is silent. Resource leaks are similarly invisible in small examples.

What to do instead

Classify every I/O class by direction (in/out) and unit (byte/char). Always specify a charset explicitly when the API allows it, and prefer Files factory methods. Wrap every stream in try-with-resources and remember that closing the outer stream closes the underlying one; declaring multiple resources closes them in reverse order.

Mistake 10

Treating `String.format` and `DateTimeFormatter` patterns as interchangeable, or assuming `%d` accepts a `long` boxed as `Long` without issue, and misjudging locale-sensitive formatting such as number grouping or month names.

Format specifiers and date-time pattern letters are different languages. Candidates also forget that String.format uses the default locale unless one is supplied, so output differs across environments, and that %d accepts integral types but not double.

What to do instead

Keep two separate reference lists: conversion characters (%s, %d, %f, %n, %t) and date-time pattern letters (yyyy, MM, dd, HH, mm, ss). For any formatting question, identify the locale used and the argument's static type before predicting output. Practise formatting the same value with Locale.US and a non-English locale.