Java SE 8 Programmer II cheat sheet
Java SE 8 Programmer II · Keep the key ideas within reach.
Java Class Design
Encapsulation: private fields + public accessors; a public setter on a private field does not make the field read-only.
An overridden method cannot reduce visibility: public > protected > default (package) > private; private methods are not inherited and cannot be overridden.
Covariant return types are allowed: an override may return a subtype of the superclass return type.
final method: cannot be overridden; final class: cannot be extended; final variable: assigned exactly once (blank final must be assigned in every constructor or initializer).
static methods are hidden, not overridden; the version invoked depends on the reference type, not the object type.
Constructor rules: super()/this() must be the first statement; if no explicit call, the compiler inserts super() with no args, which fails if the superclass has no no-arg constructor.
Access from another package: protected members are reachable only through inheritance (via a subclass reference), not through an instance of the superclass.
An object's runtime type determines which overridden instance method runs; field access and static members use the declared reference type.
Object contract: equals/hashCode must agree; toString, equals, and hashCode are the commonly overridden methods from java.lang.Object.
Advanced Java Class Design
An abstract class may have zero abstract methods; a class with at least one abstract method must be declared abstract and cannot be instantiated.
An interface method without a body is implicitly public abstract; fields in an interface are implicitly public static final.
A class may implement multiple interfaces but extend only one class; an interface may extend multiple interfaces.
An abstract method cannot be private, static, or final; it may be protected or public (or default/package).
An anonymous inner class is created with new Type() { ... }; it cannot declare a constructor and captures effectively final local variables.
A static nested class has no implicit outer-instance reference; a non-static inner class does and cannot declare static members except constant variables.
A local class declared in a method may access effectively final locals of that method; a variable is effectively final if assigned once and never reassigned.
enum: implicitly extends java.lang.Enum, cannot extend anything else, may implement interfaces, and its constructors are implicitly private.
Overloading is resolved at compile time by reference type; overriding is resolved at runtime by object type.
Generics and Collections
Generics are erased at compile time: List and List share one runtime class, so instanceof List is illegal and overloads differing only in type parameters do not compile.
Wildcards: List<? extends Number> is a read-only view (can get a Number, cannot add except null); List<? super Integer> is write-oriented (can add Integer, get returns Object).
Type parameter bounds: <T extends Comparable<? super T>> allows T or any supertype to supply the comparison; a class bound may be followed by interface bounds.
List: ArrayList is array-backed with O(1) get and O(n) middle insert; LinkedList is node-based with O(1) ends and O(n) index access. Both allow duplicates and preserve insertion order.
Set: HashSet has no order; LinkedHashSet keeps insertion order; TreeSet is sorted by natural order or Comparator and rejects elements that compare as equal.
Map: HashMap has no order; LinkedHashMap keeps insertion order; TreeMap is sorted by key; all three reject duplicate keys, and Map does not extend Collection.
Queue/Deque: ArrayDeque and LinkedList support addFirst/addLast/pollFirst; PriorityQueue orders by natural order or Comparator and its iterator does not guarantee sorted order.
Comparable declares compareTo(T) for natural ordering; Comparator declares compare(T,T), usable with lambda (a,b) -> a.getX() - b.getX() or Comparator.comparing.
equals/hashCode must be consistent for HashMap/HashSet keys; mutating a key after insertion makes it unreachable. Arrays.asList is fixed-size; List.of is immutable.
Lambda Built-in Functional Interfaces
Functional interface: exactly one abstract method (default and static methods do not count); @FunctionalInterface makes the compiler enforce this.
Function<T,R>: R apply(T); BiFunction<T,U,R>: R apply(T,U); UnaryOperator and BinaryOperator are Function/BiFunction specializations with identical types.
Predicate: boolean test(T); BiPredicate<T,U>; Supplier: T get() (no input); Consumer: void accept(T); BiConsumer<T,U>.
Primitive specializations avoid boxing: IntFunction, ToIntFunction, IntPredicate, IntSupplier, IntUnaryOperator, IntBinaryOperator.
Method references: Type::staticMethod, instance::instanceMethod, Type::instanceMethod (first arg is the receiver), and Type::new for constructors.
A lambda can use local variables only if they are effectively final; instance and static fields are unrestricted.
Target typing: the same lambda can implement different functional interfaces depending on context; a lambda cannot be assigned to Object or to an ambiguous overload.
Comparator.comparing, thenComparing, reversed, and Predicate.and/or/negate/ isEqual return composed lambdas usable in streams.
Java Stream API
Stream pipeline = source + zero or more intermediate operations (lazy, return a Stream) + one terminal operation (triggers execution, returns non-Stream).
A stream can be consumed once; reusing it throws IllegalStateException. Streams are built from collection.stream(), Arrays.stream, Stream.of, IntStream.range.
Intermediate: filter, map, mapToInt, flatMap, distinct, sorted, limit, skip, peek. Terminal: forEach, collect, reduce, count, min, max, anyMatch, allMatch, noneMatch, findFirst, findAny.
collect(Collectors.toList()/toSet()/toMap()/joining()/groupingBy()/partitioningBy()/counting()/summingInt()); toMap throws IllegalStateException on duplicate keys unless a merge function is supplied.
Optional: isPresent, ifPresent(Consumer), orElse, orElseGet(Supplier), orElseThrow, map, filter; get() throws NoSuchElementException when empty.
Lazy evaluation: without a terminal operation, no intermediate operation runs; peek is for debugging and may be skipped in short-circuiting pipelines.
flatMap flattens Stream<Stream> or Stream<List> into Stream; map produces one output per input.
Sorting a stream of Comparable elements uses natural order; sorted(Comparator) for custom order; primitive streams (IntStream) offer sum, average, summaryStatistics.
Exceptions and Assertions
Throwable branches into Error (unrecoverable, unchecked) and Exception; RuntimeException and its subclasses are unchecked; all other Exceptions are checked.
A checked exception must be caught or declared with throws; an unchecked exception need not be, though it may be.
try/catch/finally: finally runs even after return or throw, except System.exit; if finally returns, it discards the pending return/exception.
Multi-catch: catch (IOException | SQLException e) - the parameter is implicitly final and the alternatives must not be related by subclassing.
try-with-resources: resources must implement AutoCloseable; they are closed in reverse order of declaration; a suppressed exception is attached via getSuppressed().
Overriding method may throw fewer or narrower checked exceptions, but not broader ones; it may throw any unchecked exception.
Custom checked exception extends Exception; custom unchecked extends RuntimeException. Constructors typically chain cause via super(message, cause).
assert statement: assert cond; or assert cond : detail; disabled by default, enabled with -ea; an AssertionError is thrown and assertions should not have side effects.
Using the Java I/O API
Byte streams: InputStream/OutputStream (FileInputStream, BufferedInputStream, ByteArrayInputStream); character streams: Reader/Writer (FileReader, BufferedReader, PrintWriter).
Buffering wraps a node stream: new BufferedReader(new FileReader(f)); readLine() returns null at end of stream.
Serialization: class must implement java.io.Serializable; transient and static fields are not serialized; serialVersionUID guards compatibility.
ObjectOutputStream.writeObject / ObjectInputStream.readObject; a NotSerializableException occurs if any non-transient field is not serializable.
Console I/O: System.in/out/err; System.console() returns null when no interactive console is attached (e.g., in many IDEs).
File class represents a path name, not file content; useful methods: exists, isDirectory, listFiles, mkdirs, delete, length.
Close streams in finally or use try-with-resources; closing a wrapper closes the underlying stream; most read/write methods throw IOException.
Concurrency
Thread creation: extend Thread and override run, or implement Runnable and pass to new Thread(r); start() launches a new thread, run() executes on the caller thread.
Thread states: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED; getState() reports them.
synchronized guards a monitor: on an instance method the lock is this; on a static method it is the Class object; on a block it is the given object.
wait/notify/notifyAll must be called while holding the object's monitor, otherwise IllegalMonitorStateException; use in a while loop to guard against spurious wakeups.
ExecutorService from Executors.newFixedThreadPool/newSingleThreadExecutor; submit returns Future, execute returns void; shutdown() stops new tasks, shutdownNow() interrupts.
Callable returns V and may throw checked exceptions; Future.get() blocks and throws ExecutionException wrapping the task's exception.
Atomic classes (AtomicInteger) and java.util.concurrent collections (ConcurrentHashMap, CopyOnWriteArrayList) provide thread-safe alternatives.
Deadlock requires two locks acquired in opposite order; avoid by consistent lock ordering or a single lock. volatile guarantees visibility, not atomicity.
Building Database Applications with JDBC
DriverManager.getConnection(url, user, password); URL forms: jdbc:derby://host:port/db, jdbc:mysql://host/db, jdbc:oracle:thin:@host:port:sid.
Statement for static SQL; PreparedStatement for parameterized SQL with ? placeholders, preventing SQL injection and enabling reuse; CallableStatement for stored procedures.
ResultSet cursor starts before the first row; iterate with while (rs.next()); read columns by index (1-based) or by label.
executeQuery returns ResultSet (SELECT); executeUpdate returns int row count (INSERT/UPDATE/DELETE) or 0 for DDL; execute returns boolean indicating a ResultSet.
Resource order: Connection -> Statement -> ResultSet; close in reverse order or use try-with-resources since all implement AutoCloseable.
ResultSetMetaData (from rs.getMetaData()) gives getColumnCount and getColumnLabel; DatabaseMetaData describes the database itself.
Transactions: setAutoCommit(false), then commit() or rollback(); default is auto-commit true, so each statement commits immediately.
SQLException is checked; getMessage, getSQLState, getErrorCode, and getNextException expose chained errors.
Localization
Locale formats: language lowercase, country uppercase (en_US, fr_FR, ja_JP); Locale.getDefault() and Locale.forLanguageTag("en-US").
ResourceBundle.getBundle("baseName", locale) loads baseName_language_country.properties, then baseName_language, then baseName, then the default locale bundle.
Properties files are ISO-8859-1 by default; use \uXXXX escapes or a PropertyResourceBundle with an explicit Reader for other encodings.
Missing key: ResourceBundle throws MissingResourceException; getString returns String, getObject returns Object; use containsKey to test.
MessageFormat.format("Hello {0}, {1}", name, date) supports numbered placeholders and choice/date/number formats.
NumberFormat.getCurrencyInstance(locale), getNumberInstance, getPercentInstance; DecimalFormat applies custom patterns like #,##0.00.
DateFormat.getDateInstance(style, locale) with styles SHORT/MEDIUM/LONG/FULL; SimpleDateFormat uses pattern letters (yyyy, MM, dd, HH, mm, ss).
Locale.Category.DISPLAY vs FORMAT controls which default locale is used for display text versus formatting.
Java File I/O (NIO.2)
Path is an interface; obtain with Paths.get("a","b") or FileSystems.getDefault().getPath(...); it is immutable and does not touch the file system.
Files.exists, isDirectory, isRegularFile, size, delete, deleteIfExists, createDirectory, createDirectories, copy, move - most throw IOException.
Files.readAllLines(path) returns List; Files.readAllBytes returns byte[]; Files.write(path, lines) writes with default UTF-8.
Files.walk(path) and Files.find(path, maxDepth, predicate) return Stream; must be closed (try-with-resources).
Files.newBufferedReader(path) / newBufferedWriter(path) give character streams; Files.newInputStream/newOutputStream give byte streams.
Files.list returns a lazy Stream of directory entries; DirectoryStream via Files.newDirectoryStream supports glob patterns like "*.java".
Path methods: getFileName, getParent, getRoot, resolve, relativize, normalize, toAbsolutePath, toRealPath; Files.isSameFile compares content/location.
FileVisitor / SimpleFileVisitor with Files.walkFileTree performs recursive traversal; visitFile, preVisitDirectory, postVisitDirectory, visitFileFailed.
Java Date/Time API
Core types are immutable and thread-safe: LocalDate (date), LocalTime (time), LocalDateTime (both), ZonedDateTime (with zone), Instant (epoch), Duration (time-based), Period (date-based).
now() uses the system clock and default zone; of(y,m,d) validates values (Month is 1-12; invalid dates throw DateTimeException).
Formatting: DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") and predefined constants like ISO_LOCAL_DATE; parse with LocalDate.parse(text, formatter).
plus/minus return new instances (immutable); with(field, value) adjusts; Period.ofDays(3) adds date units, Duration.ofHours(2) adds time units.
ZonedDateTime handles DST; atZone(zone) attaches a zone; withZoneSameInstant preserves the instant while changing the zone.
Instant is a point on the timeline; toEpochMilli and ofEpochSecond convert; Instant plus Duration is valid, Instant plus Period is not.
Duration.between(t1, t2) and Period.between(d1, d2) measure differences; ChronoUnit.DAYS.between(d1, d2) returns a long.
Old/new bridge: Date.toInstant(), Instant.atZone(zone).toLocalDateTime(), and GregorianCalendar.toZonedDateTime() convert between legacy and java.time.
Java Class Design
Encapsulation: private fields + public accessors; a public setter on a private field does not make the field read-only.
An overridden method cannot reduce visibility: public > protected > default (package) > private; private methods are not inherited and cannot be overridden.
Covariant return types are allowed: an override may return a subtype of the superclass return type.
final method: cannot be overridden; final class: cannot be extended; final variable: assigned exactly once (blank final must be assigned in every constructor or initializer).
static methods are hidden, not overridden; the version invoked depends on the reference type, not the object type.
Constructor rules: super()/this() must be the first statement; if no explicit call, the compiler inserts super() with no args, which fails if the superclass has no no-arg constructor.
Access from another package: protected members are reachable only through inheritance (via a subclass reference), not through an instance of the superclass.
An object's runtime type determines which overridden instance method runs; field access and static members use the declared reference type.
Object contract: equals/hashCode must agree; toString, equals, and hashCode are the commonly overridden methods from java.lang.Object.
Advanced Java Class Design
An abstract class may have zero abstract methods; a class with at least one abstract method must be declared abstract and cannot be instantiated.
An interface method without a body is implicitly public abstract; fields in an interface are implicitly public static final.
A class may implement multiple interfaces but extend only one class; an interface may extend multiple interfaces.
An abstract method cannot be private, static, or final; it may be protected or public (or default/package).
An anonymous inner class is created with new Type() { ... }; it cannot declare a constructor and captures effectively final local variables.
A static nested class has no implicit outer-instance reference; a non-static inner class does and cannot declare static members except constant variables.
A local class declared in a method may access effectively final locals of that method; a variable is effectively final if assigned once and never reassigned.
enum: implicitly extends java.lang.Enum, cannot extend anything else, may implement interfaces, and its constructors are implicitly private.
Overloading is resolved at compile time by reference type; overriding is resolved at runtime by object type.
Generics and Collections
Generics are erased at compile time: List and List share one runtime class, so instanceof List is illegal and overloads differing only in type parameters do not compile.
Wildcards: List<? extends Number> is a read-only view (can get a Number, cannot add except null); List<? super Integer> is write-oriented (can add Integer, get returns Object).
Type parameter bounds: <T extends Comparable<? super T>> allows T or any supertype to supply the comparison; a class bound may be followed by interface bounds.
List: ArrayList is array-backed with O(1) get and O(n) middle insert; LinkedList is node-based with O(1) ends and O(n) index access. Both allow duplicates and preserve insertion order.
Set: HashSet has no order; LinkedHashSet keeps insertion order; TreeSet is sorted by natural order or Comparator and rejects elements that compare as equal.
Map: HashMap has no order; LinkedHashMap keeps insertion order; TreeMap is sorted by key; all three reject duplicate keys, and Map does not extend Collection.
Queue/Deque: ArrayDeque and LinkedList support addFirst/addLast/pollFirst; PriorityQueue orders by natural order or Comparator and its iterator does not guarantee sorted order.
Comparable declares compareTo(T) for natural ordering; Comparator declares compare(T,T), usable with lambda (a,b) -> a.getX() - b.getX() or Comparator.comparing.
equals/hashCode must be consistent for HashMap/HashSet keys; mutating a key after insertion makes it unreachable. Arrays.asList is fixed-size; List.of is immutable.
Lambda Built-in Functional Interfaces
Functional interface: exactly one abstract method (default and static methods do not count); @FunctionalInterface makes the compiler enforce this.
Function<T,R>: R apply(T); BiFunction<T,U,R>: R apply(T,U); UnaryOperator and BinaryOperator are Function/BiFunction specializations with identical types.
Predicate: boolean test(T); BiPredicate<T,U>; Supplier: T get() (no input); Consumer: void accept(T); BiConsumer<T,U>.
Primitive specializations avoid boxing: IntFunction, ToIntFunction, IntPredicate, IntSupplier, IntUnaryOperator, IntBinaryOperator.
Method references: Type::staticMethod, instance::instanceMethod, Type::instanceMethod (first arg is the receiver), and Type::new for constructors.
A lambda can use local variables only if they are effectively final; instance and static fields are unrestricted.
Target typing: the same lambda can implement different functional interfaces depending on context; a lambda cannot be assigned to Object or to an ambiguous overload.
Comparator.comparing, thenComparing, reversed, and Predicate.and/or/negate/isEqual return composed lambdas usable in streams.
Java Stream API
Stream pipeline = source + zero or more intermediate operations (lazy, return a Stream) + one terminal operation (triggers execution, returns non-Stream).
A stream can be consumed once; reusing it throws IllegalStateException. Streams are built from collection.stream(), Arrays.stream, Stream.of, IntStream.range.
Intermediate: filter, map, mapToInt, flatMap, distinct, sorted, limit, skip, peek. Terminal: forEach, collect, reduce, count, min, max, anyMatch, allMatch, noneMatch, findFirst, findAny.
collect(Collectors.toList()/toSet()/toMap()/joining()/groupingBy()/partitioningBy()/counting()/summingInt()); toMap throws IllegalStateException on duplicate keys unless a merge function is supplied.
Optional: isPresent, ifPresent(Consumer), orElse, orElseGet(Supplier), orElseThrow, map, filter; get() throws NoSuchElementException when empty.
Lazy evaluation: without a terminal operation, no intermediate operation runs; peek is for debugging and may be skipped in short-circuiting pipelines.
flatMap flattens Stream<Stream> or Stream<List> into Stream; map produces one output per input.
Sorting a stream of Comparable elements uses natural order; sorted(Comparator) for custom order; primitive streams (IntStream) offer sum, average, summaryStatistics.
Exceptions and Assertions
Throwable branches into Error (unrecoverable, unchecked) and Exception; RuntimeException and its subclasses are unchecked; all other Exceptions are checked.
A checked exception must be caught or declared with throws; an unchecked exception need not be, though it may be.
try/catch/finally: finally runs even after return or throw, except System.exit; if finally returns, it discards the pending return/exception.
Multi-catch: catch (IOException | SQLException e) - the parameter is implicitly final and the alternatives must not be related by subclassing.
try-with-resources: resources must implement AutoCloseable; they are closed in reverse order of declaration; a suppressed exception is attached via getSuppressed().
Overriding method may throw fewer or narrower checked exceptions, but not broader ones; it may throw any unchecked exception.
Custom checked exception extends Exception; custom unchecked extends RuntimeException. Constructors typically chain cause via super(message, cause).
assert statement: assert cond; or assert cond : detail; disabled by default, enabled with -ea; an AssertionError is thrown and assertions should not have side effects.
Using the Java I/O API
Byte streams: InputStream/OutputStream (FileInputStream, BufferedInputStream, ByteArrayInputStream); character streams: Reader/Writer (FileReader, BufferedReader, PrintWriter).
Buffering wraps a node stream: new BufferedReader(new FileReader(f)); readLine() returns null at end of stream.
Serialization: class must implement java.io.Serializable; transient and static fields are not serialized; serialVersionUID guards compatibility.
ObjectOutputStream.writeObject / ObjectInputStream.readObject; a NotSerializableException occurs if any non-transient field is not serializable.
Console I/O: System.in/out/err; System.console() returns null when no interactive console is attached (e.g., in many IDEs).
File class represents a path name, not file content; useful methods: exists, isDirectory, listFiles, mkdirs, delete, length.
Close streams in finally or use try-with-resources; closing a wrapper closes the underlying stream; most read/write methods throw IOException.
Concurrency
Thread creation: extend Thread and override run, or implement Runnable and pass to new Thread(r); start() launches a new thread, run() executes on the caller thread.
Thread states: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED; getState() reports them.
synchronized guards a monitor: on an instance method the lock is this; on a static method it is the Class object; on a block it is the given object.
wait/notify/notifyAll must be called while holding the object's monitor, otherwise IllegalMonitorStateException; use in a while loop to guard against spurious wakeups.
ExecutorService from Executors.newFixedThreadPool/newSingleThreadExecutor; submit returns Future, execute returns void; shutdown() stops new tasks, shutdownNow() interrupts.
Callable returns V and may throw checked exceptions; Future.get() blocks and throws ExecutionException wrapping the task's exception.
Atomic classes (AtomicInteger) and java.util.concurrent collections (ConcurrentHashMap, CopyOnWriteArrayList) provide thread-safe alternatives.
Deadlock requires two locks acquired in opposite order; avoid by consistent lock ordering or a single lock. volatile guarantees visibility, not atomicity.
Building Database Applications with JDBC
DriverManager.getConnection(url, user, password); URL forms: jdbc:derby://host:port/db, jdbc:mysql://host/db, jdbc:oracle:thin:@host:port:sid.
Statement for static SQL; PreparedStatement for parameterized SQL with ? placeholders, preventing SQL injection and enabling reuse; CallableStatement for stored procedures.
ResultSet cursor starts before the first row; iterate with while (rs.next()); read columns by index (1-based) or by label.
executeQuery returns ResultSet (SELECT); executeUpdate returns int row count (INSERT/UPDATE/DELETE) or 0 for DDL; execute returns boolean indicating a ResultSet.
Resource order: Connection -> Statement -> ResultSet; close in reverse order or use try-with-resources since all implement AutoCloseable.
ResultSetMetaData (from rs.getMetaData()) gives getColumnCount and getColumnLabel; DatabaseMetaData describes the database itself.
Transactions: setAutoCommit(false), then commit() or rollback(); default is auto-commit true, so each statement commits immediately.
SQLException is checked; getMessage, getSQLState, getErrorCode, and getNextException expose chained errors.
Localization
Locale formats: language lowercase, country uppercase (en_US, fr_FR, ja_JP); Locale.getDefault() and Locale.forLanguageTag("en-US").
ResourceBundle.getBundle("baseName", locale) loads baseName_language_country.properties, then baseName_language, then baseName, then the default locale bundle.
Properties files are ISO-8859-1 by default; use \uXXXX escapes or a PropertyResourceBundle with an explicit Reader for other encodings.
Missing key: ResourceBundle throws MissingResourceException; getString returns String, getObject returns Object; use containsKey to test.
MessageFormat.format("Hello {0}, {1}", name, date) supports numbered placeholders and choice/date/number formats.
NumberFormat.getCurrencyInstance(locale), getNumberInstance, getPercentInstance; DecimalFormat applies custom patterns like #,##0.00.
DateFormat.getDateInstance(style, locale) with styles SHORT/MEDIUM/LONG/FULL; SimpleDateFormat uses pattern letters (yyyy, MM, dd, HH, mm, ss).
Locale.Category.DISPLAY vs FORMAT controls which default locale is used for display text versus formatting.
Java File I/O (NIO.2)
Path is an interface; obtain with Paths.get("a","b") or FileSystems.getDefault().getPath(...); it is immutable and does not touch the file system.
Files.exists, isDirectory, isRegularFile, size, delete, deleteIfExists, createDirectory, createDirectories, copy, move - most throw IOException.
Files.readAllLines(path) returns List; Files.readAllBytes returns byte[]; Files.write(path, lines) writes with default UTF-8.
Files.walk(path) and Files.find(path, maxDepth, predicate) return Stream; must be closed (try-with-resources).
Files.newBufferedReader(path) / newBufferedWriter(path) give character streams; Files.newInputStream/newOutputStream give byte streams.
Files.list returns a lazy Stream of directory entries; DirectoryStream via Files.newDirectoryStream supports glob patterns like "*.java".
Path methods: getFileName, getParent, getRoot, resolve, relativize, normalize, toAbsolutePath, toRealPath; Files.isSameFile compares content/location.
FileVisitor / SimpleFileVisitor with Files.walkFileTree performs recursive traversal; visitFile, preVisitDirectory, postVisitDirectory, visitFileFailed.
Java Date/Time API
Core types are immutable and thread-safe: LocalDate (date), LocalTime (time), LocalDateTime (both), ZonedDateTime (with zone), Instant (epoch), Duration (time-based), Period (date-based).
now() uses the system clock and default zone; of(y,m,d) validates values (Month is 1-12; invalid dates throw DateTimeException).
Formatting: DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") and predefined constants like ISO_LOCAL_DATE; parse with LocalDate.parse(text, formatter).
plus/minus return new instances (immutable); with(field, value) adjusts; Period.ofDays(3) adds date units, Duration.ofHours(2) adds time units.
ZonedDateTime handles DST; atZone(zone) attaches a zone; withZoneSameInstant preserves the instant while changing the zone.
Instant is a point on the timeline; toEpochMilli and ofEpochSecond convert; Instant plus Duration is valid, Instant plus Period is not.
Duration.between(t1, t2) and Period.between(d1, d2) measure differences; ChronoUnit.DAYS.between(d1, d2) returns a long.
Old/new bridge: Date.toInstant(), Instant.atZone(zone).toLocalDateTime(), and GregorianCalendar.toZonedDateTime() convert between legacy and java.time.