Java Tutorial
Learn Java
Modern Java 25 for back-end developers, from your first program to production APIs.
Stage 1
01
Getting Started
02
Variables and Types
03
Control Flow
04
Strings and Text
05
Methods
Stage 2
06
Classes and Objects
07
Inheritance and Interfaces
08
Records, Enums and Sealed Types
09
Exceptions
10
Packages and Modules
Stage 3
11
Collections
12
Generics
13
Lambdas and Functional Interfaces
14
Streams
15
Dates and Times
Stage 4
16
Working with Data
17
HTTP in Java
18
Building a REST API by Hand
19
Databases with JDBC
Stage 5
20
Concurrency
21
Testing
22
Build Tools
23
Logging and Configuration
Stage 6
24
Security Essentials
25
The JVM and Performance
26
Modern Java (21 to 25 and Beyond)
Stage 7
Java Reference
101 pages · 10 groups · syntax, parameters and worked examples
java.lang.String14
length()Returns the number of UTF-16 code units in a String, which is not always the number of characters a person sees.charAt()Reads the single char at a zero-based index, and throws StringIndexOutOfBoundsException when the index is outside the String.substring()Copies part of a String between a start index (inclusive) and an end index (exclusive) into a new String.indexOf()Finds the index of the first match of a char or substring, from the start or a given position, and returns -1 when there is none.contains()Returns true when a String includes a given sequence of chars anywhere, with an exact, case-sensitive comparison.startsWith() and endsWith()Test whether a String begins or ends with given text, the cheap and readable way to check prefixes, suffixes and file extensions.replace() and replaceAll()replace() swaps every occurrence of literal text; replaceAll() and replaceFirst() treat the first argument as a regular expression.split()Splits a String around matches of a regular expression into an array, with a limit that controls how many parts and empty trailing fields you get.strip(), trim() and isBlank()Remove leading and trailing whitespace and test for whitespace-only input, and know why strip() and isBlank() beat trim() for Unicode text.toUpperCase() and toLowerCase()Convert case with an explicit Locale, and avoid the Turkish-i and German-sharp-s bugs that the default locale causes.equals() and equalsIgnoreCase()Compare String content with equals() or ignore case with equalsIgnoreCase(), and avoid == and the NullPointerException traps.String.join()Joins strings from varargs or any Iterable with a delimiter between them, with no trailing separator to trim off.repeat()Returns the String repeated a given number of times, the Java 11 replacement for padding loops and hand-built separator lines.chars()Streams the chars of a String as an IntStream for counting, checking and grouping, and shows when codePoints() is the right call instead.
java.util.List12
List.of()Creates a compact, unmodifiable list in one expression, and rejects nulls so bad data fails early.add()Appends an element or inserts it at a position, and explains why add sometimes throws instead of growing the list.get()Reads the element at a zero-based index, with the bounds rules and the LinkedList cost that catch people out.set()Replaces the element at an index and returns the old one, without changing the size of the list.remove()Removes by index or by value, and avoids the Integer overload trap and the exception from removing inside a loop.contains()Tests whether a list holds an equal element, and shows when equals, boxing or list size make the answer wrong or slow.indexOf()Finds the position of the first (or, with lastIndexOf, the last) equal element, returning -1 when there is none.size() and isEmpty()Counts the elements in a list and checks for an empty one, plus the null-versus-empty and capacity mistakes around them.sort()Sorts a list in place with a Comparator, stably, and shows why it fails on List.of and returns nothing.subList()Returns a live view of a range of a list, for paging, chunking and range deletes, with the rules that keep it valid.getFirst() and getLast()Reads the first or last element directly (Java 21), and shows how they fail on empty lists compared with get(0).reversed()Returns a reverse-ordered view of a list (Java 21) without copying, and how it differs from Collections.reverse.
java.util.Map12
Map.of()Create a small unmodifiable map in one expression, and know why it rejects nulls, duplicate keys and any later change.put()Add or replace a mapping, and use the returned previous value to tell a fresh insert from an overwrite in one lookup.get()Look up a value by key, handle the null it returns for a miss, and avoid the wrong-key-type trap the compiler does not catch.getOrDefault()Read a value with a fallback for missing keys, and avoid the three traps: null values, eager defaults and defaults that are never stored.containsKey()Check whether a key is present, tell a missing key from a null value, and avoid the double lookup and race of check-then-get.remove()Delete a mapping by key or by key and value, and remove entries safely while iterating without a ConcurrentModificationException.putIfAbsent()Store a value only when the key is free, read the existing value from the result, and know when computeIfAbsent is the better tool.computeIfAbsent()Get a value or create it on first use in one call, for grouping into lists and caching, without breaking the map from inside the function.merge()Insert a value or combine it with the existing one in a single call, for counters, totals and reference counts.entrySet()Iterate keys and values together without extra lookups, update values in place, and sort or filter a map through its entries.forEach()Run an action for every key and value with a lambda, and know when a plain loop or replaceAll is the better choice.keySet() and values()Get a map's keys or values as live views, know what removing through them does, and copy them before handing them to other code.
java.util.Optional8
Optional.of() and Optional.ofNullable()Wrap a value in an Optional, choosing of() when null is a bug and ofNullable() when null means the value is genuinely absent.Optional.empty()Return an empty Optional instead of null so callers handle the not-found case with the same methods they use for a value.isPresent() and isEmpty()Test whether an Optional holds a value, and know when a plain boolean check is right and when map or orElse reads better.orElse() and orElseGet()Unwrap an Optional with a fallback, and use orElseGet when the fallback is expensive, because orElse evaluates its argument every time.orElseThrow()Unwrap an Optional or throw: a NoSuchElementException by default, or your own not-found exception that becomes a 404.map()Transform the value inside an Optional without unwrapping it, so a missing value flows through the chain as empty instead of null.flatMap()Chain steps that each return an Optional, such as one lookup feeding the next, without ending up with Optional<Optional<T>>.ifPresent() and ifPresentOrElse()Run an action only when an Optional holds a value, or pick between two actions, without unwrapping it by hand.
java.util.stream.Stream14
Stream.of()Create a sequential, ordered stream from a few values or an object array, and avoid the primitive-array trap that gives you a stream of one element.filter()Keep only the elements that match a predicate, without touching the source collection, and know when filtering belongs in the database instead.map()Transform each element into exactly one new value, such as an entity into a response DTO, and use the primitive variants to avoid boxing.flatMap()Turn each element into a stream of zero or more values and join them into one flat stream, such as all line items across a list of orders.sorted()Sort stream elements by natural order or by a Comparator, with tie-breakers, reversed order and nulls handled, and know what sorting costs.distinct()Remove duplicate elements by equals and hashCode while keeping the first occurrence, and de-duplicate by a key when whole objects differ.limit() and skip()Take the first n elements or drop them, page through in-memory results, and cut infinite streams short, with takeWhile and dropWhile for condition-based cuts.collect()Turn a stream into a set, map, string or grouped summary with a Collector, and know when toList() or the three-argument form fits better.toList()Collect a stream straight into an unmodifiable List, and know how it differs from Collectors.toList() and Collectors.toUnmodifiableList().reduce()Fold a stream into a single value with an identity and an associative function, and know when sum(), max() or collect() is the better tool.count()Count the elements of a stream as a long, understand why it may skip your pipeline, and avoid counting when you only need to know if anything matches.anyMatch(), allMatch() and noneMatch()Answer yes-or-no questions about a stream with short-circuiting checks, and remember what each returns for an empty stream.findFirst()Get the first element of a stream as an Optional, turn a missing result into a 404, and know when findAny or min is the better choice.iterate() and generate()Build streams from a seed and a step function or from a supplier, stop them with a condition or a limit, and use them for sequences, retries and paging.
java.util.stream.Collectors8
Collectors.toMap()Turns a stream into a Map with a key and value function, and shows how to handle duplicate keys, null values and the map type.Collectors.groupingBy()Groups stream elements into a Map by a key, with a downstream collector per group and a choice of map type.Collectors.partitioningBy()Splits a stream into the elements that match a predicate and those that do not, with both groups always present.Collectors.joining()Concatenates stream elements into one String, with an optional delimiter, prefix and suffix.Collectors.counting()Counts the elements of a stream or of each group, and explains the Long result and when Stream.count() is the better call.Collectors.summingInt() and averagingDouble()Totals and averages a numeric field per stream or per group, and covers int overflow, the 0.0 average of an empty group and money.Collectors.mapping()Transforms each element before a downstream collector sees it, so groups hold just the field you need instead of whole objects.Collectors.toSet()Collects a stream into a Set of distinct elements, and shows how to choose ordering and mutability instead of relying on defaults.
java.time9
LocalDate.now() and LocalDate.of()Get today's date for a given zone or clock, and build a specific calendar date that is validated as it is created.LocalDate.parse()Turn a date string such as 2026-07-04 into a LocalDate, use a custom format when needed, and turn bad input into a clean 400.plusDays() and minusDays()Move a date forward or back by whole days, keep the result, and know how day arithmetic behaves around month ends and clock changes.Instant.now()Capture the current moment as a UTC timestamp for logs, records and expiry checks, and make it testable with a Clock.Duration.between()Measure the exact time between two instants or times as a Duration, and read it out in hours, minutes or milliseconds.Period.between()Get the calendar gap between two dates as years, months and days, the right tool for ages, tenures and subscription terms.DateTimeFormatter.ofPattern()Build a formatter from a pattern such as dd MMM uuuu, pass a Locale, and avoid the pattern-letter mix-ups that print the wrong year.ZonedDateTime.withZoneSameInstant()Show the same moment in another time zone, such as a UTC timestamp in a user's local time, and know how it differs from withZoneSameLocal.ChronoUnit.between()Count the whole days, weeks, months or hours between two dates or times as a single number, with truncation you can predict.
java.net.http8
HttpClient.newHttpClient()Create an HttpClient with default settings in one call, and know exactly which defaults (no redirects, no timeouts) you are accepting.HttpClient.newBuilder()Configure an HttpClient's connect timeout, redirects, HTTP version, executor and cookies before building it once and sharing it.HttpRequest.newBuilder()Build an immutable HttpRequest with its URI, method, headers and per-request timeout, and avoid the headers and URIs the builder rejects.HttpRequest.BodyPublishers.ofString()Send a String as the request body for POST, PUT or PATCH, with the right Content-Type and a byte-accurate Content-Length.HttpClient.send()Send a request and block until the response arrives, and handle the exceptions it throws and the error statuses it does not.HttpClient.sendAsync()Send a request without blocking and get a CompletableFuture of the response, then combine, transform and recover from calls in a pipeline.HttpResponse.BodyHandlers.ofString()Read a whole response body as a String decoded with the server's charset, and know when to cap it or use a streaming handler instead.HttpResponse.statusCode() and headers()Read the status code and response headers of an HttpResponse, with case-insensitive lookups, repeated headers and numeric values.
java.nio.file.Files10
Files.readString()Read a whole small file into one String in a single call, choose the right charset, and know when the file is too big for it.Files.writeString()Write text to a file in one call, control create, overwrite and append with open options, and avoid half-written files.Files.readAllLines()Load a small text file as a List of lines with any line ending handled for you, ready for filtering, parsing or indexing.Files.lines()Stream a file line by line with flat memory use, close it correctly, and handle the UncheckedIOException it throws mid-stream.Files.exists()Test whether a path exists or is a file or directory, understand the third answer it can hide, and avoid check-then-act races.Files.createDirectories()Create a directory and any missing parents in one call that is safe to repeat, and see how it differs from createDirectory.Files.list() and Files.walk()List a directory's entries or walk a whole tree as a Stream of Paths, filter by type and name, and close the stream.Files.copy() and Files.move()Copy and move files with explicit replace and atomic options, save an upload stream to disk, and know what copying a directory does.Files.delete() and deleteIfExists()Delete files and empty directories, choose between failing and ignoring a missing file, and remove a whole tree safely.Path.of() and resolve()Build file paths from parts, join them with resolve, normalise them, and keep user-supplied names inside the directory you meant.
java.util.Objects6
Objects.equals()Compare two values that may be null without writing null checks or risking a NullPointerException.Objects.hash()Build a hashCode from several fields in one line, null-safe and consistent with an equals that compares the same fields.Objects.requireNonNull()Fail fast with a clear NullPointerException when a required argument or dependency is null, at the point the mistake is made.Objects.requireNonNullElse()Swap a null for a default value in one call, with requireNonNullElseGet when the default is costly to create.Objects.isNull() and nonNull()Use Objects::nonNull and Objects::isNull as ready-made predicates to drop or count nulls in streams and collections.Objects.toString()Turn any value, including null, into a string without a NullPointerException, and choose what null should print as.