Toolmingo
Guides11 min read

Java Cheat Sheet: Syntax, OOP, Collections & Streams

A complete Java cheat sheet — variables, OOP, generics, collections, streams, exceptions, concurrency, and common patterns with copy-ready examples for Java 17+.

Java is a statically typed, object-oriented language that runs on the JVM. This cheat sheet covers Java 17+ — from primitives and OOP to Streams, Records, and concurrency — with copy-ready examples for everyday development.

Quick reference

The 25 patterns that cover 95% of everyday Java development.

Pattern Example
Variable int x = 42;
String String s = "hello";
Array int[] arr = {1, 2, 3};
ArrayList List<String> list = new ArrayList<>();
HashMap Map<String, Integer> map = new HashMap<>();
For-each for (String item : list) { }
Stream filter list.stream().filter(s -> s.length() > 3)
Stream map .map(String::toUpperCase).toList()
Optional Optional.ofNullable(value).orElse("default")
Lambda Runnable r = () -> System.out.println("hi");
Method reference list.forEach(System.out::println)
Record record Point(int x, int y) {}
Switch expression int val = switch (day) { case MON -> 1; ... };
Try-with-resources try (var in = new FileInputStream(f)) { }
String format "Hello %s, you are %d".formatted(name, age)
String join String.join(", ", list)
var (local inference) var items = new ArrayList<String>();
instanceof pattern if (obj instanceof String s) { use(s); }
Sealed class sealed interface Shape permits Circle, Rect {}
Text block `String json = """ {"key":"val"} """;`
Comparator list.sort(Comparator.comparing(Person::name))
Collectors .collect(Collectors.groupingBy(String::length))
CompletableFuture CompletableFuture.supplyAsync(() -> fetch())
Synchronized synchronized (lock) { /* critical section */ }
Interface default default void greet() { System.out.println("hi"); }

Variables and types

// Primitives
int     count  = 42;
long    big    = 10_000_000L;
double  price  = 9.99;
boolean active = true;
char    ch     = 'A';

// Reference types
String  name   = "Alice";
Integer boxed  = 100;          // auto-boxing from int

// Local type inference (Java 10+)
var list = new ArrayList<String>();
var map  = new HashMap<String, Integer>();

// Constants
final int MAX_SIZE = 100;
static final double PI = 3.14159;

// Type casting
double d = 3.7;
int    i = (int) d;            // 3 — truncates, not rounds

// String to number
int    parsed  = Integer.parseInt("42");
double parsedD = Double.parseDouble("3.14");

// Number to string
String s = String.valueOf(42);
String s2 = Integer.toString(42);

Strings

String s = "Hello, World!";

// Common methods
s.length()                     // 13
s.toUpperCase()                // "HELLO, WORLD!"
s.toLowerCase()                // "hello, world!"
s.trim()                       // strips leading/trailing whitespace
s.strip()                      // Unicode-aware (Java 11+)
s.isEmpty()                    // false
s.isBlank()                    // false (Java 11+)
s.contains("World")            // true
s.startsWith("Hello")          // true
s.endsWith("!")                // true
s.indexOf("o")                 // 4
s.lastIndexOf("o")             // 8
s.substring(7, 12)             // "World"
s.replace("World", "Java")     // "Hello, Java!"
s.replaceAll("\\d+", "#")      // regex replace
s.split(", ")                  // ["Hello", "World!"]
s.charAt(0)                    // 'H'
String.join("-", "a", "b")     // "a-b"

// String.format / formatted (Java 15+)
String msg = "Name: %s, Age: %d, Score: %.2f".formatted("Alice", 30, 9.5);

// Text blocks (Java 15+)
String json = """
    {
        "name": "Alice",
        "age": 30
    }
    """;

// StringBuilder for concatenation in loops
StringBuilder sb = new StringBuilder();
for (String item : items) {
    sb.append(item).append(", ");
}
String result = sb.toString();

// Comparison — NEVER use == for strings
"hello".equals(s)              // correct
"hello".equalsIgnoreCase(s)    // case-insensitive
s.compareTo("hello")           // lexicographic

Arrays

// Declaration and initialization
int[] nums   = {1, 2, 3, 4, 5};
String[] arr = new String[3];   // null, null, null

// Access
int first = nums[0];
int last  = nums[nums.length - 1];

