Java logoJavav25INTERMEDIATE

Java

Core Java language reference - syntax, OOP, generics, collections, streams, and modern Java 25 features.

15 min read
javajvmoopbackendstreamscollections

Sign in to mark items as known and track your progress.

Sign in

Getting Started

Your first program, compiling, and running Java.

Hello World

The classic entry point, plus the simplified launch form finalized in Java 25.

java
// Quick Reference
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}
💡 Class name must match the file name for a public class (Main -> Main.java).
⚡ System.out.println() prints with a trailing newline; use print() without.
📌 Java 25 compact source files let beginners skip the class/static/args boilerplate.
🟢 %n is the platform-independent newline in printf, preferred over \n.
basicsmain

Compile & Run

Compile to bytecode, run, or launch a single file directly.

java
// Quick Reference
javac Main.java   // compile -> Main.class
java Main         // run the class (no .class extension)
java Main.java    // compile + run a single file in one step
💡 java Main runs a compiled class; java Main.java compiles and runs in one shot.
⚡ jshell is a built-in REPL for testing snippets without a full program.
📌 Bytecode (.class) runs on any JVM - "write once, run anywhere".
🟢 Use Javadoc /** */ comments to document public APIs for tooling.
clicompile

Variables & Data Types

Primitives, type inference, constants, and wrappers.

Primitive Types

Java's eight built-in value types.

java
// Quick Reference
int i = 42;
long l = 42L;
double d = 3.14;
float f = 3.14f;
boolean b = true;
char c = 'A';
💡 int and double are the defaults; long needs L and float needs f suffixes.
⚡ char uses single quotes; double quotes always make a String, never a char.
📌 Primitives hold values directly and cannot be null (unlike wrapper objects).
🟢 Underscores in literals (1_000_000) are ignored by the compiler, purely visual.
typesprimitives

var, final & Wrappers

Local type inference, constants, casting, and boxed types.

java
// Quick Reference
var name = "Sam";        // inferred as String
final int MAX = 100;     // constant, cannot reassign
Integer boxed = 42;      // wrapper object (nullable)
💡 var only works for local variables with an initializer, not fields or params.
⚡ Wrapper types (Integer, Double) can be null; primitives cannot.
📌 Prefer primitives for performance; use wrappers when you need null or generics.
🟢 Narrowing casts (double -> int) truncate and must be explicit with (type).
varfinalwrappers

Operators

Arithmetic, comparison, logical, and type checks.

Operators

Everyday operators plus the ternary and instanceof pattern.

java
// Quick Reference
+  -  *  /  %          // arithmetic
== != <  >  <= >=      // comparison
&& ||  !               // logical
condition ? a : b      // ternary
💡 Integer division drops the remainder; make one operand a double for real division.
⚡ && and || short-circuit - the right side is skipped when the result is known.
📌 instanceof pattern binds a typed variable, removing the manual cast.
🟢 Use == for primitives, but .equals() to compare object contents like Strings.
operatorsinstanceof

Math & Numbers

The Math class, parsing, exact decimals, and randomness.

Math, Parsing & BigDecimal

Common numeric operations and gotchas.

java
// Quick Reference
Math.max(3, 7);   Math.abs(-5);   Math.pow(2, 10);
Math.sqrt(16);    Math.round(3.6);
int n = Integer.parseInt("42");
💡 Floating-point math is inexact - use BigDecimal (from a String) for money.
⚡ Compare BigDecimals with compareTo(); equals() also checks scale (2.0 != 2.00).
📌 Integer.parseInt(s, radix) parses binary/hex/octal; parseInt throws on bad input.
🟢 Math.round returns long/int; Math.floor/ceil return double.
mathbigdecimalparsing

Strings & Text Blocks

Working with text, builders, and multi-line strings.

String Methods

Common operations on immutable strings.

java
// Quick Reference
s.length()          s.charAt(0)
s.toUpperCase()     s.trim()  s.strip()
s.substring(1, 4)   s.split(",")
s.contains("x")     s.replace("a", "b")
💡 Strings are immutable - every "modifying" method returns a brand-new String.
⚡ Use .equals() (or .equalsIgnoreCase()) for content comparison, never ==.
📌 strip() is Unicode-aware; trim() only removes ASCII whitespace <= U+0020.
🟢 isBlank() checks for empty-or-whitespace; isEmpty() only checks length 0.
stringsmethods

StringBuilder & Text Blocks

Efficient concatenation, multi-line text, and formatting.

java
// Quick Reference
var sb = new StringBuilder();
sb.append("a").append("b");
String out = sb.toString();

String json = """
    { "name": "Sam" }
    """;                 // text block
