Java SE 17 (1Z0-829) cheat sheet
Java SE 17 (1Z0-829) · Keep the key ideas within reach.
Handling date, time, text, numeric and boolean values
java.time types are immutable: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration (time-based), Period (date-based).
LocalDate.of(2024, 2, 29) throws DateTimeException for invalid dates; Month is 1-based in java.time but 0-based in java.util.Calendar.
DateTimeFormatter.ofPattern uses 'M' month, 'd' day, 'H' hour 0-23, 'h' hour 1-12, 'm' minute, 's' second; text styles need 'MMM' or more; 'yyyy' is year-of-era.
String methods: strip() is Unicode-aware trim; isBlank() true for whitespace-only; repeat(n) returns concatenation; indent(n) adds n spaces per line and normalizes line endings.
String literals are interned; new String("a") is a distinct object, so == is false while equals is true. StringBuilder is mutable and not thread-safe; StringBuffer is synchronized.
Numeric literals: underscores may not start/end a literal or sit beside a decimal point; 0x hex, 0b binary, 0_ prefix octal; long needs L suffix; float needs f suffix.
Autoboxing caches: Integer.valueOf returns cached objects for -128..127, so == on boxed values in that range is true; outside it is false.
Text blocks (""") require a line break after the opening delimiter, strip incidental indentation, and support \s and \ escapes; """ escapes triple quotes.
switch on primitives, enums, String, and (Java 17) any type via pattern matching preview; switch expressions use yield or arrow form and must be exhaustive.
Utilizing collections and streams
List.of, Set.of, Map.of create immutable collections that reject nulls and throw UnsupportedOperationException on mutation.
HashMap allows one null key and null values; Hashtable and ConcurrentHashMap reject nulls; TreeMap sorts by natural order or Comparator and rejects null keys.
equals/hashCode contract: equal objects must have equal hash codes; a broken contract makes HashSet and HashMap lookups fail.
Stream pipeline: source -> zero or more intermediate operations (lazy) -> one terminal operation (eager). A stream cannot be reused after a terminal operation.
Collectors.toMap throws IllegalStateException on duplicate keys unless a merge function is supplied; Collectors.groupingBy returns Map<K, List> by default.
Optional: orElse always evaluates its argument; orElseGet is lazy; get() on empty throws NoSuchElementException; of(null) throws NullPointerException.
Comparator: comparing thenComparing chains; reversed() flips order; naturalOrder and reverseOrder are static factories; nullsFirst/nullsLast handle nulls.
Deque: ArrayDeque is preferred for stack/queue use; offer/poll/peek return special values, add/remove/element throw exceptions on empty.
Stream reduce with identity returns identity for empty streams; the 3-arg reduce is for parallel streams and requires an associative combiner.
Controlling program flow
switch arrow form has no fall-through; multiple labels use comma (case 1, 2 ->). Colon form falls through without break.
A switch expression must be exhaustive: cover all enum constants, all sealed subtypes, or include a default; otherwise compile error.
yield returns a value from a block in a switch expression; arrow with a single expression returns implicitly.
Labeled break exits the labeled loop entirely; labeled continue skips to the next iteration of the labeled loop.
for(;;) is an infinite loop; while(false) is a compile error for unreachable code; if(false) is allowed.
Ternary operator requires both branches to be compatible types; mixing int and Integer causes unboxing and possible NullPointerException.
Pattern matching for instanceof (Java 16+) binds a variable in the true branch: if (o instanceof String s) { s.length(); }.
do-while executes the body at least once and requires a semicolon after the while condition.
Unreachable code after return, throw, break, or continue in the same block is a compile error.
Handling exceptions and using local variable type inference
Checked exceptions extend Exception but not RuntimeException; they must be caught or declared. Error and RuntimeException are unchecked.
Multi-catch (catch (A | B e)) cannot include types where one is a subclass of the other, and the parameter is implicitly final.
try-with-resources closes resources in reverse declaration order; close() exceptions are suppressed and available via getSuppressed().
A catch block for a checked exception that cannot be thrown causes a compile error, except for Exception and Throwable.
var requires an initializer on the same statement, cannot be used for fields, method parameters, or return types, and is not a keyword.
var infers the declared type, not the runtime type: var list = new ArrayList() has static type ArrayList.
var with a null initializer or a lambda/method reference initializer is a compile error because no type can be inferred.
Overriding methods may narrow the throws clause but not broaden it; they may throw unchecked exceptions freely.
finally runs even after return in try; a return inside finally overrides the try's return value and discards exceptions.
Using object-oriented concepts and functional interfaces
Interface methods: abstract, default, static, private (Java 9+). Fields are implicitly public static final.
A class may implement multiple interfaces; if two interfaces provide conflicting default methods, the class must override and may call X.super.m().
Records are implicitly final, generate a canonical constructor, accessors, equals, hashCode, and toString; compact constructors validate without repeating parameters.
Sealed types use sealed/permits; permitted subtypes must be final, sealed, or non-sealed; sealed classes may omit permits if subtypes are in the same file.
Functional interfaces have exactly one abstract method; @FunctionalInterface is optional but enforces the rule.
Core functional interfaces: Function<T,R> apply, Consumer accept, Supplier get, Predicate test, UnaryOperator, BinaryOperator.
Method reference kinds: static (Type::method), instance on a particular object (obj::method), instance on a parameter (Type::method), and constructor (Type::new).
Abstract class vs interface: abstract classes may hold state and constructors; interfaces support multiple inheritance of type and default behavior.
Covariant return types are allowed in overrides; a subclass method may return a subtype of the parent's return type.
Handling date, time, text, numeric and boolean values
Period.between uses date units (years/months/days); Duration.between uses time units; mixing them on LocalDate throws UnsupportedTemporalTypeException.
LocalDateTime.of and ZonedDateTime.of throw DateTimeException on invalid values; atZone resolves gaps and overlaps using the zone rules.
DateTimeFormatter is immutable and thread-safe; SimpleDateFormat is mutable and not thread-safe.
parse() throws DateTimeParseException (a RuntimeException) on malformed input; format() throws on unsupported fields.
Integer.parseInt rejects leading '+'? No-it accepts a leading sign; Integer.valueOf caches -128..127 results.
Boolean.parseBoolean returns false for any string other than "true" ignoring case; it never throws.
Math.round(2.5) returns 3 (rounds half up); Math.round(-2.5) returns -2; casting a double to int truncates toward zero.
Utilizing collections and streams
Stream.of, Arrays.stream, Collection.stream, and IntStream.range are common sources; IntStream.range excludes the upper bound, rangeClosed includes it.
Intermediate operations: filter, map, flatMap, distinct, sorted, peek, limit, skip, takeWhile, dropWhile. Terminal: forEach, collect, reduce, count, anyMatch, findFirst.
flatMap flattens Stream<Stream> or maps to a stream and concatenates; map produces one output per input.
Collectors.partitioningBy always returns a Map with both true and false keys, even if one side is empty.
Collectors.joining(delimiter, prefix, suffix) requires CharSequence elements; summingInt and averagingInt return primitive-friendly results.
List.copyOf and Map.copyOf make unmodifiable copies; subList and Arrays.asList return views backed by the original, so set() writes through.
Iterator.remove is the safe way to delete during iteration; modifying a collection directly while iterating throws ConcurrentModificationException.
Arrays.sort on objects is stable; binarySearch requires a sorted array and returns a negative insertion point when not found.
Controlling program flow
Operator precedence: postfix > unary > cast > multiplicative > additive > shift > relational > equality > & > ^ > | > && > || > ?: > assignment.
Short-circuit && and || skip the right operand; & and | on booleans always evaluate both sides.
Integer division truncates toward zero; % follows the dividend's sign, so -7 % 3 is -1.
Compound assignment casts implicitly: byte b = 1; b += 1 compiles, b = b + 1 does not.
Pre-increment returns the new value; post-increment returns the old value before incrementing.
String concatenation with + converts null to "null"; comparing with == on Strings compares references.
Pattern matching for switch (Java 17 preview) requires -enable-preview; guarded patterns use when.
Numeric promotion: byte/short/char promote to int in arithmetic; mixing int and long yields long; mixing with float yields float.
Handling exceptions and using local variable type inference
Exception hierarchy: Throwable -> Error, Exception -> RuntimeException. Only checked exceptions require handling.
try-with-resources requires resources to implement AutoCloseable; effectively final variables may be used as resources (Java 9+).
Custom exceptions extend Exception (checked) or RuntimeException (unchecked); constructors should call super(message) or super(message, cause).
throw accepts only Throwable instances; throwing null causes NullPointerException.
var in a for-each loop is allowed: for (var s : list) is valid; var in a lambda parameter requires all parameters use var or none.
var cannot be used with array initializer shorthand: var a = {1,2} is illegal; use new int[]{1,2}.
Catching Exception catches RuntimeException too; catching Throwable also catches Error, which is discouraged.
Rethrowing a caught exception with a more precise static type is allowed in Java 7+ precise rethrow analysis.
Using object-oriented concepts and functional interfaces
Overloading is resolved at compile time by static types; overriding is resolved at runtime by the actual object type.
Object methods: equals, hashCode, toString, getClass, clone, finalize (deprecated); wait/notify are final on Object.
Static methods are hidden, not overridden; a static method cannot override an instance method and vice versa.
Constructors are not inherited; the first statement is this(...) or super(...), and the compiler inserts super() if absent.
Inner classes: static nested classes need no outer instance; non-static inner classes capture the outer instance and cannot declare static members (except constants).
Lambda expressions can capture effectively final local variables; instance and static fields are always accessible.
Predicate default methods: and, or, negate; Function has andThen and compose; Comparator has thenComparing and reversed.
Enum constants are implicitly public static final; enums can have constructors, fields, abstract methods per constant, and implement interfaces.
Handling date, time, text, numeric and boolean values
LocalDate.now() uses the default zone; Instant.now() is UTC-based; ZonedDateTime converts between them via atZone and toInstant.
withX methods return new instances (withYear, withMonth, plusDays, minusHours); the original object is unchanged.
TemporalAdjusters: firstDayOfMonth, lastDayOfYear, next(DayOfWeek), nextOrSame; adjustInto applies an adjuster to a temporal.
ChronoUnit.between returns a long count of whole units; DAYS.between on LocalDate ignores time-of-day.
String.format and printf use %s, %d, %f, %b, %n; %b prints false for null; %d rejects non-integral arguments with IllegalFormatConversionException.
String.repeat(0) returns an empty string; repeat with a negative count throws IllegalArgumentException.
Character.isDigit accepts Unicode digits; Integer.parseInt accepts only ASCII digits with an optional sign.
Utilizing collections and streams
Map iteration: entrySet, keySet, values; forEach(BiConsumer); computeIfAbsent inserts only when the key is absent or mapped to null.
merge(key, value, remappingFunction) removes the entry when the function returns null; compute always applies the function.
TreeSet and TreeMap use compareTo or Comparator; a Comparator inconsistent with equals breaks Set uniqueness semantics.
Stream.findAny may return any element and is preferred in parallel streams; findFirst preserves encounter order.
Primitive streams (IntStream, LongStream, DoubleStream) offer sum, average, summaryStatistics, and boxed().
Collectors.toMap requires non-null values; a null value causes NullPointerException in the merge path.
ArrayDeque cannot hold nulls; LinkedList can, but Deque methods like push(null) throw NullPointerException.
Stream.iterate(seed, hasNext, next) is a three-argument bounded form (Java 9+); the two-argument form is infinite.
Controlling program flow
if/else if chains evaluate in order; the first true branch wins and later conditions are skipped.
The enhanced for loop over an array or Iterable cannot modify the underlying collection structurally without ConcurrentModificationException.
switch with String uses equals semantics and throws NullPointerException on a null selector.
Bitwise shift: >> is arithmetic (sign-preserving), >>> is logical (zero-fill); shift distance is masked to 5 bits for int and 6 for long.
Boolean expressions in if require a boolean, not an int; unlike C, if (1) is a compile error.
Nested loops with labeled break exit only the labeled loop; unlabeled break exits the innermost loop or switch.
Conditional operator with one branch throwing is allowed: x > 0 ? 1 : throwException() compiles if the method returns int.
assert statements are disabled by default and require -ea; they throw AssertionError, not Exception.
Handling exceptions and using local variable type inference
finally is skipped only if the JVM exits (System.exit) or the thread is killed; otherwise it always runs.
try-with-resources may omit catch and finally; the compiler still generates close handling.
Suppressed exceptions are attached to the primary exception and retrieved with getSuppressed(); they are not lost.
var cannot be used as a class field, method parameter, catch parameter, or in a method signature; it is only for local variables and lambda parameters.
var with diamond and anonymous classes: var x = new Object(){} infers an anonymous type; var with diamond infers the target type.
Checked exceptions in lambdas must be handled inside the lambda; functional interfaces like Runnable do not declare checked exceptions.
Exception in initializer blocks or static initializers surfaces as ExceptionInInitializerError or NoClassDefFoundError.
Overriding methods may not throw broader checked exceptions, but may throw any unchecked exception.
Using object-oriented concepts and functional interfaces
Inheritance: a subclass constructor must call an accessible superclass constructor; private constructors prevent subclassing.
Polymorphism applies to instance methods only; fields and static methods are resolved by the reference type.
Abstract methods have no body and must be implemented by the first concrete subclass; abstract classes cannot be instantiated.
Interface static methods are not inherited and must be called via the interface name.
Lambda target type must be a functional interface; assigning a lambda to Object is illegal because Object is not functional.
Method reference Type::instanceMethod with one parameter treats the parameter as the receiver; with two parameters it treats the first as receiver.
Records cannot extend classes (they extend Record) but can implement interfaces; they cannot declare instance fields beyond the components.
Sealed interface permits records, classes, and other interfaces; the permits clause is mandatory unless subtypes are in the same compilation unit.
Handling date, time, text, numeric and boolean values
Instant is a point on the timeline in UTC; it has no zone or offset and does not support plusMonths (throws UnsupportedTemporalTypeException).
LocalDate.plusMonths adjusts the day-of-month to the last valid day: 2024-01-31 plus 1 month is 2024-02-29.
DayOfWeek values are Monday=1 through Sunday=7; Month values are January=1 through December=12.
ZonedDateTime handles DST: during a gap, times shift forward; during an overlap, the earlier offset is chosen by default.
String.stripLeading and stripTrailing remove Unicode whitespace; trim removes only characters <= U+0020.
Integer.toBinaryString, toHexString, toOctalString return unsigned representations; negative ints show two's complement bits.
Boolean logical operators: & and | are non-short-circuit; ^ is exclusive-or and returns true when operands differ.
Utilizing collections and streams
Collection vs Map: Map does not extend Collection; Map.Entry is a nested interface accessed via entrySet.
ArrayList grows by about 50% when full; LinkedList offers O(1) insert at ends but O(n) index access.
HashSet iteration order is unspecified; LinkedHashSet preserves insertion order; TreeSet sorts.
Stream.sorted() requires Comparable elements or a Comparator; otherwise ClassCastException at runtime.
Collectors.counting returns Long; Collectors.mapping applies a mapper before a downstream collector.
Optional.stream() (Java 9+) converts an Optional to a zero-or-one-element stream for flatMap pipelines.
Stream.toList() (Java 16+) returns an unmodifiable list; Collectors.toList() returns a mutable ArrayList in practice.
Parallel streams use the common ForkJoinPool; ordering operations like findFirst and forEachOrdered preserve encounter order at a cost.
Controlling program flow
Comparison of boxed types with == compares references; use equals or unbox to a primitive for value comparison.
The switch selector cannot be long, float, double, or boolean; it may be int-compatible, String, or enum.
A switch expression assigned to a variable must be exhaustive; a switch statement need not be.
Nested ternary expressions associate right-to-left; parentheses clarify precedence.
Loop variable scope: a variable declared in a for initializer is visible only in the loop body and update.
continue in a do-while jumps to the condition evaluation, not the body start.
Integer overflow wraps silently; Math.addExact throws ArithmeticException on overflow.
Pattern variable scope in instanceof extends past the if when the condition guarantees the type, e.g. after an early return.
Handling exceptions and using local variable type inference
Order of catch blocks matters: a superclass catch before a subclass catch is a compile error for related checked types.
A try block with only a finally (no catch) is legal; the exception propagates after finally runs.
try-with-resources resource declarations are implicitly final; reassigning them is a compile error.
var infers from the initializer's static type; var x = 1 is int, var y = 1L is long, var z = 1.0 is double.
var cannot be initialized with a null literal because the type cannot be inferred.
var in a lambda parameter requires the parameter type syntax: (var a, var b) -> ...; mixing var and typed parameters is illegal.
Multi-catch parameter is implicitly final; assigning to it inside the catch block is a compile error.
Unchecked exceptions need not be declared but may be; declaring RuntimeException in throws is legal though unusual.
Using object-oriented concepts and functional interfaces
Composition over inheritance: has-a relationships avoid fragile base class problems and allow interface-based delegation.
Interface default method conflicts are resolved by class override; the class can invoke Interface.super.method().
Encapsulation: private fields with public accessors; records expose accessors named after components without get prefixes.
equals must be reflexive, symmetric, transitive, consistent, and return false for null; hashCode must match equals.
Functional interface composition: Predicate.and short-circuits; Function.andThen applies this then the argument.
Anonymous classes can extend a class or implement an interface and capture effectively final locals; lambdas cannot declare state.
Static nested vs inner: a static nested class can be instantiated without an outer instance; an inner class requires one.
Covariant return type and bridge methods: the compiler generates bridge methods to preserve polymorphism after erasure.
Handling date, time, text, numeric and boolean values
Duration.ofDays(1) is 24 hours; Period.ofDays(1) is one calendar day. Duration works on time-based temporals, Period on date-based.
DateTimeFormatter.ofLocalizedDate requires a locale and style; ISO_LOCAL_DATE is the default toString format for LocalDate.
parse with a pattern requires the input to match exactly; extra characters cause DateTimeParseException.
ZonedDateTime.of(2024, 3, 10, 2, 30, 0, 0, ZoneId.of("America/New_York")) shifts to 3:30 due to the DST gap.
Numeric wrapper parsing: Double.parseDouble accepts "NaN" and "Infinity"; Integer.parseInt does not accept decimals.
String comparison: compareTo returns the difference of the first differing characters; equalsIgnoreCase ignores case but not locale rules.
Text block incidental whitespace is stripped based on the least-indented line and the closing delimiter position.
Utilizing collections and streams
Queue methods: offer/add, poll/remove, peek/element; the second of each pair throws on failure or empty.
Map.getOrDefault returns the default without inserting; computeIfAbsent inserts the computed value.
Stream.limit(n) on an infinite stream terminates it; without a short-circuiting operation the pipeline never completes.
Collectors.teeing (Java 12+) applies two collectors and merges results with a BiFunction.
Grouping with a downstream collector: groupingBy(classifier, counting()) returns Map<K, Long>.
Arrays.asList returns a fixed-size list backed by the array; add and remove throw UnsupportedOperationException but set works.
Collections.unmodifiableList wraps a view; changes to the backing list remain visible through the wrapper.
Stream.concat merges two streams; duplicates are not removed unless distinct() is applied.
Controlling program flow
The diamond operator cannot be used with anonymous inner classes in Java 8 but is allowed in Java 9+.
Switch on enum: case labels use unqualified constant names, not EnumType.CONSTANT.
A while loop condition must be boolean; assignment in the condition is allowed only if it yields boolean.
The comma operator does not exist in Java; multiple declarations in a for initializer use commas but expressions do not.
Labeled statements can label any statement, but break/continue labels must reference an enclosing loop for continue.
Integer caching affects switch on Integer selectors: unboxing occurs, so null causes NullPointerException.
Logical complement ! has higher precedence than relational operators; !a == b parses as (!a) == b.
Handling exceptions and using local variable type inference
var is a reserved type name, not a keyword; a class named var is legal but discouraged.
var cannot be used in a method's throws clause, in a cast, or as a type argument in a declaration.
var with an array initializer requires explicit type: var a = new int[]{1,2} is legal; var a = {1,2} is not.
try-with-resources with multiple resources closes in reverse order and suppresses close exceptions onto the first thrown.
A finally block that throws replaces the original exception; the original is lost unless captured.
Catching a checked exception that the try cannot throw is a compile error unless the catch type is Exception or Throwable.
var in a for loop initializer is allowed: for (var i = 0; i < 10; i++).
Custom checked exceptions must extend Exception; extending Throwable directly is legal but unusual and not checked by the compiler's handler rules.
Using object-oriented concepts and functional interfaces
Interface segregation: small functional interfaces (Supplier, Consumer) compose better than large ones.
A class implementing Comparable must be consistent with equals for sorted collections to behave correctly.
Overriding toString, equals, and hashCode together keeps debugging and hash-based collections correct.
Lambda vs anonymous class: this in a lambda refers to the enclosing instance; in an anonymous class it refers to the anonymous instance.
Method references to super and this: super::method and this::method are valid; TypeName.super::method works in overrides.
Sealed class permits clause can be omitted when all permitted subclasses are in the same source file.
Records with a compact constructor cannot assign fields directly; they assign parameters and the compiler generates field assignment.
Abstract class can implement an interface without implementing its methods, leaving them to subclasses.
Handling date, time, text, numeric and boolean values
LocalDate.ofEpochDay and toEpochDay convert between date and day count; Instant.ofEpochSecond converts seconds to an instant.
ChronoUnit.DAYS.between(LocalDate, LocalDate) returns a long; Period.between returns a Period with years, months, days.
DateTimeFormatter.withLocale affects month and day names; without it the default locale is used.
String.join(delimiter, elements) accepts CharSequence elements and null-safe delimiter; elements may be null and print as "null".
Integer.compare and Long.compare return negative, zero, or positive; useful for Comparator.comparingInt.
Boolean.valueOf(String) returns Boolean.TRUE only for "true" ignoring case; otherwise Boolean.FALSE.
Math.floorDiv and floorMod handle negative operands consistently: floorMod(-7, 3) is 2.
Utilizing collections and streams
Stream operations are lazy until a terminal operation; peek without a terminal operation executes nothing.
A stream can be created from a file with Files.lines and must be closed; use try-with-resources.
Collectors.toUnmodifiableList (Java 10+) rejects null elements; Stream.toList also rejects nulls.
Map.ofEntries accepts Map.entry pairs and is preferable for more than 10 entries.
TreeMap.headMap, tailMap, and subMap return views; changes to the view affect the original map.
Iterator.forEachRemaining consumes the rest of the iterator; it is a terminal action on the iterator.
Stream.ofNullable (Java 9+) returns an empty stream for null and a singleton stream otherwise.
Collectors.reducing is a general reduction; the three-argument form requires identity, mapper, and BinaryOperator.
Controlling program flow
The conditional operator's result type follows binary numeric promotion; int and Integer mix unboxes.
A switch statement with arrow labels does not fall through, so break is unnecessary and allowed only in colon form.
The enhanced for loop over an array copies the element reference; modifying the loop variable does not change the array.
Infinite loops with while(true) are allowed; the compiler does not flag the following code as unreachable unless it is in the same block after the loop.
Short-circuit evaluation prevents NullPointerException: obj != null && obj.method() is safe.
Nested switch statements can use break to exit only the innermost switch.
The instanceof pattern variable is in scope in the else branch only if negated and the type is provably incompatible.
Handling exceptions and using local variable type inference
Exception chaining: new RuntimeException("msg", cause) preserves the cause; getCause retrieves it.
printStackTrace prints the chain; StackTraceElement gives class, method, file, and line.
try-with-resources with a null resource is allowed; close is skipped for null resources.
var with a lambda initializer is illegal because the lambda needs a target type; assign to a functional interface instead.
var cannot be used in a static initializer? It can, as a local variable inside a static block.
Checked exceptions from close() are suppressed, not propagated, when the try body throws.
Error subclasses (OutOfMemoryError, StackOverflowError) are unchecked and should not be caught in normal flow.
A method may declare throws for an unchecked exception; callers are not forced to handle it.
Using object-oriented concepts and functional interfaces
Interface fields are constants; they cannot be instance fields and are initialized at declaration.
Default methods can be added to interfaces without breaking implementers; they may call other interface methods.
A functional interface may declare default and static methods; only one abstract method is allowed.
Lambda parameter types may be omitted; if one is typed, all must be typed (before Java 11 var support).
Method reference to an instance method of an arbitrary object requires the first parameter to be the receiver type.
Constructors are not inherited but can be invoked with super; private constructors prevent both subclassing and instantiation.
Records generate a canonical constructor whose parameter list matches the component list; additional constructors must delegate to it.
Sealed hierarchy exhaustiveness in switch expressions is checked without a default when all permitted subtypes are covered.
Handling date, time, text, numeric and boolean values
LocalTime has nanosecond precision; LocalTime.of(12, 30, 45, 500_000_000) sets 500 milliseconds.
Instant.plus(Duration) works; Instant.plus(Period) throws UnsupportedTemporalTypeException.
ZoneId.of("UTC") and ZoneOffset.UTC differ in type; ZoneOffset is a subclass of ZoneId.
DateTimeFormatter.ISO_INSTANT formats an Instant; formatting a LocalDate with it throws UnsupportedTemporalTypeException.
String.format("%5.2f", 3.14159) pads to width 5 and rounds to 2 decimals, producing " 3.14".
NumberFormat and DecimalFormat are locale-sensitive; DecimalFormat is not thread-safe.
Integer.MAX_VALUE + 1 overflows to Integer.MIN_VALUE; use Math.addExact to detect overflow.
Utilizing collections and streams
Stream.collect with Collectors.toMap requires unique keys; duplicates throw IllegalStateException unless a merge function is given.
Collectors.partitioningBy with a downstream collector returns Map<Boolean, D>; both keys are always present.
Stream.flatMap requires a function returning a stream; returning null causes NullPointerException.
List.of and Set.of reject null elements; Map.of rejects null keys and values.
ConcurrentHashMap does not allow null keys or values; computeIfAbsent with a null-returning function leaves the mapping absent.
ArrayDeque as a stack: push adds to the head, pop removes from the head, peek examines the head.
Stream.count on a parallel stream may skip traversal but still returns the correct count.
Comparator.comparing requires a key extractor returning Comparable; use comparingInt for primitives to avoid boxing.
Controlling program flow
The if statement without braces applies only to the next statement; dangling else binds to the nearest if.
switch case labels must be compile-time constants (or enum constants, or String literals) in colon form.
A switch expression with arrow labels can return a value directly without yield if the body is an expression.
The for-each loop cannot be used to modify array elements through the loop variable; assign via index instead.
Short-circuit || evaluates the right side only when the left is false; & always evaluates both.
The ternary operator cannot be used as a statement on its own; its result must be used or assigned.
Integer comparison with == outside the cache range returns false; always use equals for boxed values.
A labeled continue must reference an enclosing loop; a label on a non-loop statement cannot be used with continue.
Handling exceptions and using local variable type inference
Multi-catch reduces duplication; the caught variable's type is the least upper bound of the alternatives.
A try-finally without catch propagates the exception after finally; a return in finally suppresses it.
var cannot be used with a null initializer, a lambda, or a method reference without a target type.
var in a lambda parameter list requires all parameters to use var and the lambda to have an explicit target type.
Checked exceptions must be handled or declared; wrapping in RuntimeException converts them to unchecked.
try-with-resources resources are closed even if the try block returns; the close happens before the method returns.
An overriding method may throw fewer checked exceptions but not more; unchecked exceptions are unrestricted.
ExceptionInInitializerError wraps an exception thrown in a static initializer.
Using object-oriented concepts and functional interfaces
Inheritance and constructors: super() must be the first statement; this() delegates to another constructor in the same class.
Overriding rules: same signature, covariant return, not more restrictive access, not broader checked exceptions.
Static methods cannot be abstract; abstract classes can have static methods and final methods.
Functional interface assignment: a lambda can be assigned to any compatible functional interface; overload resolution can be ambiguous.
Predicate.not (Java 11+) negates a predicate; useful with method references.
Records cannot declare instance fields other than components; static fields are allowed.
Sealed types restrict extension; a non-sealed subtype reopens the hierarchy for extension.
Interface private methods (Java 9+) share code between default methods without exposing it to implementers.
Handling date, time, text, numeric and boolean values
Period.between(2024-01-31, 2024-03-01) returns P1M1D because months are counted first, then days.
Duration.between(LocalTime, LocalTime) returns a Duration; negative durations occur when the end is before the start.
DateTimeFormatter patterns: 'u' is year, 'y' is year-of-era; 'a' is AM/PM; 'z' is zone name.
String.toUpperCase uses the default locale; use toUpperCase(Locale.ROOT) for locale-independent results (Turkish i problem).
Numeric literals: 1_000_000 is valid; 1__0 is valid; 1 and 1 are invalid.
Character.getNumericValue('A') returns 10; Character.digit('A', 16) returns 10.
Boolean operators on wrapper types unbox; a null Boolean causes NullPointerException in a logical expression.
Utilizing collections and streams
Collection.remove(Object) vs remove(int) on List: autoboxing decides which overload is called.
List.indexOf uses equals; a broken equals makes indexOf and contains unreliable.
Set.add returns false if the element is already present; HashSet uses hashCode then equals.
Stream.sorted is stable for ordered streams; sorted with a Comparator does not mutate the source.
Collectors.groupingBy with a TreeMap supplier preserves key order; the default is HashMap.
Stream.generate requires a Supplier and is infinite; combine with limit to terminate.
Optional.ifPresentOrElse (Java 9+) handles both present and empty cases without isPresent.
Arrays.deepEquals compares nested arrays; Arrays.equals on Object[] uses equals on elements.
Controlling program flow
The switch statement on a String is compiled to hashCode and equals; a null selector throws NullPointerException.
The arrow form of switch allows a block body with yield; a single expression returns implicitly.
A switch expression must cover all possible values; for enums, all constants or a default.
Nested loops: break exits the innermost loop or switch; labeled break exits the labeled construct.
The for loop's update section can contain multiple expressions separated by commas.
The enhanced for loop on a null array or collection throws NullPointerException at the start.
Operator precedence: cast binds tighter than multiplicative but looser than postfix; (int) 3.9 + 1 is 4.
Integer division by zero throws ArithmeticException; floating-point division by zero yields Infinity or NaN.
Handling exceptions and using local variable type inference
try-with-resources with an effectively final variable: try (var r = existingResource) is allowed if r is effectively final.
var cannot be used for a catch parameter; catch parameters must have an explicit type or multi-catch union.
A finally block can omit catch; the exception propagates after finally unless finally returns or throws.
Suppressed exceptions are added in reverse order of closing; getSuppressed returns an array.
Custom exceptions should provide at least a message constructor and a message-plus-cause constructor.
Unchecked exceptions include IllegalArgumentException, IllegalStateException, NullPointerException, and ClassCastException.
A method overriding one that throws IOException may throw FileNotFoundException (a subclass) but not Exception.
var is not allowed for compound declarations like var a = 1, b = 2; each declaration needs its own var.
Using object-oriented concepts and functional interfaces
Interface default method conflict: the class must override; InterfaceName.super.method() invokes a specific default.
Abstract class vs interface: a class extends one class but implements many interfaces; interfaces cannot have instance fields.
Polymorphism with fields: field access is resolved by the reference type, not the object type.
Lambda expressions implement functional interfaces; they cannot extend classes or have instance state.
Method reference to a constructor: Supplier<List> s = ArrayList::new; the target type determines the constructor.
Records are implicitly final and cannot be abstract; they can be sealed? No-records are final and cannot be sealed parents.
Sealed class permits clause: permitted subtypes must be accessible and in the same module or package.
Functional interface with a generic method: the target type supplies type arguments; a raw type loses type safety.
Handling date, time, text, numeric and boolean values
LocalDate.parse("2024-02-29") succeeds; parsing "2024-02-30" throws DateTimeParseException.
DateTimeFormatter.ofPattern("dd/MM/yyyy") parses day-first; using MM/dd/yyyy on the same input may throw or misparse.
Instant.EPOCH is 1970-01-01T00:00:00Z; Instant.now().getEpochSecond returns seconds since then.
ChronoUnit.MONTHS.between counts whole months; it truncates partial months.
String.matches uses the entire string; Pattern.compile with find searches substrings.
Integer.toUnsignedString and Integer.divideUnsigned handle unsigned arithmetic.
Boolean.getBoolean reads a system property, not a string literal; it returns false if the property is absent.
Utilizing collections and streams
Map.entrySet().stream() enables stream processing over map entries; use Map.Entry::getKey and getValue.
Collectors.toMap with a merge function resolves duplicates: (a, b) -> a keeps the first value.
Stream.reduce(BinaryOperator) returns Optional; the identity form returns the identity for empty streams.
IntStream.sum returns int and can overflow; use summaryStatistics or mapToLong for safety.
Collection.parallelStream uses the common pool; custom pools require a ForkJoinPool submit.
Stream operations on a closed stream throw IllegalStateException.
List.sort(Comparator) mutates in place; Stream.sorted returns a new stream.
Arrays.binarySearch on an unsorted array returns an undefined result.
Controlling program flow
The while loop with a constant false condition is legal but the body is unreachable if the condition is a compile-time constant false? The compiler flags unreachable code after while(false) only in some cases.
A switch statement with no matching case and no default does nothing.
The conditional operator requires the second and third operands to be convertible to a common type; otherwise a compile error.
Numeric promotion in the conditional operator: int and long yield long; int and float yield float.
Labels are identifiers followed by a colon; they can label loops and blocks.
break inside a switch inside a loop exits the switch, not the loop.
The for-each loop over an Iterable uses iterator(); a null iterator causes NullPointerException.
The instanceof operator returns false for null; a pattern variable is not assigned when the check fails.
Handling exceptions and using local variable type inference
var with a diamond operator infers from the target type in some contexts; otherwise it infers from the constructor.
var cannot be used in a method signature, field declaration, or as a return type.
try-with-resources can declare multiple resources separated by semicolons; they close in reverse order.
A catch block can catch multiple exception types with a multi-catch; the parameter is final.
finally is not executed if the JVM crashes or System.exit is called.
Checked exceptions in a lambda must be caught inside or wrapped; the functional interface declares no checked exceptions.
Exception.getMessage returns the detail message; getLocalizedMessage may be overridden.
A try block with a return and a finally that modifies a local variable does not change the returned value if the variable is primitive and returned by value.
Using object-oriented concepts and functional interfaces
Inheritance: a subclass can access protected members; package-private members are accessible only within the same package.
Overriding equals requires overriding hashCode; records generate both from components.
Abstract methods cannot be private, static, or final; they must be implemented by concrete subclasses.
Interface static methods are not inherited and cannot be overridden; call them via the interface name.
Lambda expressions can be assigned to a functional interface variable; the lambda's body determines the behavior.
Method reference kinds: static, bound instance, unbound instance, and constructor; the target type determines compatibility.
Records cannot declare instance fields; they can declare static fields and instance methods.
Sealed types: a permitted subtype must be final, sealed, or non-sealed; otherwise a compile error.
Handling date, time, text, numeric and boolean values
LocalDate.atStartOfDay returns LocalDateTime at 00:00; atStartOfDay(zone) resolves DST gaps.
ZonedDateTime.withZoneSameInstant keeps the instant; withZoneSameLocal keeps the local time.
Duration.toMinutes truncates; toMinutesPart returns the minutes component.
Period.normalized adjusts months to years but does not normalize days to months.
String.format("%s", null) prints "null"; String.format("%b", null) prints "false".
Integer.parseInt(" 1") throws NumberFormatException; whitespace is not trimmed.
Math.abs(Integer.MIN_VALUE) returns Integer.MIN_VALUE due to overflow.
Utilizing collections and streams
Stream.iterate with a predicate (Java 9+) creates a finite stream; the predicate is tested before each element.
Collectors.filtering (Java 9+) filters before downstream collection; useful with groupingBy.
Collectors.flatMapping flattens mapped streams before downstream collection.
Map.forEach(BiConsumer) iterates entries; modifying the map during iteration throws ConcurrentModificationException.
List.of().get(0) throws IndexOutOfBoundsException; List.of() is empty and immutable.
Set.of() rejects duplicates at creation with IllegalArgumentException.
Stream.findFirst on an empty stream returns Optional.empty; get on it throws NoSuchElementException.
Comparator.nullsFirst requires a comparator for non-null values; nullsFirst(naturalOrder()) sorts nulls first.
Controlling program flow
The switch statement on an enum with a null selector throws NullPointerException; guard with a null check.
The arrow form of switch does not allow fall-through; each label is independent.
A switch expression can be used as a statement; the result is discarded.
The for loop's condition is evaluated before each iteration; an empty condition means true.
The do-while loop's body executes before the condition; the condition must be boolean.
Nested ternary expressions can be hard to read; parentheses clarify grouping.
The conditional operator's result type is the least upper bound of the two operands after numeric promotion.
Integer overflow in a loop condition can cause an infinite loop; use long or a bound check.
Handling exceptions and using local variable type inference
var cannot be used with a null initializer; the compiler cannot infer a type.
var with a lambda requires a target type; assign to a functional interface variable.
try-with-resources requires AutoCloseable; Closeable extends AutoCloseable with IOException.
Multi-catch cannot include related types; a subclass and superclass in the same multi-catch is a compile error.
finally runs after catch; a return in finally overrides any return in try or catch.
Checked exceptions must be declared or caught; RuntimeException and Error are unchecked.
A method can declare throws for an unchecked exception; callers are not required to handle it.
Exception chaining preserves the cause; getCause returns null if no cause was set.
Using object-oriented concepts and functional interfaces
Inheritance: a subclass constructor must call an accessible superclass constructor; the compiler inserts super() if no explicit call.
Overriding: the method signature must match; covariant return types are allowed; access cannot be reduced.
Abstract class: can have abstract and concrete methods; cannot be instantiated.
Interface: can have abstract, default, static, and private methods; fields are constants.
Lambda: implements a functional interface; captures effectively final locals.
Method reference: Type::method, obj::method, Type::new; the target type determines compatibility.
Record: immutable data carrier; generates constructor, accessors, equals, hashCode, toString.
Sealed: restricts which classes can extend; permits clause lists permitted subtypes.
Handling date, time, text, numeric and boolean values
LocalDate.of(2024, 13, 1) throws DateTimeException; month must be 1-12.
LocalTime.of(25, 0) throws DateTimeException; hour must be 0-23.
DateTimeFormatter.ofPattern("yyyy-MM-dd") formats LocalDate; parsing requires exact match.
Instant.parse expects ISO-8601 with Z; other formats throw DateTimeParseException.
String.repeat(-1) throws IllegalArgumentException; repeat(0) returns "".
Integer.valueOf("1") returns a cached Integer for 1; == with another valueOf(1) is true.
Boolean.parseBoolean("TRUE") returns true; it ignores case.
Math.round(-2.5) returns -2; Math.round(2.5) returns 3.
Utilizing collections and streams
Stream.of(T...) creates a stream; Stream.of(array) creates a stream of one array unless flattened.
Arrays.stream(int[]) creates an IntStream; boxed() converts to Stream.
Collectors.toMap with a merge function and a map supplier controls duplicate handling and map type.
Collectors.groupingBy with a classifier and downstream collector returns Map<K, D>.
Optional.map returns Optional; flatMap avoids nested Optional.
List.copyOf creates an unmodifiable copy; changes to the original are not reflected.
Map.copyOf creates an unmodifiable copy; null keys or values throw NullPointerException.
Stream.concat(a, b) preserves order; duplicates are not removed.
Controlling program flow
The if statement's condition must be boolean; an int is not convertible to boolean.
The switch selector can be byte, short, char, int, String, or enum; not long, float, double, or boolean.
The arrow form of switch does not fall through; the colon form does without break.
A switch expression must be exhaustive; a switch statement need not be.
The for loop's initializer can declare multiple variables of the same type.
The enhanced for loop cannot modify the array or collection structure.
break exits the innermost loop or switch; labeled break exits the labeled construct.
continue skips the rest of the loop body and proceeds to the next iteration.
Handling exceptions and using local variable type inference
var infers the static type from the initializer; var x = 1 is int.
var cannot be used for fields, method parameters, or return types.
var cannot be initialized with null; the type cannot be inferred.
var with a lambda requires a target type; assign to a functional interface.
try-with-resources closes resources in reverse order; close exceptions are suppressed.
Multi-catch cannot include related types; the parameter is implicitly final.
finally runs even after return; a return in finally overrides the try's return.
Checked exceptions must be caught or declared; unchecked exceptions need not be.
Using object-oriented concepts and functional interfaces
Interface default methods can be overridden; conflicting defaults require an override.
Abstract classes can have constructors; interfaces cannot.
Records are implicitly final; they cannot be extended.
Sealed classes restrict extension; permitted subtypes must be final, sealed, or non-sealed.
Functional interfaces have one abstract method; default and static methods are allowed.
Lambda expressions capture effectively final locals; they cannot modify them.
Method references are shorthand for lambdas; the target type determines compatibility.
Polymorphism applies to instance methods; fields and static methods are resolved by the reference type.