// Iterate
for (int n : nums) System.out.println(n);

// Sort and search
Arrays.sort(nums);
int idx = Arrays.binarySearch(nums, 3);  // requires sorted

// Copy
int[] copy = Arrays.copyOf(nums, nums.length);
int[] slice = Arrays.copyOfRange(nums, 1, 4);  // [2, 3, 4]

// 2D array
int[][] matrix = new int[3][3];
matrix[0][0] = 1;

// Array to string (for printing)
System.out.println(Arrays.toString(nums));         // [1, 2, 3, 4, 5]
System.out.println(Arrays.deepToString(matrix));   // 2D arrays

Collections

List

// ArrayList — indexed, allows duplicates
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
list.add("d");
list.add(0, "z");          // insert at index
list.remove("b");          // by value
list.remove(0);            // by index
list.get(1);               // "b"
list.size();               // 3
list.contains("c");        // true
list.indexOf("c");         // 1
list.isEmpty();            // false
Collections.sort(list);
list.sort(Comparator.reverseOrder());

// Immutable list (Java 9+)
List<String> fixed = List.of("x", "y", "z");

// LinkedList — efficient head/tail ops
Deque<String> deque = new LinkedList<>();
deque.addFirst("first");
deque.addLast("last");
deque.pollFirst();

Map

// HashMap — no order guarantee
Map<String, Integer> map = new HashMap<>();
map.put("alice", 90);
map.put("bob",   85);
map.getOrDefault("charlie", 0);   // 0 — safe get
map.putIfAbsent("alice", 100);    // won't override
map.containsKey("bob");           // true
map.remove("bob");
map.size();                       // 1

// Iterate
for (Map.Entry<String, Integer> e : map.entrySet()) {
    System.out.println(e.getKey() + " = " + e.getValue());
}
map.forEach((k, v) -> System.out.println(k + " = " + v));

// Merge and compute
map.merge("alice", 5, Integer::sum);         // alice=95
map.computeIfAbsent("dave", k -> 0);         // init if missing

// LinkedHashMap — insertion order
Map<String, Integer> ordered = new LinkedHashMap<>();

// TreeMap — sorted by key
Map<String, Integer> sorted = new TreeMap<>();

// Immutable map (Java 9+)
Map<String, Integer> fixed = Map.of("a", 1, "b", 2);

Set

Set<String> set = new HashSet<>(List.of("a", "b", "c"));
set.add("d");
set.contains("a");     // true
set.remove("b");
set.size();            // 3

// Set operations
Set<String> other = new HashSet<>(Set.of("c", "d", "e"));
set.retainAll(other);  // intersection: {c, d}
set.addAll(other);     // union
set.removeAll(other);  // difference

// TreeSet — sorted
Set<Integer> sorted = new TreeSet<>(List.of(3, 1, 2));  // [1, 2, 3]

OOP — Classes and interfaces

// Class with constructor
public class Person {
    private final String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age  = age;
    }

    public String name() { return name; }
    public int    age()  { return age;  }

    @Override
    public String toString() {
        return "Person{name='%s', age=%d}".formatted(name, age);
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Person p)) return false;
        return age == p.age && name.equals(p.name);
    }

    @Override public int hashCode() {
        return Objects.hash(name, age);
    }
}

// Inheritance
public class Employee extends Person {
    private final String role;

    public Employee(String name, int age, String role) {
        super(name, age);
        this.role = role;
    }

    @Override public String toString() {
        return super.toString() + ", role=" + role;
    }
}

// Interface
public interface Drawable {
    void draw();                           // abstract
    default String color() { return "black"; }  // default impl
    static Drawable noop() { return () -> {}; } // static factory
}

// Record — immutable data class (Java 16+)
record Point(double x, double y) {
    // Compact constructor for validation
    Point {
        if (x < 0 || y < 0) throw new IllegalArgumentException("negative");
    }

    double distanceTo(Point other) {
        return Math.hypot(x - other.x, y - other.y);
    }
}

// Sealed interface (Java 17+)
sealed interface Shape permits Circle, Rectangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double w, double h) implements Shape {}

// Pattern matching with switch (Java 21 — preview in 17)
double area(Shape s) {
    return switch (s) {
        case Circle c     -> Math.PI * c.radius() * c.radius();
        case Rectangle r  -> r.w() * r.h();
    };
}

