Basics & Syntax, OOP, Collections Framework, Exceptions, Streams & Lambdas, Concurrency, JVM Internals — Java mastery.
// ── Primitive Types ──
byte b = 127; // 8-bit (-128 to 127)
short s = 32767; // 16-bit (-32768 to 32767)
int i = 2147483647; // 32-bit
long l = 9223372036854775807L; // 64-bit (use L suffix)
float f = 3.14f; // 32-bit (use f suffix)
double d = 3.14159; // 64-bit
boolean bool = true; // true or false
char c = 'A'; // 16-bit Unicode
// ── Type Inference (var, Java 10+) ──
var name = "Alice"; // Inferred as String
var list = new ArrayList<String>();
var stream = list.stream(); // Inferred as Stream<String>
// ── String ──
String s1 = "hello";
String s2 = new String("hello"); // different object
s1.equals(s2); // true (value comparison)
s1 == s2; // false (reference comparison)
s1.length(); // 5
s1.substring(1, 4); // "ell"
s1.toUpperCase(); // "HELLO"
s1.strip(); // trim whitespace (Java 11+)
s1.isBlank(); // true if empty or whitespace
s1.repeat(3); // "hellohellohello"
s1.lines().toList(); // Stream<String> split by lines
s1.formatted("Hi %s, age %d", "Alice", 30);
// ── Text Blocks (Java 15+) ──
String json = """
{
"name": "%s",
"age": %d
}
""".formatted(name, age).stripIndent();
// ── Arrays ──
int[] nums = {1, 2, 3, 4, 5};
int[] nums2 = new int[10];
int[][] matrix = {{1,2}, {3,4}};
Arrays.sort(nums);
Arrays.stream(nums).sum();
Arrays.asList(1, 2, 3);
// ── Switch Expression (Java 14+) ──
String result = switch (day) {
case MONDAY, FRIDAY -> "Working day";
case SATURDAY, SUNDAY -> "Weekend";
default -> "Unknown";
};
// ── Pattern Matching for switch (Java 21+) ──
String formatted = switch (obj) {
case Integer i -> "Int: " + i;
case String s when s.length() > 5 -> "Long string: " + s;
case String s -> "String: " + s;
case null -> "null";
default -> "Unknown";
};
// ── Records (Java 16+) ──
record Point(int x, int y) {}
Point p = new Point(3, 4);
p.x(); // 3
p.toString(); // "Point[x=3, y=4]"
p.equals(new Point(3, 4)); // true (auto-generated)
// ── Sealed Classes (Java 17+) ──
sealed interface Shape permits Circle, Rectangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double w, double h) implements Shape {}
double area = switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.w() * r.h();
// no default needed — exhaustive
};| Version | Key Features |
|---|---|
| Java 8 | Lambdas, Streams, Optional, Date-Time API, default methods |
| Java 9 | Modules (Jigsaw), jshell, private interface methods, HTTP Client |
| Java 10 | var (local-variable type inference) |
| Java 11 | HTTP Client (standard), String::lines(), Files::readString() |
| Java 14 | Switch expressions, Records preview, NullPointerException |
| Java 15 | Text blocks, sealed classes preview, hidden classes |
| Java 16 | Records, pattern matching for instanceof |
| Java 17 | Sealed classes, pattern matching for switch, pseudo-random |
| Java 18 | Simple web server, code snippets in API docs |
| Java 19 | Virtual threads preview, structured concurrency preview |
| Java 21 | Pattern matching for switch, record patterns, virtual threads, sequenced collections |
| Java 22 | Unnamed variables & patterns, statements before super(), stream gatherers |
| Modifier | Class | Package | Subclass | World |
|---|---|---|---|---|
| public | Yes | Yes | Yes | Yes |
| protected | Yes | Yes | Yes | No |
| (default) | Yes | Yes | No | No |
| private | Yes | No | No | No |
// ── Abstract Class ──
public abstract class Animal {
protected String name;
private int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public abstract void speak(); // Must be implemented
public final void describe() { // Cannot be overridden
System.out.println(name + " is " + age + " years old");
}
}
// ── Interface (Java 8+ default & static methods) ──
public interface Flyable {
void fly();
default void glide() {
System.out.println("Gliding...");
}
static void describe() {
System.out.println("I can fly!");
}
}
// ── Implementation with multiple interfaces ──
public class Dog extends Animal implements Flyable, Comparable<Dog> {
public Dog(String name, int age) {
super(name, age);
}
@Override
public void speak() {
System.out.println(name + " says: Woof!");
}
@Override
public void fly() {
System.out.println(name + " is flying (somehow)!");
}
@Override
public int compareTo(Dog other) {
return this.name.compareTo(other.name);
}
}
// ── Enum (with fields and methods) ──
public enum Status {
ACTIVE(1), INACTIVE(0), PENDING(2);
private final int code;
Status(int code) { this.code = code; }
public int getCode() { return code; }
}
// ── Enum implementing interface ──
public interface Describable {
String description();
}
public enum Priority implements Describable {
LOW { public String description() { return "Low priority"; } },
HIGH { public String description() { return "High priority"; } };
}
// ── Nested Classes ──
public class Outer {
private String outer = "outer";
// Static nested class (no access to instance members)
public static class StaticNested {
void run() { System.out.println("static nested"); }
}
// Inner class (has access to outer instance)
public class Inner {
void run() { System.out.println(outer); } // accesses outer field
}
// Anonymous class
public Runnable getTask() {
return new Runnable() {
@Override
public void run() {
System.out.println("Running from anonymous class");
}
};
}
// Local class (inside method)
public void process() {
class Local {
void help() { System.out.println(outer); }
}
new Local().help();
}
}
// ── Generics ──
public class Box<T> {
private T value;
public void set(T value) { this.value = value; }
public T get() { return value; }
// Bounded type parameter
public static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) >= 0 ? a : b;
}
}
// ── Wildcards
public static void printAll(List<?> list) { } // any type
public static void addDogs(List<? super Dog> list) { } // Dog or supertype
public static void readDogs(List<? extends Dog> list) { } // Dog or subtype| Principle | Description | Java Mechanism |
|---|---|---|
| Encapsulation | Hide internal state | private fields + getters/setters |
| Inheritance | Reuse and extend behavior | extends (single class), implements (multiple interfaces) |
| Polymorphism | One interface, multiple implementations | Method overriding, interfaces, generics |
| Abstraction | Hide complexity, show essentials | abstract classes, interfaces |
| Method | Purpose | Contract |
|---|---|---|
| equals() | Value equality | Reflexive, symmetric, transitive, consistent, null returns false |
| hashCode() | Hash for collections | Must be consistent with equals: a.equals(b) => a.hashCode() == b.hashCode() |
| toString() | String representation | Format: ClassName[field1=val1, field2=val2] |
| compareTo() | Natural ordering | Consistent with equals (recommended but not required) |
| clone() | Copy object | Must implement Cloneable; prefer copy constructor |
// ── List (ordered, allows duplicates) ──
List<String> list = new ArrayList<>();
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
List<String> immutable = List.of("a", "b", "c"); // immutable (Java 9+)
List<String> copyList = List.copyOf(existingList); // defensive copy
list.add("hello");
list.add(0, "first"); // insert at index
list.addAll(otherList);
list.get(0); // "first"
list.set(0, "new"); // replace
list.remove(0); // remove by index
list.remove("hello"); // remove by value
list.indexOf("b"); // first occurrence
list.contains("a"); // true
list.subList(0, 2); // [0, 2)
list.sort(Comparator.naturalOrder());
list.reversed(); // Java 21+
// ── Set (no duplicates) ──
Set<String> hashSet = new HashSet<>(); // unordered, O(1)
Set<String> treeSet = new TreeSet<>(); // sorted (natural order)
Set<String> linkedSet = new LinkedHashSet<>(); // insertion order
Set<String> immutable = Set.of("a", "b", "c");
Set<String> unmodifiable = Collections.unmodifiableSet(hashSet);
// ── Map ──
Map<String, Integer> map = new HashMap<>(); // unordered, O(1)
Map<String, Integer> treeMap = new TreeMap<>(); // sorted by key
Map<String, Integer> linked = new LinkedHashMap<>(); // insertion order
map.put("key", 1);
map.putIfAbsent("key", 2); // only if key absent
map.get("key"); // 1
map.getOrDefault("missing", 0); // 0
map.merge("key", 1, Integer::sum); // merge with function
map.computeIfAbsent("key", k -> k.length());
map.forEach((k, v) -> System.out.println(k + "=" + v));
map.keySet(); // Set<String>
map.values(); // Collection<Integer>
map.entrySet(); // Set<Map.Entry<String, Integer>>
// ── Immutable Maps (Java 9+) ──
Map<String, Integer> imm = Map.of("a", 1, "b", 2);
Map<String, Integer> imm2 = Map.ofEntries(
Map.entry("a", 1),
Map.entry("b", 2)
);
// ── Queue / Deque ──
Queue<String> queue = new LinkedList<>();
queue.offer("first"); // add to tail
queue.poll(); // remove from head (null if empty)
queue.peek(); // examine head (null if empty)
Deque<String> stack = new ArrayDeque<>();
stack.push("a"); // add to head
stack.pop(); // remove from head
// ── Collections Utility ──
Collections.sort(list);
Collections.reverse(list);
Collections.shuffle(list);
Collections.frequency(list, "a"); // count occurrences
Collections.unmodifiableList(list);
Collections.emptyList(); // returns immutable empty list
Collections.max(list); // natural ordering max
Collections.min(list);
// ── Iteration ──
for (String s : list) { } // for-each
list.forEach(s -> System.out.println(s)); // lambda
list.iterator(); // Iterator
list.listIterator(); // bidirectional
list.stream(); // Stream API| Requirement | Best Choice | Alternative |
|---|---|---|
| Fast random access | ArrayList | CopyOnWriteArrayList (concurrent reads) |
| Frequent insert/remove | LinkedList | ArrayDeque (as deque) |
| No duplicates | HashSet | EnumSet (enums), BitSet (bits) |
| Sorted unique | TreeSet | ConcurrentSkipListSet (thread-safe) |
| Key-value pairs | HashMap | LinkedHashMap (order), TreeMap (sorted) |
| Thread-safe list | CopyOnWriteArrayList | Collections.synchronizedList |
| Thread-safe map | ConcurrentHashMap | Collections.synchronizedMap |
| FIFO queue | LinkedList | ArrayDeque (faster) |
| LIFO stack | ArrayDeque | Stack (legacy, not recommended) |
| Immutable | List.of() | Collections.unmodifiableList() |
| Structure | Add | Get | Contains | Remove |
|---|---|---|---|---|
| ArrayList | O(1)* | O(1) | O(n) | O(n) |
| LinkedList | O(1) | O(n) | O(n) | O(1) |
| HashMap | O(1) | O(1) | O(1) | O(1) |
| TreeMap | O(log n) | O(log n) | O(log n) | O(log n) |
| HashSet | O(1) | O(1) | O(1) | O(1) |
| TreeSet | O(log n) | O(log n) | O(log n) | O(log n) |
// ── Exception Hierarchy ──
// Throwable
// ├── Error (don't catch — system errors: OutOfMemoryError, StackOverflowError)
// └── Exception
// ├── RuntimeException (unchecked — don't need to declare)
// │ ├── NullPointerException
// │ ├── IllegalArgumentException
// │ ├── IndexOutOfBoundsException
// │ ├── IllegalStateException
// │ ├── ClassCastException
// │ └── ArithmeticException
// └── IOException (checked — must declare or handle)
// ├── FileNotFoundException
// └── SQLException
// ── Try-Catch-Finally ──
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.err.println("Cannot divide by zero: " + e.getMessage());
} catch (IllegalArgumentException | NullPointerException e) {
System.err.println("Bad argument: " + e.getMessage());
} catch (Exception e) { // catch all exceptions
System.err.println("Unexpected: " + e.getMessage());
} finally {
System.out.println("Always runs"); // even if exception or return
}
// ── Try-With-Resources (AutoCloseable, Java 7+) ──
try (
BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
BufferedWriter writer = new BufferedWriter(new FileWriter("out.txt"))
) {
String line = reader.readLine();
writer.write(line);
} catch (IOException e) {
System.err.println("IO error: " + e.getMessage());
} // reader and writer automatically closed
// ── Multiple resources ──
try (var in = new FileInputStream("in.txt");
var out = new FileOutputStream("out.txt")) {
in.transferTo(out);
}
// ── Custom Exception ──
public class BusinessException extends RuntimeException {
private final String errorCode;
public BusinessException(String message, String errorCode) {
super(message);
this.errorCode = errorCode;
}
public String getErrorCode() { return errorCode; }
}
// Usage
throw new BusinessException("User not found", "USER_404");
// ── Re-throwing (preserving stack trace) ──
try {
riskyOperation();
} catch (IOException e) {
throw new BusinessException("Operation failed", "OP_ERR", e);
}
// ── Exception utilities ──
Objects.requireNonNull(value, "Value must not be null");
Objects.checkIndex(index, length);
throw new IllegalArgumentException("Expected positive, got: " + value);| Feature | Checked | Unchecked |
|---|---|---|
| Extends | Exception (not RuntimeException) | RuntimeException / Error |
| Must declare | Yes (throws clause) | No |
| Must handle | Yes (try-catch or throws) | No |
| Examples | IOException, SQLException | NPE, IllegalArgumentException |
| Compiler enforces | Yes | No |
| When to use | Recoverable conditions | Programming errors |
import java.util.stream.*;
import java.util.function.*;
// ── Create Streams ──
Stream<String> s1 = list.stream(); // from Collection
Stream<String> s2 = Stream.of("a", "b", "c"); // from values
Stream<Integer> s3 = IntStream.range(1, 100).boxed(); // from range
Stream<String> s4 = Files.lines(Path.of("file.txt")); // from file
Stream<String> s5 = "hello world".chars()
.mapToObj(c -> String.valueOf((char) c)); // from chars
DoubleStream random = DoubleStream.generate(Math::random).limit(10);
IntStream iterate = IntStream.iterate(0, n -> n + 2).limit(10);
// ── Intermediate Operations (lazy) ──
list.stream()
.filter(s -> s.startsWith("a")) // keep matching
.map(String::toUpperCase) // transform
.mapToInt(String::length) // convert to IntStream
.distinct() // remove duplicates
.sorted() // natural sort
.sorted(Comparator.reverseOrder()) // custom sort
.limit(10) // first N
.skip(5) // skip first N
.peek(System.out::println) // debug (side effect)
.flatMap(s -> Arrays.stream(s.split(""))) // flatten
.takeWhile(n -> n < 10) // Java 9+ (while true)
.dropWhile(n -> n < 5); // Java 9+ (while true)
// ── Terminal Operations (eager, one per stream) ──
list.stream().collect(Collectors.toList()); // to List
list.stream().collect(Collectors.toSet()); // to Set
list.stream().collect(Collectors.joining(", ")); // joined string
list.stream().count(); // long
list.stream().findFirst(); // Optional
list.stream().findAny(); // Optional
list.stream().anyMatch(s -> s.length() > 5); // boolean
list.stream().allMatch(s -> !s.isEmpty()); // boolean
list.stream().noneMatch(s -> s.isEmpty()); // boolean
list.stream().toArray(String[]::new); // String[]
list.stream().forEach(System.out::println); // void
list.stream().reduce("", (a, b) -> a + b); // Optional (reduction)
// ── Collectors ──
Map<String, Long> freq = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
Map<Boolean, List<String>> partitioned = list.stream()
.collect(Collectors.partitioningBy(s -> s.length() > 5));
Map<String, List<String>> grouped = list.stream()
.collect(Collectors.groupingBy(s -> s.substring(0, 1)));
String joined = list.stream()
.collect(Collectors.joining(", ", "[", "]"));
Map<String, String> nameMap = list.stream()
.collect(Collectors.toMap(
Function.identity(),
String::toUpperCase,
(existing, replacement) -> existing // merge function
));
// ── Optional (Java 8+) ──
Optional<String> opt = list.stream().filter(s -> s.length() > 5).findFirst();
opt.isPresent(); // boolean
opt.orElse("default"); // value or default
opt.orElseGet(() -> computeDefault()); // lazy default
opt.orElseThrow(); // NoSuchElementException
opt.ifPresent(System.out::println);
opt.map(String::toUpperCase).orElse("");
opt.filter(s -> s.length() > 3).orElse("");
opt.flatMap(s -> Optional.ofNullable(getNullableValue(s)));
opt.or(() -> Optional.of("fallback")); // chain fallbacks| Syntax | Description | Example |
|---|---|---|
| () -> expr | No parameters | () -> 42 |
| x -> expr | Single param, expression | x -> x * 2 |
| x -> { stmts } | Single param, block | x -> { return x; } |
| (a, b) -> expr | Multiple params | (a, b) -> a + b |
| Type::method | Method reference | String::toUpperCase |
| Class::new | Constructor ref | ArrayList::new |
| Interface | Method | Parameters | Returns |
|---|---|---|---|
| Predicate<T> | test | T | boolean |
| Function<T,R> | apply | T | R |
| Consumer<T> | accept | T | void |
| Supplier<T> | get | - | T |
| BiFunction<T,U,R> | apply | T, U | R |
| UnaryOperator<T> | apply | T | T |
| BinaryOperator<T> | apply | T, T | T |
peek() is mainly for debugging. Avoid side effects in stream operations. Use parallelStream() only for CPU-intensive operations on large datasets.// ── Thread Basics ──
Thread t = new Thread(() -> System.out.println("Hello"));
t.start();
t.join(); // wait for completion
t.interrupt(); // send interrupt signal
// ── ExecutorService (preferred over raw Thread) ──
ExecutorService executor = Executors.newFixedThreadPool(4);
ExecutorService cached = Executors.newCachedThreadPool();
ExecutorService single = Executors.newSingleThreadExecutor();
ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(2);
// Submit tasks
Future<String> future = executor.submit(() -> "result");
future.get(); // blocks until done
future.get(5, TimeUnit.SECONDS); // with timeout
future.cancel(true); // cancel if running
future.isDone(); // check status
// InvokeAll — wait for all tasks
List<Callable<String>> tasks = List.of(
() -> fetchUrl("https://a.com"),
() -> fetchUrl("https://b.com"),
() -> fetchUrl("https://c.com")
);
List<Future<String>> futures = executor.invokeAll(tasks);
for (Future<String> f : futures) {
System.out.println(f.get());
}
// ── CompletableFuture (Java 8+) ──
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
return fetchData(); // runs on ForkJoinPool
});
cf.thenApply(data -> process(data)) // sync transform
.thenApplyAsync(data -> heavyProcess(data)) // async transform
.thenCombine(otherCf, (a, b) -> a + b) // combine two futures
.acceptEither(otherCf, result -> use(result)) // use whichever completes first
.exceptionally(ex -> handleError(ex)) // error handling
.handle((result, ex) -> { // result or error
return ex != null ? "fallback" : result;
})
.thenAccept(System.out::println); // consume result
// Wait for multiple futures
CompletableFuture.allOf(cf1, cf2, cf3).join();
CompletableFuture.anyOf(cf1, cf2, cf3).join(); // first to complete
// ── Virtual Threads (Java 21+) ──
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10_000; i++) {
executor.submit(() -> handleRequest(i));
}
}
// Or start a single virtual thread
Thread vt = Thread.startVirtualThread(() -> processTask());
// ── Synchronized ──
public class Counter {
private int count = 0;
public synchronized void increment() { count++; }
// Or use ReentrantLock for more flexibility
private final ReentrantLock lock = new ReentrantLock();
public void safeIncrement() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
// ── Atomic classes (lock-free) ──
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet();
counter.getAndIncrement();
counter.updateAndGet(x -> x + 10);
// ── Concurrent Collections ──
ConcurrentHashMap<String, Integer> chm = new ConcurrentHashMap<>();
chm.putIfAbsent("key", 1);
chm.computeIfAbsent("key", k -> expensiveCompute(k));
chm.forEach((k, v) -> System.out.println(k + "=" + v));
CopyOnWriteArrayList<String> cowList = new CopyOnWriteArrayList<>();
ConcurrentLinkedQueue<String> clq = new ConcurrentLinkedQueue<>();
BlockingQueue<String> bq = new LinkedBlockingQueue<>(100);| Mechanism | Purpose | Notes |
|---|---|---|
| synchronized | Mutual exclusion | Monitor lock on object/method |
| ReentrantLock | Explicit locking | tryLock(), lockInterruptibly() |
| volatile | Visibility guarantee | No atomicity — use for flags only |
| Atomic* | Lock-free CAS | AtomicInteger, AtomicReference, etc. |
| wait/notify | Condition signaling | Must be inside synchronized block |
| CountDownLatch | Wait for N events | countDown() then await() |
| Semaphore | Limit concurrent access | acquire(), release() |
| CyclicBarrier | Sync at barrier point | N threads wait for each other |
| Factory | Threads | Queue | Use Case |
|---|---|---|---|
| newFixedThreadPool(n) | Fixed N | Unbounded | CPU-bound tasks |
| newCachedThreadPool() | Unbounded | SynchronousQueue | Short async tasks |
| newSingleThreadExecutor() | 1 | Unbounded | Sequential tasks |
| newScheduledThreadPool(n) | Fixed N | DelayQueue | Periodic tasks |
| newVirtualThreadPerTaskExecutor() | Unbounded | - | I/O-bound (Java 21+) |
# ── JVM Flags ──
# Memory settings
java -Xms512m -Xmx2g MyApp # Initial and max heap
java -Xmn256m MyApp # Young generation size
java -XX:MetaspaceSize=256m MyApp # Initial metaspace
java -XX:MaxMetaspaceSize=512m MyApp # Max metaspace (replaces PermGen)
java -XX:NewRatio=2 MyApp # Old:Young = 2:1
java -XX:SurvivorRatio=8 MyApp # Eden:Survivor = 8:1
# Garbage Collection
java -XX:+UseG1GC MyApp # G1GC (default since Java 9)
java -XX:+UseZGC MyApp # ZGC (low latency, Java 15+)
java -XX:+UseShenandoahGC MyApp # Shenandoah (low latency)
java -XX:+UseParallelGC MyApp # Parallel GC (throughput)
java -XX:+UseSerialGC MyApp # Serial GC (single-threaded, small apps)
# GC Logging
java -Xlog:gc*:file=gc.log:time,uptime:filecount=5,filesize=50m MyApp
# Monitoring
jps -l # List running JVM processes
jstat -gc <pid> 1000 # GC statistics every 1s
jmap -heap <pid> # Heap summary
jmap -histo <pid> # Object histogram
jmap -dump:live,format=b,file=heap.hprof <pid> # Heap dump
jstack <pid> # Thread dump
jcmd <pid> GC.heap_info # GC info
jcmd <pid> VM.flags # All VM flags
jcmd <pid> VM.system_properties # System properties| Area | Description | GC |
|---|---|---|
| Heap | Objects, arrays — shared across threads | Yes (major + minor GC) |
| Metaspace | Class metadata, method bytecode, static fields | Yes (when full) |
| Stack | Thread call stack, local primitives, references | No (allocated/freed with thread) |
| Code Cache | Compiled native code (JIT) | Yes (when full) |
| Direct Memory | NIO buffers (ByteBuffer.allocateDirect) | No (manual or Cleaner) |
| Thread stacks | Per-thread stack memory | No (thread lifecycle) |
| GC | Focus | Latency | Throughput | Best For |
|---|---|---|---|---|
| Serial | Small heaps | Low (single thread) | Low | Client apps, embedded |
| Parallel | Throughput | High (STW pauses) | Highest | Batch processing |
| G1GC | Balanced | Low-mid (concurrent) | High | General purpose (default) |
| ZGC | Ultra-low latency | Sub-ms | Moderate | Real-time, low-latency |
| Shenandoah | Low latency | Low (concurrent) | Moderate | Responsive apps |
# ── Java Flight Recorder (JFR) ──
java -XX:StartFlightRecording=duration=60s,filename=recording.jfr MyApp
jfr print recording.jfr
jfr summary recording.jfr
# ── Java Mission Control (JMC) — GUI tool for JFR analysis
# ── Useful JVM Diagnostics ──
java -XX:+PrintFlagsFinal -version # All JVM flags and defaults
java -XX:+PrintCompilation MyApp # JIT compilation log
java -Djava.security.debug=ssl MyApp # SSL debugging== compares object references (memory addresses). equals() compares object content (value). For strings, == is true only for string literals from the pool (interning). Always use equals() for value comparison. Remember to override both equals() and hashCode() together — if two objects are equal, their hash codes must also be equal.
HashMap uses an array of buckets (Node[] table). For each key: 1) Compute hash = key.hashCode(). 2) Apply index = hash & (n-1) to find bucket. 3) If collision, store as linked list (or tree if list size > 8). Java 8+ converts linked lists to red-black trees for O(log n) lookup on collisions. put(), get(), and remove() are all O(1) average case. Capacity doubles when load factor > 0.75.
ArrayList uses a dynamic array — O(1) random access, O(n) insert/delete (may shift elements). Best for read-heavy access. LinkedList uses doubly-linked nodes — O(1) insert/delete at known position, O(n) random access. Better for frequent insertions/deletions. In practice, ArrayList is almost always the better choice due to CPU cache locality.
The JMM defines how threads interact through memory. Without synchronization, threads may cache variables in CPU registers/caches. volatile ensures: 1) Visibility — writes are immediately visible to other threads. 2) Ordering — prevents instruction reordering. But volatile does NOT make compound operations atomic (e.g., count++). For atomic compound operations, use AtomicInteger or synchronized.
GC finds unreachable objects (no references from GC roots: static fields, thread stacks, JNI references). Mark phase: traverse from roots and mark reachable objects. Sweep phase: free memory from unmarked objects. Modern GCs (G1, ZGC) use generational hypothesis: most objects die young. Heap is divided into Young (Eden + 2 Survivor) and Old. New objects go to Eden; survivors move to Survivor after minor GC; long-lived objects promote to Old. Major GC cleans Old generation.
Future is a read-only handle — you can get the result or check if done, but cannot set it programmatically (except via FutureTask). CompletableFuture is composable: supports chaining (thenApply, thenCompose), combining (thenCombine, allOf, anyOf), error handling (exceptionally, handle), and can be completed manually (complete()). Always prefer CompletableFuture in new code.