Java Syntax, Primitives, Operators, and Control Flow
Establish a rock-solid foundation in Java's strongly typed architecture, virtual machine compilation lifecycle, primitive type boundaries, and conditional branch execution.
1.1 The Architecture of the Java Virtual Machine (JVM)
Java is a statically typed, class-based, object-oriented programming language designed around the core tenet: "Write Once, Run Anywhere" (WORA). To achieve platform independence, Java does not compile source code directly into hardware-specific binary machine code. Instead, the Java compiler (javac) compiles human-readable .java source files into platform-neutral bytecode instructions stored in .class files.
At runtime, the Java Virtual Machine (JVM) executes this bytecode across host operating systems (Windows, Linux, macOS) through three major subsystems:
- ClassLoader Subsystem: Dynamically loads compiled
.classfiles into the JVM memory space, links references, and initializes static class state. - Runtime Data Areas: Memory divided into the Method Area (storing class metadata and bytecode), the Heap (where all object instances and arrays are allocated), the Java Thread Stack (holding local variables, primitive values, and partial frame results), Program Counter (PC) Registers, and Native Method Stacks.
- Execution Engine: Translates bytecode into native CPU instructions using an interpreter for immediate startup, paired with a sophisticated Just-In-Time (JIT) Compiler (such as HotSpot C1/C2) that identifies performance-critical "hot spots" in loops and compiles them directly into optimized native machine code.
1.2 Structure of a Java Program & The Entry Point
Every single line of executable Java code must reside inside an enclosing class definition. The standard entry point executed by the JVM launcher is the public static void main(String[] args) signature:
// Fundamental Java Class Structure
package com.funkoding.course;
public class HelloWorld {
// The main method serves as the deterministic runtime execution entry point
public static void main(String[] args) {
System.out.println("Welcome to Fun Koding Java Masterclass!");
}
}
The components of this entry point signature carry strict architectural significance:
public: An access modifier granting the external JVM launcher unrestricted permission to invoke the method from outside the enclosing package.static: Designates that the method belongs to the class itself rather than a specific object instance. This allows the JVM to execute the method without allocating an unneeded instance of the class into heap memory.void: Declares that the method returns no value to the operating system upon termination.main: The exact method identifier name targeted by the JVM execution protocol.String[] args: An array of string objects containing optional command-line arguments passed to the program during launch.
1.3 Variables, Memory Footprints & Primitive Data Types
Java enforces strict static type safety: every variable must be declared with a definitive type before assignment. Java divides data into two fundamental categories: primitive types and reference types. There are exactly 8 primitive data types defined in the language specification, each with immutable memory boundaries:
byte: 8-bit signed two's complement integer. Range: -128 to 127. Memory footprint: 1 byte. Ideal for memory-constrained byte arrays.short: 16-bit signed integer. Range: -32,768 to 32,767. Memory footprint: 2 bytes.int: 32-bit signed integer. Range: -2,147,483,648 to 2,147,483,647. Memory footprint: 4 bytes. The standard default choice for integral arithmetic.long: 64-bit signed integer. Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807. Appended with anLsuffix (e.g.,10000000000L).float: 32-bit single-precision IEEE 754 floating point. Range: ~1.4E-45 to ~3.4E+38. Appended with anfsuffix (e.g.,3.14159f).double: 64-bit double-precision IEEE 754 floating point. The default standard for mathematical decimal computations.boolean: Represents truth values: strictlytrueorfalse. In Java, booleans are not integers (unlike C/C++), preventing invalid numeric-boolean casts.char: 16-bit Unicode character encoded in UTF-16. Range:'\u0000'(0) to'\uffff'(65,535). Enclosed in single quotes (e.g.,'A').
Type Casting & Conversion Rules: When moving from a smaller primitive type to a larger type (e.g. int to long, or float to double), Java performs automatic widening conversion with zero loss of magnitude. Conversely, converting from a larger type to a smaller type (e.g. double to int) requires an explicit narrowing cast: int truncated = (int) 9.99;, which forcibly discards the fractional decimal component.
1.4 Conditional Control Flow: Branching & Switch Expressions
Control flow structures govern the dynamic decision pathways of code execution based on boolean truth evaluations:
// Control Flow: Modern Switch Expression & If-Else Branching
int userAge = 20;
// Classical If-Else Ladder
if (userAge >= 21) {
System.out.println("Full adult access granted.");
} else if (userAge >= 18) {
System.out.println("Standard access granted.");
} else {
System.out.println("Restricted minor account.");
}
// Modern Java Switch Expression (Java 14+) with pattern arrow syntax
String dayOfWeek = "WEDNESDAY";
int workloadHours = switch (dayOfWeek) {
case "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY" -> 8;
case "FRIDAY" -> 6;
case "SATURDAY", "SUNDAY" -> 0;
default -> throw new IllegalArgumentException("Invalid day: " + dayOfWeek);
};
Modern switch expressions eliminate dangerous fall-through bugs by discarding the classical requirement for manual break; statements, permitting multiple comma-separated case labels and yielding values directly into variable assignments.
1.5 Iteration Mechanics: For, While, and Do-While Loops
Repetitive execution is managed through iteration statements:
- Traditional For Loop: Best suited for counter-controlled loops with known bounds:
for (int i = 0; i < count; i++). - While Loop: Condition-controlled loop evaluated before entering the body. Continues while the invariant condition remains
true. - Do-While Loop: Guaranteed to execute its body at least once because condition validation occurs post-execution.
- Enhanced For-Each Loop: Idiomatic iteration over iterable collections and arrays:
for (String item : array), eliminating off-by-one indexing errors.
Level 1 Interactive Puzzle Bank (Puzzles 1โ30)
30 algorithmic drills, debugging challenges, and memory mechanics questions covering core syntax.
Integer Division vs Floating-Point Promotion
int a = 7 / 2;
double b = 7 / 2;
double c = 7.0 / 2;
System.out.println(a + ", " + b + ", " + c);
Primitive Integer Overflow Boundary
Integer.MAX_VALUE by 1 in Java? What does the code print?int max = Integer.MAX_VALUE;
System.out.println(max + 1);
Floating-Point Binary Inexactness
(0.1 + 0.2 == 0.3) evaluate to false in Java? How do enterprise financial applications solve this problem?
Short-Circuit Guard Against NullPointerException
NullPointerException when str is null:String str = null;
if (str == null || str.isEmpty()) {
System.out.println("Empty or null");
}
Bitwise Operator Bug in Conditional Statement
public boolean validate(User user) {
return user != null & user.isActive();
}
String Literal Pool vs Heap Allocation
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
System.out.println((s1 == s2) + " " + (s1 == s3) + " " + s1.equals(s3));
String Concatenation Performance in Loops
String s = ""; for (int i = 0; i < 10000; i++) s += i; cause severe latency? What is the $O(N)$ solution?
Ternary Operator Type Promotion Mystery
result in this ternary statement?Object result = true ? Integer.valueOf(42) : Double.valueOf(3.14);
System.out.println(result.getClass().getSimpleName());
Refactoring Legacy Switch to Java 17+ Switch Expression
String role = "ADMIN";
int level;
switch (role) {
case "ADMIN": level = 10; break;
case "EDITOR": level = 5; break;
default: level = 1;
}
Array Default Values Inspection
new int[2], new boolean[2], and new String[2], what are their initial element values?
Pass-by-Value Mechanics with Arrays
main after executing this method?public static void modify(int[] arr) {
arr[0] = 99;
arr = new int[]{1, 2, 3};
}
public static void main(String[] args) {
int[] nums = {10, 20};
modify(nums);
System.out.println(nums[0] + " " + nums.length);
}
Enhanced For-Each Loop Element Mutation Trap
int[] values = {1, 2, 3};
for (int val : values) {
val = 0;
}
System.out.println(values[0]);
Do-While Loop Execution Guarantee
do-while loop execute its body even if the loop condition is false at the start?
Breaking Out of Nested Loops with Labels
Primitive Method Overload Resolution
void test(int x) and void test(long x), which method does test(10) invoke?
Silent NullPointerException in Autounboxing
Integer counter = null;
int currentCount = counter;
System.out.println(currentCount);
The Java Integer Cache Range Mystery
Integer a = 100; Integer b = 100; (a == b) is true, but Integer c = 200; Integer d = 200; (c == d) is false.
Character Arithmetic & Numeric Promotion
System.out.println('A' + 1); print versus System.out.println((char)('A' + 1));?
Rules of the 'var' Local Variable Inference
var keyword permitted in Java, and where is it prohibited?
Negative Modulo Arithmetic in Java
-7 % 3 evaluate to in Java? Why does it differ from Python?
The Math.abs(Integer.MIN_VALUE) Corner Case
Math.abs(Integer.MIN_VALUE)? Why is it not positive?
Infinite Loop Identification in Byte Loop
for (byte b = 0; b < 130; b++) {
// Some processing
}
Static Method Call on Null Reference
Printer with public static void printLogo(), what happens when executing:Printer p = null;
p.printLogo();
Compile-Time Constant Folding
final int a = 10; final int b = 20; int c = a + b;, when is a + b evaluated?
Optimal Two-Pointer Palindrome Checker
Idiomatic FizzBuzz Implementation
Bitwise In-Place Variable Swap
x and y be swapped without using a temporary variable?
Counting Set Bits (Hamming Weight)
Why BufferedReader Outperforms Scanner for Large I/O
BufferedReader dramatically faster than Scanner when parsing large volumes of input data?
Overflow-Safe Binary Search Midpoint Calculation
int mid = (low + high) / 2; fail on large arrays? How do you write it safely?
Frequently Asked Developer Questions: Java Fundamentals
The JVM (Java Virtual Machine) is the abstract runtime engine that executes compiled bytecode, manages memory via garbage collection, and interfaces with hardware. The JRE (Java Runtime Environment) is an on-disk bundle containing the JVM plus the core Java standard class libraries required to run pre-compiled Java applications. The JDK (Java Development Kit) is the superset development package containing the JRE, JVM, and essential engineering tools: the compiler (javac), documentation generator (javadoc), archiver (jar), and debuggers.
Java retains 8 primitive data types for strict hardware execution speed and memory efficiency. An object reference in Java incurs substantial heap overhead: object header metadata (typically 12 to 16 bytes for mark word and class pointers), reference pointer overhead (4 to 8 bytes on 64-bit JVMs), and CPU cache-unfriendly memory indirection. A primitive int occupies exactly 4 contiguous bytes allocated directly on the fast thread stack or inside CPU registers with zero pointer dereferencing latency.
Java's logical operators && (AND) and || (OR) perform short-circuit evaluation. If the left-hand operand of && evaluates to false, the overall expression can never be true, so the JVM completely aborts evaluation of the right-hand operand. This allows idiomatic, safe null checks: if (user != null && user.isActive()). If user is null, the method user.isActive() is never executed, preventing an immediate NullPointerException.
The main method must be public so the external JVM runtime launcher can discover and invoke it across package boundaries. It must be static so the JVM can call ClassName.main() directly without needing to instantiate an object of that class, which would require knowledge of which constructor arguments to provide. It must return void because once the main thread finishes execution, the application process terminates (unless daemon threads remain active), communicating exit status through System.exit(status) instead of method return values.
Object-Oriented Programming (OOP) Architecture & The Collections Framework
Master the four pillars of object-oriented designโEncapsulation, Inheritance, Polymorphism, and Abstractionโpaired with the high-performance data structures of the Java Collections Framework.
2.1 The Object-Oriented Paradigm: State, Behavior & Memory Allocation
Object-Oriented Programming (OOP) is an engineering paradigm that models software systems around autonomous entities called objects that bundle mutable state (fields) together with associated operations (methods). A class serves as the blueprint or schematic from which individual object instances are materialized.
When an object is instantiated using the new keyword in Java:
// Memory Allocation Mechanics in Java
BankAccount account = new BankAccount("FK-1092", 5000.0);
- Stack Memory Allocation: The reference variable
accountis allocated on the current thread's stack frame. It stores an address pointer referencing the actual memory block on the heap. - Heap Memory Allocation: The
newoperator allocates contiguous memory on the JVM heap for the object instance, initializing its instance variables to their type-safe default values (0 for numbers,falsefor booleans,nullfor references). - Constructor Execution: The selected constructor runs, executing field initialization logic and establishing the object's initial valid invariant state.
2.2 The Four Core Pillars of Object-Oriented Architecture
Enterprise Java architecture relies on four foundational principles that govern modularity, maintainability, and code reusability:
1. Encapsulation (Information Hiding & Invariant Defense)
Encapsulation conceals the internal representation of an object from direct external tampering, exposing controlled access strictly through public API boundaries (getters and setters). By marking fields private, the class establishes complete control over valid state transitions:
// Defending State Invariants via Encapsulation
public class BankAccount {
private final String accountNumber;
private double balance;
public BankAccount(String accountNumber, double initialDeposit) {
if (initialDeposit < 0) {
throw new IllegalArgumentException("Initial balance cannot be negative.");
}
this.accountNumber = accountNumber;
this.balance = initialDeposit;
}
public synchronized void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Deposit amount must be strictly positive.");
}
this.balance += amount;
}
public double getBalance() {
return this.balance;
}
}
2. Inheritance (Hierarchical Code Reusability & The IS-A Contract)
Inheritance permits a new class (subclass) to inherit fields and behaviors from an existing class (superclass) using the extends keyword. Java enforces single class inheritanceโa class can extend at most one direct superclass, preventing the infamous "Diamond Problem" of multiple inheritance ambiguity.
3. Polymorphism (Static Overloading vs. Dynamic Method Dispatch)
Polymorphism (meaning "many forms") enables a unified interface to control distinct underlying forms. Java implements two distinct types of polymorphism:
- Compile-Time Polymorphism (Method Overloading): Defining multiple methods within the same class sharing the exact same name but differing in parameter count, parameter types, or parameter order. The compiler resolves the target method at compile time based on invocation argument signatures.
- Runtime Polymorphism (Method Overriding & Dynamic Dispatch): When a subclass provides a specific implementation of a method already defined in its superclass using the
@Overrideannotation. At runtime, the JVM inspects the actual object type in heap memory (not the reference variable type) and executes the overridden method through its virtual method table (vtable).
4. Abstraction (Decoupling Contracts from Implementations)
Abstraction hides complex implementation details, exposing only essential behavioral contracts. In Java, abstraction is realized through abstract classes (which can contain instance variables and concrete methods) and interfaces (which define pure behavioral contracts). Since Java 8, interfaces also permit default and static utility methods with concrete bodies.
2.3 The Java Collections Framework: Hierarchy & Algorithmic Trade-offs
The java.util Collections Framework provides unified, high-performance data structures that replace error-prone manual array resizing:
// The Core Collections Interfaces & Concrete Implementations
// 1. List Interface: Ordered sequence permitting duplicate elements
List<String> arrayList = new ArrayList<>(); // O(1) amortized append, O(1) random access
List<String> linkedList = new LinkedList<>(); // O(1) insertion at ends, O(N) random access
// 2. Set Interface: Mathematical collection guaranteeing unique elements
Set<Integer> hashSet = new HashSet<>(); // O(1) average lookup via hashing
Set<Integer> treeSet = new TreeSet<>(); // O(log N) ordered traversal via Red-Black Tree
// 3. Map Interface: Key-Value association dictionaries
Map<String, Integer> hashMap = new HashMap<>(); // O(1) amortized get/put
Map<String, Integer> treeMap = new TreeMap<>(); // O(log N) sorted keys
Level 2 Interactive Puzzle Bank (Puzzles 31โ60)
30 OOP design problems, inheritance puzzles, collection traps, and memory invariant drills.
Explicit Superclass Constructor Invocation
Vehicle defines only a parameterized constructor public Vehicle(String vin), why does a subclass public Car() {} fail to compile? How do you fix it?
Polymorphic Field Hiding vs Method Overriding
class Parent { int x = 10; int getX() { return x; } }
class Child extends Parent { int x = 20; int getX() { return x; } }
Parent p = new Child();
System.out.println(p.x + " " + p.getX());
Covariant Return Types in Subclasses
The Equals and HashCode Contract Violation
equals() but does NOT override hashCode() when stored in a HashSet or HashMap?
Constructing a 100% Immutable Class
Date or List?
Java Records vs Traditional POJOs
record simplify immutable data carrier classes? Write a UserRecord with id and email.
ArrayList Growth Algorithm & Capacity Sizing
ArrayList expand its internal array when capacity is reached in modern Java? How do you prevent resizing overhead?
Fail-Fast Iterators & ConcurrentModificationException
ConcurrentModificationException? How do you fix it?List<String> list = new ArrayList<>(List.of("A", "B", "C"));
for (String s : list) {
if (s.equals("B")) list.remove(s);
}
Comparable vs Comparator Architectural Distinction
Comparable<T> versus providing external Comparator<T> instances?
Arrays.asList() Mutation Gotcha
Arrays.asList("a", "b").add("c"); throw an UnsupportedOperationException?
List.of() vs Arrays.asList() Immutability
List.of(...) (Java 9+) and Arrays.asList(...).
TreeSet Incomparable Element Exception
Person into a TreeSet if Person does not implement Comparable?
PriorityQueue Iteration Ordering Trap
PriorityQueue with a for-each loop print elements in sorted order?
Creating a Production-Grade Custom Exception
Return Statement in Finally Block Anti-Pattern
public static int test() {
try {
return 1;
} finally {
return 2;
}
}
Exception Swallowing in Finally
try block and the finally block throw an exception in traditional Java?
Generics Invariance & Wildcard Mutation Rules
List<? extends Number> list = new ArrayList<Integer>();
list.add(Integer.valueOf(10)); // Compile error!
Why Generic Arrays are Prohibited in Java
T[] arr = new T[10];?
Two Sum Optimal Solution via HashMap
nums that add up to target in $O(N)$ time.
Cycle Detection (Floyd's Tortoise & Hare)
Valid Parentheses Checker via ArrayDeque
()[]{} using ArrayDeque as a stack.
Building an LRU Cache via LinkedHashMap
LinkedHashMap?
Scope of 'this' in Anonymous Class vs Lambda
this keyword refer to inside an anonymous inner class versus inside a lambda expression?
Resolving Multiple Interface Default Method Conflicts
Service implements interfaces A and B, and both declare a default method default void execute(), how does Service resolve the collision?
Why Java's Cloneable Interface is Considered Flawed
Cloneable and clone()? What pattern should be used instead?
Exception in Static Initialization Block
RuntimeException?
Double-Checked Locking Singleton with Volatile
volatile keyword strictly mandatory?
The Single-Element Enum Singleton Guarantee
enum considered the most bulletproof way to implement a Singleton in Java?
Iterative In-Place Singly Linked List Reversal
Deep Copying Object Graphs with Nested Collections
Frequently Asked Developer Questions: OOP & Collections
Java prohibits multiple class inheritance to avoid the structural ambiguity known as the Diamond Problem. If class D extends both class B and class C, and both B and C inherit and override a method from class A with different implementations, class D cannot deterministically know which superclass method to execute. Interfaces originally avoided this because they contained no method implementations or mutable state. With Java 8 default methods, interface collisions are resolved at compile time through strict conflict resolution rules requiring explicit override.
In Java, a HashMap uses an array of buckets. When two distinct keys generate the same bucket index via key.hashCode(), Java resolves the collision through separate chaining. Prior to Java 8, chained nodes were stored as a simple singly linked list with $O(N)$ lookup. In Java 8 and newer, when a bucket exceeds TREEIFY_THRESHOLD = 8 elements and the total map capacity is at least 64, Java converts that linked list into a balanced Red-Black Tree. This reduces worst-case collision lookup time from $O(N)$ linear time to $O(\log N)$ logarithmic time, preventing algorithmic complexity attacks.
Method overloading is resolved statically at compile time (early binding) by examining the method name and declared argument types present at the call site. The compiler generates an explicit invokevirtual bytecode instruction tied to that exact signature. Method overriding (dynamic dispatch) is resolved dynamically at runtime (late binding). When calling an overridden method on an object reference, the JVM inspects the actual object type in heap memory at runtime and uses the object's internal virtual method table (vtable) pointer to execute the subclass implementation.
Choose an Abstract Class when creating a strong IS-A hierarchical relationship where related subclasses need to inherit mutable instance state (private non-static fields), access protected constructors, or reuse non-public helper methods. Choose an Interface when defining a behavioral contract (CAN-DO capability, such as Comparable, Serializable, or AutoCloseable) that disparate, unrelated classes across different class hierarchies can implement without restricting their single class inheritance budget.
Exception Engineering, Generics, File I/O & The Java Stream API
Explore production-grade enterprise Java: deterministic resource cleanup with try-with-resources, invariant generics type erasure, and declarative data processing with functional Streams.
3.1 Robust Exception Engineering & Try-With-Resources
In Java, exceptions are represented by the java.lang.Throwable hierarchy, which bifurcates into two distinct branches:
- Errors (
java.lang.Error): Severe internal JVM conditions from which standard applications cannot recover (e.g.OutOfMemoryError,StackOverflowError). Developers should never catchError. - Exceptions (
java.lang.Exception): Exceptional conditions that applications should anticipate and handle. This branch divides into:- Checked Exceptions: Subclasses of
ExceptionexcludingRuntimeException(e.g.IOException,SQLException). The compiler forces developers to either catch them with atry-catchblock or declare them in the method signature viathrows. - Unchecked Exceptions: Subclasses of
RuntimeException(e.g.NullPointerException,IndexOutOfBoundsException). These indicate programming bugs and invalid preconditions that should be corrected through code logic rather than caught.
- Checked Exceptions: Subclasses of
Deterministic Resource Cleanup via Try-With-Resources: Traditional exception handling relied on verbose finally blocks to close database connections or file streams, which were prone to masking original exceptions if the close operation also failed. Java 7 introduced the try-with-resources statement, which guarantees that any object implementing java.lang.AutoCloseable is automatically closed when execution leaves the block, preserving suppressed exceptions:
// Automatic Resource Management with Try-With-Resources
public void processReport(Path inputPath) throws IOException {
// Both resources will be closed deterministically in reverse order of declaration
try (BufferedReader reader = Files.newBufferedReader(inputPath);
BufferedWriter writer = Files.newBufferedWriter(Paths.get("output.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
writer.write(line.toUpperCase());
writer.newLine();
}
} // Automatic reader.close() and writer.close() executed here
}
3.2 Java Generics & Type Erasure Mechanics
Java Generics provide compile-time type safety, allowing classes and methods to operate on parameterized types without hazardous runtime type casting. Prior to Generics (Java 5), collections held raw Object references, leading to frequent runtime ClassCastException crashes.
To preserve binary backward compatibility with legacy Java 1.4 bytecode, the Java compiler implements Generics through Type Erasure. During compilation, the compiler:
- Replaces all generic type parameters with their upper bounds (or
Objectif unbounded). - Inserts explicit bytecode casts to maintain type safety.
- Generates synthetic bridge methods to preserve polymorphism in extended generic classes.
Because type arguments are erased at compile time, generic type information is largely unavailable at runtime. Consequently, you cannot write new T(), create generic arrays like new T[10], or inspect instanceof List<String>.
The PECS Guideline (Producer Extends, Consumer Super): When working with generic wildcards in collections:
- Producer Extends: If you only read items of type
Tfrom a collection, declare it asList<? extends T>(covariance). It produces data for your consumption. - Consumer Super: If you only write items of type
Tinto a collection, declare it asList<? super T>(contravariance). It consumes data from your code.
3.3 Modern Functional Programming & The Stream API
Introduced in Java 8, the Stream API fundamentally transformed Java from an exclusively imperative language into a hybrid language supporting declarative, functional programming. A Stream is a sequence of elements supporting sequential and parallel aggregate operations, operating on data without mutating the underlying source.
// Declarative Data Processing via Java 8+ Stream Pipeline
List<String> sourceWords = List.of("apple", "banana", "avocado", "cherry", "apricot", "blueberry");
// Filter words starting with 'a', transform to uppercase, and collect to list
List<String> filteredWords = sourceWords.stream()
.filter(word -> word.startsWith("a")) // Intermediate operation (lazy)
.map(String::toUpperCase) // Method reference transformation
.sorted() // Intermediate sorting
.collect(Collectors.toList()); // Terminal collection operation
System.out.println(filteredWords); // Output: [APPLE, APRICOT, AVOCADO]
Level 3 Interactive Puzzle Bank (Puzzles 61โ90)
30 advanced architectural puzzles, Stream pipelines, multithreading race conditions, and NIO operations.
Lambda Local Variable Effectively Final Constraint
final or effectively final?
Proving Stream Lazy Evaluation with Peek
Stream<String> stream = Stream.of("a", "b", "c")
.filter(s -> {
System.out.println("Filter: " + s);
return s.startsWith("a");
});
System.out.println("Stream pipeline built.");
Short-Circuiting Infinite Streams
GroupingBy with Downstream Aggregating Collector
Transaction(city, amount), write a Stream pipeline to calculate the total transaction sum per city.
Flattening Nested Lists with FlatMap
List<List<String>> nestedList, how do you extract a sorted list of unique words in uppercase using Stream API?
Parallel Stream ForkJoinPool Contention Hazard
list.parallelStream() considered dangerous in enterprise web applications?
Executing Parallel Streams on an Isolated ForkJoinPool
The Thread-Unsafe SimpleDateFormat Vulnerability
SimpleDateFormat across multiple threads a critical bug? What is the Java 8 replacement?
Volatile Keyword Semantics & The Java Memory Model
volatile keyword provide under the Java Memory Model? Does it make count++ thread-safe?
AtomicInteger vs Synchronized: Lock-Free CAS
AtomicInteger.incrementAndGet() outperform synchronized blocks under low-to-moderate thread contention?
Deadlock Conditions & Diagnosis
ThreadLocal Memory Leak in Thread Pools
ThreadLocal without calling remove() cause a memory leak in application servers like Tomcat?
Asynchronous Pipelines with CompletableFuture
CompletableFuture that fetches user data, enriches it with orders, and recovers from errors with a fallback.
NIO.2: Files.readAllLines vs Files.lines
Files.readAllLines(path) crash on a 10GB file, while Files.lines(path) processes it with tiny memory usage?
High-Throughput Zero-Copy File Transfer in NIO
FileChannel.transferTo() achieve zero-copy data transfer to a network socket?
Accessing Suppressed Exceptions in Try-with-Resources
Disambiguating Method References
Consumer<String> c = System.out::println; compile cleanly, but passing an overloaded method reference to a raw functional interface can cause compiler ambiguity?
Eliminating Boxing Overhead with IntStream
IntStream.rangeClosed(1, 10_000_000).sum() run over 10x faster and consume zero heap memory compared to Stream.iterate(1, n -> n + 1).limit(10_000_000).reduce(0, Integer::sum)?
Implementing a Custom Stream Collector
Collector<T, A, R> in Java?
ReentrantLock vs Synchronized Capabilities
ReentrantLock that cannot be achieved using the standard synchronized keyword.
CountDownLatch vs CyclicBarrier Architectural Differences
CyclicBarrier over a CountDownLatch in multi-threaded coordination?
WeakReference vs SoftReference Garbage Collection
WeakReference versus a SoftReference?
G1 GC String Deduplication Optimization
Sealed Classes & Exhaustive Pattern Matching
sealed classes provide in Java 17+? Provide a code example.
Pattern Matching for Switch in Java 21
Virtual Threads (Project Loom) Architecture
Diagnosing Static Collection Memory Leaks
public static final List<Event> history = new ArrayList<>(); a notorious source of memory leaks in production?
Safe Publication via Final Field Semantics
final fields without explicit synchronization?
Thread-Safe Token Bucket Rate Limiter
Designing an O(1) LRU Cache from Scratch
get(key) and $O(1)$ put(key, value) using a Doubly-Linked List and a HashMap.
Frequently Asked Developer Questions: Advanced Java & Streams
Type Erasure is the process by which the Java compiler strips all generic type parameter information from the bytecode during compilation, replacing parameters with their bound (e.g. Object or an upper bound). This was chosen in Java 5 to maintain 100% binary backwards compatibility with existing legacy JVM runtimes. The runtime limitations it imposes include: inability to instantiate a generic type with new T(), inability to create generic arrays like new T[10], absence of primitive generic types (requiring boxed wrappers like Integer), and inability to use instanceof List<String>.
PECS stands for "Producer Extends, Consumer Super", popularized by Joshua Bloch in Effective Java. If a parameterized collection produces items for your code to read, use <? extends T> (covariance). This allows passing collections of any subtype of T safely. If a collection consumes items passed from your code (you only write into it), use <? super T> (contravariance). This allows passing collections of any supertype of T safely. If you both read from and write to the collection, do not use wildcardsโuse exact type parameters.
In traditional Java, closing resources inside finally blocks required nested try-catch structures that were vulnerable to exception masking: if an exception occurred in the try block and a second exception occurred while closing the resource in the finally block, the closing exception completely overwrote the original business logic exception, hiding the root cause. try-with-resources ensures that the original exception is preserved, while any secondary exception thrown during close() is attached to the primary exception as a suppressed exception (accessible via e.getSuppressed()).
Parallel streams (parallelStream()) partition data processing across multiple CPU cores utilizing the common ForkJoinPool. They should only be used when: 1) the dataset is large (typically $N \times Q > 10,000$ where $Q$ is computational work per item), 2) operations are completely stateless, independent, and free of shared mutable state, and 3) the data source splits efficiently (like ArrayList or arrays, not LinkedList or I/O streams). Pitfalls include thread starvation on the shared common pool, thread synchronization overhead on shared locks, and non-deterministic results if operations are order-dependent.