// Enum
public enum Status {
    PENDING, ACTIVE, CLOSED;

    public boolean isTerminal() {
        return this == CLOSED;
    }
}

Generics

// Generic class
public class Pair<A, B> {
    private final A first;
    private final B second;

    public Pair(A first, B second) {
        this.first = first; this.second = second;
    }
    public A first()  { return first;  }
    public B second() { return second; }
}

// Generic method
public <T extends Comparable<T>> T max(T a, T b) {
    return a.compareTo(b) >= 0 ? a : b;
}

// Bounded wildcards
void printAll(List<? extends Number> nums) { /* read-only */ }
void addNumbers(List<? super Integer> list) { list.add(42); }

// PECS: Producer Extends, Consumer Super

Streams (Java 8+)

List<String> words = List.of("apple", "banana", "cherry", "avocado");

// filter + map + collect
List<String> result = words.stream()
    .filter(w -> w.startsWith("a"))
    .map(String::toUpperCase)
    .sorted()
    .toList();                            // ["APPLE", "AVOCADO"]

// reduce
int total = List.of(1, 2, 3, 4, 5).stream()
    .reduce(0, Integer::sum);             // 15

// count, min, max
long count = words.stream().filter(w -> w.length() > 5).count();
Optional<String> longest = words.stream()
    .max(Comparator.comparingInt(String::length));

// flatMap
List<List<Integer>> nested = List.of(List.of(1,2), List.of(3,4));
List<Integer> flat = nested.stream()
    .flatMap(Collection::stream)
    .toList();                            // [1, 2, 3, 4]

// groupingBy
Map<Integer, List<String>> byLength = words.stream()
    .collect(Collectors.groupingBy(String::length));

// joining
String joined = words.stream()
    .collect(Collectors.joining(", ", "[", "]"));  // [apple, banana, ...]

// partitioningBy
Map<Boolean, List<String>> parts = words.stream()
    .collect(Collectors.partitioningBy(w -> w.length() > 5));

// IntStream, LongStream, DoubleStream
int sum = IntStream.rangeClosed(1, 100).sum();     // 5050
double avg = IntStream.of(1,2,3,4,5).average().orElse(0.0);

// Parallel stream (use for CPU-bound, large datasets only)
words.parallelStream().filter(w -> isExpensive(w)).toList();

Optional (Java 8+)

Optional<String> opt = Optional.ofNullable(getValue());

// Access
opt.isPresent()                         // true/false
opt.isEmpty()                           // Java 11+
opt.get()                               // throws if empty — avoid
opt.orElse("default")
opt.orElseGet(() -> computeDefault())   // lazy
opt.orElseThrow(() -> new IllegalStateException("missing"))

// Transform
Optional<Integer> len = opt.map(String::length);
Optional<String>  upper = opt.map(String::toUpperCase);
Optional<String>  filtered = opt.filter(s -> s.length() > 3);

// flatMap — when the function already returns Optional
Optional<String> city = findUser(id)
    .flatMap(user -> findAddress(user))
    .map(Address::city);

Exception handling

// Checked vs unchecked
// - Checked (must catch or declare): IOException, SQLException
// - Unchecked (RuntimeException): NullPointerException, IllegalArgumentException

// Try-catch-finally
try {
    int result = Integer.parseInt(input);
} catch (NumberFormatException e) {
    System.err.println("Bad input: " + e.getMessage());
} catch (Exception e) {
    e.printStackTrace();
} finally {
    // always runs
}

// Try-with-resources (auto-close)
try (var reader = new BufferedReader(new FileReader("file.txt"))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    throw new RuntimeException("Failed to read file", e);
}

// Custom exception
public class NotFoundException extends RuntimeException {
    private final String id;
    public NotFoundException(String id) {
        super("Not found: " + id);
        this.id = id;
    }
    public String id() { return id; }
}

// Multi-catch
try {
    // ...
} catch (IOException | SQLException e) {
    log.error("Data error", e);
}

Lambdas and functional interfaces

// Built-in functional interfaces
Function<String, Integer>   f  = String::length;        // T -> R
Consumer<String>            c  = System.out::println;   // T -> void
Supplier<String>            s  = () -> "hello";         // () -> T
Predicate<String>           p  = str -> str.isEmpty();  // T -> boolean
BiFunction<String, Integer, String> bi = String::repeat;