💡 Build strings in loops with StringBuilder - "+" in a loop creates many objects.
⚡ Text blocks strip incidental indentation based on the closing """ position.
📌 "template".formatted(args) is a concise instance-method alternative to String.format.
🟢 %s (string), %d (integer), %f (float), %n (newline) are the common format specifiers.
stringbuildertext-blocks

Regular Expressions

Matching, capturing groups, and replacing with regex.

Pattern & Matcher

Java regex via String helpers and the Pattern/Matcher API.

java
// Quick Reference
"abc123".matches("[a-z]+\\d+");     // true (whole string)
"a1b2".replaceAll("\\d", "#");       // "a#b#"
"a,b;c".split("[,;]");               // ["a", "b", "c"]
💡 In Java source, regex backslashes are doubled: \d for a digit, \s for whitespace.
⚡ String.matches() must match the ENTIRE string; Matcher.find() matches any substring.
📌 Compile a Pattern once and reuse it in loops - compiling is relatively expensive.
🟢 Groups are 1-indexed; group(0) (or group()) is the full match.
regexpattern

Control Flow

Branching, modern switch, and loops.

Conditionals & Switch

if/else and switch expressions with pattern matching.

java
// Quick Reference
if (x > 0) { ... } else if (x < 0) { ... } else { ... }

String r = switch (day) {
    case 6, 7 -> "weekend";
    default   -> "weekday";
};
💡 Arrow-form switch has no fall-through and needs no break statements.
⚡ switch can be an expression that returns a value - use yield inside a block.
📌 Pattern matching (case Type t) plus when guards replaces long if-else chains.
🟢 A pattern switch can handle null directly with a case null branch.
conditionalsswitch

Loops

for, enhanced for, while, and do-while.

java
// Quick Reference
for (int i = 0; i < 5; i++) { ... }
for (String s : list) { ... }     // enhanced for
while (cond) { ... }
do { ... } while (cond);
💡 Prefer the enhanced for (for-each) when you do not need the index.
⚡ do-while always executes the body at least once before checking the condition.
📌 Labeled break/continue targets an outer loop - handy for nested iteration.
🟢 continue skips to the next iteration; break exits the loop entirely.
loopsiteration

Methods

Defining behavior, overloading, and varargs.

Methods

Parameters, return types, overloading, and varargs.

java
// Quick Reference
returnType name(params) { ... return value; }
void greet(String n) { ... }        // no return value
int add(int... nums) { ... }        // varargs
💡 Overloading distinguishes methods by parameter types, not by return type.
⚡ Varargs (int...) must be the last parameter and behaves like an array inside.
📌 static methods belong to the class (Util.triple); instance methods need an object.
🟢 Java passes arguments by value - object references are copied, not the objects.
methodsvarargs

Classes & Records

Objects, constructors, encapsulation, and records.

Classes & Constructors

Fields, constructors, this, and access modifiers.

java
// Quick Reference
class Person {
    private String name;
    Person(String name) { this.name = name; }
    String getName() { return name; }
}
var p = new Person("Sam");
💡 this refers to the current object - it disambiguates fields from parameters.
⚡ this(...) chains to another constructor in the same class to avoid duplication.
📌 Access modifiers: private (class), default (package), protected (subclass), public.
🟢 Keep fields private and expose behavior through methods (encapsulation).
classesconstructors

Static Members & Records

Class-level members and concise immutable data carriers.

java
// Quick Reference
static int count = 0;          // shared across all instances
static final double PI = 3.14; // constant

record Point(int x, int y) {}  // immutable data class
💡 static members belong to the class itself and are shared by every instance.
⚡ Records auto-generate the constructor, accessors, equals, hashCode, and toString.
📌 Record accessors are named after the field: point.x(), not point.getX().
🟢 Records are immutable and final - ideal for DTOs, keys, and value objects.
staticrecords

Inheritance & Interfaces

Reuse, polymorphism, contracts, and sealed hierarchies.

Inheritance & Abstract Classes

extends, super, overriding, and abstract base classes.

java
// Quick Reference
class Dog extends Animal {
    @Override
    void speak() { System.out.println("Woof"); }
}
abstract class Animal { abstract void speak(); }
💡 super(...) calls the parent constructor and must be the first statement.
⚡ @Override is optional but lets the compiler catch signature mistakes.
📌 Abstract classes can mix abstract and concrete methods and hold state.
🟢 Polymorphism: a parent-typed reference dispatches to the actual subclass method.
inheritanceabstract

Interfaces & Sealed Classes

Contracts with default methods and restricted hierarchies.

java
// Quick Reference
interface Shape {
    double area();                 // abstract
    default String label() { return "shape"; } // default method
}
sealed interface Expr permits Num, Add {}
💡 A class implements many interfaces but extends only one class.
⚡ default methods add behavior to an interface without breaking implementers.
📌 sealed + permits locks a hierarchy so switch can be exhaustive with no default.
🟢 Interface methods are public and abstract by default; fields are public static final.
interfacessealed

Enums

Type-safe sets of named constants.

Enums

Simple constants and enums with fields and methods.

java
// Quick Reference
enum Day { MON, TUE, WED }
Day d = Day.MON;
switch (d) { case MON -> ...; }
💡 Enums are type-safe - the compiler rejects any value outside the defined set.
⚡ Enum constructors are implicitly private and run once per constant.
📌 values() returns all constants; valueOf(name) parses one (throws if not found).
🟢 Give enums fields and methods to attach data and behavior to each constant.
enumsconstants

Annotations

Built-in markers and defining your own.

Built-in & Custom Annotations

The common annotations plus a custom one read via reflection.

java
// Quick Reference
@Override            // method overrides a supertype method
@Deprecated          // API is obsolete
@FunctionalInterface // exactly one abstract method
@SuppressWarnings("unchecked")
💡 @Override is optional but lets the compiler catch signature typos in overrides.
⚡ @Retention(RUNTIME) is required to read an annotation via reflection at runtime.
📌 @Target restricts where an annotation may be applied (METHOD, TYPE, FIELD, ...).
🟢 Annotation elements look like methods; value() is special and can be set positionally.
annotationsreflection

Generics

Type-safe, reusable classes and methods.

Generics

Generic classes, methods, bounds, and wildcards.

java
// Quick Reference
class Box<T> { T value; }
<T> T first(List<T> list) { return list.get(0); }
List<? extends Number> nums;   // wildcard
💡 Generics give compile-time type safety and remove manual casts.
⚡ <T extends Number> bounds the type so you can call Number methods on T.
📌 Use ? extends for reading (producers), ? super for writing (consumers) - PECS.
🟢 Type parameters are erased at runtime (type erasure) - no new T() or T.class.
genericswildcards

Arrays & Collections

Fixed arrays plus the core List, Map, and Set types.

Arrays

Fixed-size sequences and the Arrays utility class.

java
// Quick Reference
int[] nums = {1, 2, 3};
int[] zeros = new int[5];
nums.length;            // 3
Arrays.sort(nums);
💡 Array length is fixed at creation and read via .length (a field, no parentheses).
⚡ Arrays.toString() prints contents; plain toString() prints a memory hash.
📌 Accessing an out-of-range index throws ArrayIndexOutOfBoundsException.
🟢 For a resizable sequence, reach for ArrayList instead of a raw array.
arrays

List (ArrayList)

The most-used resizable, ordered collection.

java
// Quick Reference
List<String> list = new ArrayList<>();
list.add("a");  list.get(0);
list.remove("a");  list.size();
var fixed = List.of("x", "y");   // immutable
💡 Program to the List interface; swap ArrayList for LinkedList without changing callers.
⚡ List.of(...) creates a compact immutable list - great for constants.
📌 remove(int) removes by index; remove(Object) removes by value - watch Integer lists.
🟢 The diamond <> on the right infers the type: new ArrayList<>().
listarraylist

Map & Set

Key-value pairs and unique collections.

java
// Quick Reference
Map<String, Integer> m = new HashMap<>();
m.put("a", 1);  m.get("a");
Set<String> set = new HashSet<>();
set.add("x");   set.contains("x");
💡 HashMap keys are unique - putting an existing key overwrites its value.
⚡ getOrDefault and merge make counting and accumulation one-liners.
📌 HashMap/HashSet are unordered; use LinkedHashMap or TreeMap for ordering.
🟢 Iterate a Map via entrySet() to access keys and values together.
mapset

Exception Handling

Catching, throwing, and cleaning up resources.

Exceptions

try/catch/finally, resources, and custom exceptions.

java
// Quick Reference
try {
    risky();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    cleanup();
}
💡 Checked exceptions (IOException) must be caught or declared with throws.
⚡ try-with-resources auto-closes anything implementing AutoCloseable - no finally needed.
📌 finally always runs - use it for cleanup, but prefer try-with-resources for closing.
🟢 Extend RuntimeException for unchecked custom errors; Exception for checked ones.
exceptionstry-catch

Lambdas & Functional Interfaces

First-class behavior with lambdas and method references.

Lambdas & Method References

Concise functions and the built-in functional interfaces.

java
// Quick Reference
Runnable r = () -> System.out.println("hi");
Function<Integer, Integer> sq = x -> x * x;
list.forEach(System.out::println);   // method reference
💡 A lambda can target any interface with exactly one abstract method (@FunctionalInterface).
⚡ Method references (Class::method) are shorthand for lambdas that just call one method.
📌 Predicate<T> -> boolean, Function<T,R> -> R, Consumer<T> -> void, Supplier<T> -> value.
🟢 Lambdas can capture effectively-final local variables from the enclosing scope.
lambdasfunctional

Streams & Optional

Declarative data pipelines and null-safe containers.

Streams API

Transform and aggregate collections functionally.

java
// Quick Reference
list.stream()
    .filter(x -> x > 2)
    .map(x -> x * 10)
    .toList();
💡 Streams are lazy - nothing runs until a terminal operation like toList() or count().
⚡ .toList() (Java 16+) is the concise replacement for .collect(Collectors.toList()).
📌 Use mapToInt/mapToDouble for numeric streams with sum(), average(), and range helpers.
🟢 A stream is single-use; create a fresh one for each pipeline you run.
streamsfunctional

Collectors & Optional

Grouping, joining, and null-safe results.

java
// Quick Reference
stream.collect(Collectors.groupingBy(fn));
stream.collect(Collectors.joining(", "));
Optional<T> o = ...;  o.orElse(fallback);
💡 Optional signals "value may be absent" - a safer API than returning null.
⚡ groupingBy and partitioningBy turn a stream into a Map in one collector.
📌 Prefer orElse/orElseGet/map over calling get(), which throws when empty.
🟢 Optional.ofNullable wraps a possibly-null value; Optional.empty() is the absent case.
collectorsoptional

Concurrency

Threads, synchronization, executors, and virtual threads.

Threads & Synchronization

Creating threads and guarding shared state.

java
// Quick Reference
Thread t = new Thread(() -> System.out.println("run"));
t.start();
t.join();                 // wait for it to finish
synchronized void inc() { count++; }
💡 Call start() (not run()) to launch a new thread; run() executes on the current one.
⚡ synchronized prevents race conditions on shared mutable state.
📌 volatile ensures a written value is visible to other threads, but is not atomic.
🟢 Thread.sleep and join throw InterruptedException - handle or declare it.
threadssynchronized

Executors & Virtual Threads

Thread pools, futures, and lightweight virtual threads (21+).

java
// Quick Reference
try (var ex = Executors.newVirtualThreadPerTaskExecutor()) {
    ex.submit(() -> handle());
}
Thread.startVirtualThread(() -> work());   // Java 21+
💡 Prefer an ExecutorService over creating raw Threads - it manages pooling and lifecycle.
⚡ Virtual threads (Java 21+) are lightweight - block freely on I/O without exhausting the pool.
📌 Future.get() blocks until the result is ready (or throws if the task failed).
🟢 ExecutorService is AutoCloseable since Java 19 - try-with-resources awaits and shuts down.
executorsvirtual-threads

Date & Time

The modern immutable java.time API.

java.time

Dates, times, instants, durations, and formatting.

java
// Quick Reference
LocalDate today = LocalDate.now();
LocalDateTime dt = LocalDateTime.now();
today.plusDays(7);
today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
💡 Use java.time (LocalDate, LocalDateTime) - the old Date and Calendar are legacy.
⚡ All java.time types are immutable; plusDays/minusHours return new instances.
📌 Duration measures time (hours/seconds); Period measures dates (years/months/days).
🟢 Instant is a UTC machine timestamp; LocalDateTime has no zone - pair it with ZoneId.
datetimejava-time

File I/O

Reading and writing files with the NIO API.

Files & Paths

Modern file reading and writing with java.nio.

java
// Quick Reference
Path p = Path.of("data.txt");
String text = Files.readString(p);
Files.writeString(p, "hello");
List<String> lines = Files.readAllLines(p);
💡 Files.readString / writeString (Java 11+) handle small files in a single call.
⚡ For large files use Files.lines() in try-with-resources so the stream closes.
📌 Path.of(...) is the modern replacement for the older new File(...) API.
🟢 Files I/O throws IOException (checked) - handle or declare it with throws.
file-ionio

Modern Java (25)

Language features finalized in and around today's LTS.

Records & Pattern Matching

Deconstruct records and match by shape.

java
// Quick Reference
record Point(int x, int y) {}

String s = switch (obj) {
    case Point(int x, int y) -> x + "," + y; // record pattern
    default -> "other";
};
💡 Record patterns destructure a record into its components inline - no accessors.
⚡ Patterns nest: match a Line and pull out both Points and their coordinates at once.
📌 var inside a pattern infers each component type, keeping matches concise.
🟢 Sealed types + record patterns give the compiler exhaustiveness checks in switch.
recordspattern-matching

New in Java 25

Finalized features that simplify everyday code.

java
// Quick Reference
void main() {                 // compact source file (JEP 512)
    IO.println("Hi!");
}
import module java.base;      // module import (JEP 511)
💡 Java 25 is the current LTS (Sept 2025) - these features are final, not preview.
⚡ Compact source files remove class/static/String[] boilerplate for scripts and learning.
📌 java.lang.IO (println/readln) is auto-imported in compact source files.
🟢 Flexible constructor bodies let you validate arguments before calling super().
java25modern