// Compose functions
Function<Integer, Integer> times2 = x -> x * 2;
Function<Integer, Integer> plus3  = x -> x + 3;
Function<Integer, Integer> combined = times2.andThen(plus3);  // (x*2)+3
Function<Integer, Integer> composed = times2.compose(plus3);  // (x+3)*2

// Predicate composition
Predicate<String> notEmpty = Predicate.not(String::isEmpty);
Predicate<String> longWord = s2 -> s2.length() > 5;
Predicate<String> both = notEmpty.and(longWord);

Concurrency basics

// Thread creation
Thread t = new Thread(() -> System.out.println("Running in thread"));
t.start();
t.join();     // wait for completion

// ExecutorService (preferred over raw threads)
ExecutorService exec = Executors.newFixedThreadPool(4);
Future<Integer> future = exec.submit(() -> computeResult());
int result = future.get();    // blocks until done
exec.shutdown();

// CompletableFuture (Java 8+)
CompletableFuture<String> cf = CompletableFuture
    .supplyAsync(() -> fetchData())
    .thenApply(String::toUpperCase)
    .thenApply(s -> "Result: " + s)
    .exceptionally(ex -> "Error: " + ex.getMessage());

// Combine multiple futures
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<String> combined = f1.thenCombine(f2, (a, b) -> a + " " + b);

// Virtual threads (Java 21)
Thread.ofVirtual().start(() -> handleRequest());
ExecutorService vExec = Executors.newVirtualThreadPerTaskExecutor();

// Synchronized block
private final Object lock = new Object();
synchronized (lock) {
    // critical section
}

// Atomic variables
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet();
counter.compareAndSet(expected, newValue);

// ConcurrentHashMap
ConcurrentHashMap<String, Integer> safeMap = new ConcurrentHashMap<>();
safeMap.compute("key", (k, v) -> v == null ? 1 : v + 1);

Common mistakes

Mistake Problem Fix
str1 == str2 Compares references, not content str1.equals(str2)
int / int integer division 5 / 2 = 2 not 2.5 Cast: (double) 5 / 2 or 5.0 / 2
Modifying list in for-each ConcurrentModificationException Use Iterator or removeIf
Optional.get() without check Throws NoSuchElementException Use orElse / orElseThrow
Mutable object in HashMap key Key hash changes, value lost Use immutable keys (String, record)
Not closing streams/connections Resource leak Use try-with-resources
parallelStream() everywhere Overhead outweighs benefit Only for large datasets, CPU-bound work

Java version quick reference

Feature Java version
Lambdas, Streams, Optional Java 8
var local type inference Java 10
String.isBlank(), strip() Java 11
switch expressions Java 14
Records Java 16
Sealed classes Java 17 (LTS)
Virtual threads Java 21 (LTS)
Pattern matching switch Java 21

Frequently asked questions

What is the difference between == and .equals() in Java?
== compares object references (memory addresses). .equals() compares object content. For strings and objects, always use .equals(). For primitives (int, char, etc.), == compares values directly.

When should I use ArrayList vs LinkedList?
Use ArrayList (the default) for almost everything — it has O(1) random access and cache-friendly memory. Use LinkedList only when you frequently insert/remove at both ends and never need random access. In practice, ArrayList wins for most use cases.

What is the difference between Comparable and Comparator?
Comparable is implemented by the class itself (natural ordering via compareTo). Comparator is an external comparison strategy. Use Comparator.comparing() to sort without modifying the class — useful for multiple sort orders.

What is autoboxing and when does it cause problems?
Autoboxing is automatic conversion between primitives (int) and wrapper types (Integer). It causes problems when comparing boxed integers with == (use .equals()), when null unboxing throws NullPointerException, and in tight loops where boxing/unboxing adds overhead.

What is the difference between throws and throw?
throw triggers an exception: throw new RuntimeException("msg"). throws declares that a method may throw a checked exception: void read() throws IOException. Unchecked exceptions (subclasses of RuntimeException) don't need to be declared.

What is the difference between Runnable and Callable?
Runnable has a run() method that returns void and can't throw checked exceptions. Callable<T> has call() that returns T and can throw checked exceptions. Use Callable with ExecutorService.submit() when you need a result or exception propagation.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools