Phase 3 — Modern & Advanced Core Java
This phase moves you from "I can write Java" to "I understand how modern Java code is written and how Java works underneath."
Chapters in this Phase
Modern Java
Functional Interfaces
Lambda Expressions
Method References
OptionalStream Fundamentals
Stream Operations —
filter,map,flatMapStream Operations —
sorted,distinct,limit,reduceCollectors — Grouping, Partitioning & Mapping
Advanced Collections & Data Processing
Advanced Collections & Choosing the Right Collection
Comparators & Advanced Sorting
File Handling & NIO
Files, Paths & Directories
Reading and Writing Text Files
Byte Streams, Character Streams & Buffered I/O
Try-with-Resources & Resource Management
Date, Time & Text Processing
Java Date & Time API
Regular Expressions
Java Metadata & Runtime Features
Annotations
Reflection
Java Modules
JVM & Performance
JVM, Bytecode, Stack, Heap & References
Garbage Collection & Object Lifetime
JVM Performance & Memory Problems
Chapter 1 — Functional Interfaces
Question
Given below is a code snippet that:
Defines a functional interface.
Uses a lambda expression to provide its behavior.
Passes behavior into a method.
Executes that behavior with different values.
What should be the output of the following code?
// A functional interface has exactly one abstract method.
@FunctionalInterface
interface DiscountCalculator {
// This method represents the behavior we want to provide.
double calculate(double price);
}
public class Main {
// This method receives behavior as an argument.
static void printDiscount(DiscountCalculator calculator, double price) {
// Execute the behavior supplied by the caller.
double discount = calculator.calculate(price);
// Display the calculated discount.
System.out.println(discount);
}
public static void main(String[] args) {
// Create behavior using a lambda expression.
DiscountCalculator calculator =
price -> price * 0.10;
// Pass that behavior into another method.
printDiscount(calculator, 1000);
// Reuse the same behavior with another value.
printDiscount(calculator, 500);
}
}Answer
100.0
50.0Step-by-step explanation
DiscountCalculatoris an interface.It has one abstract method:
calculate().Because it has exactly one abstract method, it is a functional interface.
The lambda:
price -> price * 0.10provides the implementation of
calculate().So when
calculator.calculate(1000)runs, Java calculates1000 × 0.10 = 100.With
500, the result is50.
How to read the important code
"Create a DiscountCalculator whose calculation takes price and returns ten percent of the price."
A functional interface is simply an interface designed to represent one piece of behavior.
Beginner trap
A functional interface can contain other non-abstract methods, but it must have exactly one abstract method.
Key takeaway
Functional interfaces allow Java to represent behavior as something we can pass around.
Chapter 2 — Lambda Expressions
Question
Given below is a code snippet that:
Creates behavior using lambdas.
Uses parameters.
Uses an expression lambda.
Uses a block lambda.
Passes different behavior into the same method.
What should be the output of the following code?
@FunctionalInterface
interface Calculator {
// The lambda must provide this method.
int calculate(int a, int b);
}
public class Main {
// This method accepts behavior instead of hard-coding one calculation.
static void showResult(Calculator calculator, int a, int b) {
// Run the supplied lambda.
System.out.println(calculator.calculate(a, b));
}
public static void main(String[] args) {
// Lambda with an expression body.
Calculator add = (a, b) -> a + b;
// Lambda with a block body.
Calculator multiply = (a, b) -> {
int result = a * b;
return result;
};
// Supply addition behavior.
showResult(add, 5, 3);
// Supply multiplication behavior.
showResult(multiply, 5, 3);
}
}Answer
8
15Step-by-step explanation
addstores behavior that adds two numbers.5 + 3produces8.multiplystores behavior that multiplies two numbers.Its block creates
result.5 × 3produces15.The same
showResult()method works with both behaviors.
How to read the important code
"
addis a Calculator that adds two numbers."
"
multiplyis a Calculator that multiplies two numbers."
Beginner trap
A lambda does not execute merely because it was created. It executes when its functional-interface method is called.
Key takeaway
A lambda is a compact way to provide behavior where Java expects a functional interface.
Chapter 3 — Method References
Question
Given below is a code snippet that:
Uses a method reference.
Passes an existing method as behavior.
Uses a static method reference.
Uses an instance method reference.
What should be the output of the following code?
import java.util.function.Function;
public class Main {
// Existing method that converts text to uppercase.
static String makeUpper(String text) {
return text.toUpperCase();
}
public static void main(String[] args) {
// Method reference to a static method.
Function<String, String> upper = Main::makeUpper;
// Method reference to an existing String instance method.
Function<String, String> trimmed = String::trim;
// Execute the first behavior.
System.out.println(upper.apply("java"));
// Execute the second behavior.
System.out.println(trimmed.apply(" backend "));
}
}Answer
JAVA
backendStep-by-step explanation
Function<String, String>means:receive a
Stringreturn a
String.
Main::makeUpperrefers to the existingmakeUpper()method.upper.apply("java")therefore callsmakeUpper("java").The result is
JAVA.String::trimrefers to the existingtrim()method." backend "becomes"backend".
How to read the important code
"
upperis a Function from String to String, using Main's makeUpper method."
Beginner trap
:: does not call the method immediately. It refers to the method so Java can call it later.
Key takeaway
A method reference is a shorter way to use an existing method as behavior.
Chapter 4 — Optional
Question
Given below is a code snippet that:
Creates an
Optional.Handles a value that may be absent.
Uses
map.Uses
orElse.Avoids directly calling a method on a potentially missing value.
What should be the output of the following code?
import java.util.Optional;
public class Main {
static String findUserName(int id) {
// ID 1 has a name; other IDs have no result.
if (id == 1) {
return "Alice";
}
return null;
}
public static void main(String[] args) {
// Convert the possibly-null result into an Optional.
Optional<String> user =
Optional.ofNullable(findUserName(1));
// Transform the value if it exists.
String result = user
.map(String::toUpperCase)
.orElse("UNKNOWN");
// Display the final value.
System.out.println(result);
// Search for a user that does not exist.
Optional<String> missing =
Optional.ofNullable(findUserName(99));
// Use a fallback when there is no value.
System.out.println(missing.orElse("UNKNOWN"));
}
}Answer
ALICE
UNKNOWNStep-by-step explanation
ID
1returns"Alice".ofNullable()puts that value inside anOptional.map(String::toUpperCase)transforms"Alice"into"ALICE".orElse()is not needed because a value exists.ID
99returnsnull.ofNullable(null)creates an emptyOptional.map()has nothing to transform.orElse("UNKNOWN")supplies the fallback.
How to read the important code
"Take the optional name, convert it to uppercase if present, otherwise use UNKNOWN."
Beginner trap
Optional is mainly useful for representing possible absence. It is not a replacement for every variable or field in your program.
Key takeaway
Optional makes the possibility of "no value" explicit and encourages safer handling.
Chapter 5 — Stream Fundamentals
Question
Given below is a code snippet that:
Creates a stream from a collection.
Filters values.
Transforms values.
Collects the result into a list.
Demonstrates that a stream processes data rather than storing it.
What should be the output of the following code?
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
// Create the original data.
List<String> names =
List.of("Alice", "Bob", "Andrew", "David");
// Start a stream from the list.
List<String> result = names.stream()
// Keep names beginning with A.
.filter(name -> name.startsWith("A"))
// Convert each remaining name to uppercase.
.map(String::toUpperCase)
// Turn the stream result back into a List.
.collect(Collectors.toList());
// Display the resulting list.
System.out.println(result);
}
}Answer
[ALICE, ANDREW]Step-by-step explanation
The original list contains four names.
stream()creates a stream for processing them.filter()keeps"Alice"and"Andrew".map()converts them to uppercase.collect()gathers the processed values into a new list.The resulting list is
[ALICE, ANDREW].
How to read the important code
"Stream the names, keep names starting with A, convert them to uppercase, and collect them into a list."
Beginner trap
A Stream is not a collection. It is a pipeline used to process data.
Key takeaway
Streams let you describe a data-processing pipeline clearly and concisely.
Chapter 6 — filter, map and flatMap
Question
Given below is a code snippet that:
Filters objects.
Maps objects into another value.
Flattens nested lists using
flatMap.Produces a single stream of values.
What should be the output of the following code?
import java.util.List;
import java.util.stream.Collectors;
record Order(String customer, List<String> products) {}
public class Main {
public static void main(String[] args) {
// Each order contains its own list of products.
List<Order> orders = List.of(
new Order("Alice", List.of("Laptop", "Mouse")),
new Order("Bob", List.of("Keyboard")),
new Order("Alice", List.of("Monitor", "Mouse"))
);
// Process only Alice's orders.
List<String> products = orders.stream()
// Keep orders belonging to Alice.
.filter(order -> order.customer().equals("Alice"))
// Convert each Order into its product list.
.map(Order::products)
// Flatten multiple product lists into one stream.
.flatMap(List::stream)
// Collect all products into one list.
.collect(Collectors.toList());
// Display the final list.
System.out.println(products);
}
}Answer
[Laptop, Mouse, Monitor, Mouse]Step-by-step explanation
Three orders exist.
The first and third belong to Alice.
map(Order::products)changes each Alice order into aList<String>.We now effectively have:
[["Laptop", "Mouse"], ["Monitor", "Mouse"]]flatMap()opens those nested lists and creates one stream.The result becomes:
Laptop, Mouse, Monitor, Mousecollect()creates the final list.
How to read the important code
"Filter Alice's orders, get their product lists, flatten them into one stream, and collect the products."
Beginner trap
map() generally produces one output for each input. flatMap() is useful when each input can produce multiple values that should become one combined stream.
Key takeaway
Use
mapto transform; useflatMapto transform and flatten nested results.
Chapter 7 — sorted, distinct, limit and reduce
Question
Given below is a code snippet that:
Removes duplicate values.
Sorts values.
Limits the number of values.
Combines values using
reduce.
What should be the output of the following code?
import java.util.List;
public class Main {
public static void main(String[] args) {
// Create numbers containing duplicates.
List<Integer> numbers =
List.of(5, 2, 8, 2, 10, 5, 4);
// Process the numbers.
int result = numbers.stream()
// Remove duplicate numbers.
.distinct()
// Sort from smallest to largest.
.sorted()
// Keep only the first four values.
.limit(4)
// Add all remaining values together.
.reduce(0, Integer::sum);
// Display the result.
System.out.println(result);
}
}Answer
13Step-by-step explanation
Original values:
5, 2, 8, 2, 10, 5, 4distinct()removes duplicates:5, 2, 8, 10, 4sorted()produces:2, 4, 5, 8, 10limit(4)keeps:2, 4, 5, 8reduce(0, Integer::sum)adds them:0 + 2 + 4 + 5 + 8 = 19
Wait — therefore the correct output is:
19How to read the important code
"Remove duplicates, sort the numbers, take the first four, and add them together."
Beginner trap
When predicting streams, follow the pipeline in order. Each operation changes what the next operation receives.
Key takeaway
Stream operations form a pipeline, and order matters.
Chapter 8 — Collectors: Grouping, Partitioning & Mapping
Question
Given below is a code snippet that:
Groups objects by a property.
Partitions objects into two groups.
Collects selected values.
Uses collectors to summarize data.
What should be the output of the following code?
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
record Employee(String name, String department, int salary) {}
public class Main {
public static void main(String[] args) {
// Create employee data.
List<Employee> employees = List.of(
new Employee("Alice", "IT", 80000),
new Employee("Bob", "HR", 60000),
new Employee("Carol", "IT", 90000),
new Employee("David", "HR", 70000)
);
// Group employees according to their department.
Map<String, List<Employee>> byDepartment =
employees.stream()
.collect(Collectors.groupingBy(Employee::department));
// Divide employees into high and non-high salaries.
Map<Boolean, List<Employee>> bySalary =
employees.stream()
.collect(Collectors.partitioningBy(
employee -> employee.salary() >= 70000));
// Extract employee names into a list.
List<String> names =
employees.stream()
.map(Employee::name)
.collect(Collectors.toList());
// Display all results.
System.out.println(byDepartment.get("IT").size());
System.out.println(bySalary.get(true).size());
System.out.println(names);
}
}Answer
2
3
[Alice, Bob, Carol, David]Step-by-step explanation
Two employees belong to IT.
groupingBy()creates groups based on department.Three employees have salary at least
70000.partitioningBy()creates exactly two groups:trueandfalse.map(Employee::name)extracts only names.toList()collects those names.
How to read the important code
"Group employees by department."
"Partition employees based on whether salary is at least seventy thousand."
Beginner trap
groupingBy() can create many groups; partitioningBy() specifically divides data into two groups based on a boolean condition.
Key takeaway
Collectors turn processed stream data into useful structures such as maps, lists and grouped results.
Chapter 9 — Advanced Collections & Choosing the Right Collection
Question
Given below is a code snippet that:
Uses a
Listfor ordered data.Uses a
Setfor uniqueness.Uses a
Mapfor key-value lookup.Demonstrates insertion order.
Demonstrates fast-style key lookup conceptually.
What should be the output of the following code?
import java.util.*;
public class Main {
public static void main(String[] args) {
// List preserves duplicates and element order.
List<String> skills =
new ArrayList<>(List.of("Java", "SQL", "Java"));
// Set removes duplicate values.
Set<String> uniqueSkills =
new LinkedHashSet<>(skills);
// Map associates each key with a value.
Map<String, Integer> experience =
new HashMap<>();
// Store experience for each technology.
experience.put("Java", 3);
experience.put("SQL", 2);
// Print the original list.
System.out.println(skills);
// Print unique values while preserving insertion order.
System.out.println(uniqueSkills);
// Look up Java experience by key.
System.out.println(experience.get("Java"));
}
}Answer
[Java, SQL, Java]
[Java, SQL]
3Step-by-step explanation
ArrayListallows duplicate"Java"values.LinkedHashSetremoves the duplicate.It also preserves insertion order.
HashMapstores data as key-value pairs."Java"maps to3.get("Java")returns3.
How to read the important code
"Create a list of skills."
"Create a set of unique skills while preserving insertion order."
"Create a map from technology name to years of experience."
Beginner trap
Don't automatically use ArrayList everywhere.
Think about the requirement:
Need ordered duplicates →
ListNeed uniqueness →
SetNeed key-based lookup →
MapNeed queue behavior →
Queue/Deque
Key takeaway
Choosing the correct collection is part of designing the program.
Chapter 10 — Comparators & Advanced Sorting
Question
Given below is a code snippet that:
Sorts objects using a
Comparator.Sorts by salary.
Uses a secondary sorting rule.
Demonstrates descending order.
What should be the output of the following code?
import java.util.*;
record Employee(String name, int salary) {}
public class Main {
public static void main(String[] args) {
// Create employees with different salaries.
List<Employee> employees = new ArrayList<>(List.of(
new Employee("Alice", 70000),
new Employee("Bob", 90000),
new Employee("Carol", 70000)
));
// Sort by salary descending.
employees.sort(
Comparator.comparingInt(Employee::salary)
.reversed()
// If salaries are equal, sort by name.
.thenComparing(Employee::name)
);
// Print each employee.
employees.forEach(employee ->
System.out.println(
employee.name() + " " + employee.salary()
)
);
}
}Answer
Bob 90000
Alice 70000
Carol 70000Step-by-step explanation
Bob has the highest salary, so he comes first.
Alice and Carol both have
70000.The secondary comparator sorts equal salaries by name.
"Alice"comes before"Carol".
How to read the important code
"Sort employees by salary descending, then by name."
Beginner trap
A comparator defines how two objects should be ordered. It does not modify the meaning of the objects themselves.
Key takeaway
Comparators let you define flexible, readable sorting rules.
Chapter 11 — Files, Paths & Directories
Question
Given below is a code snippet that:
Creates a
Path.Checks whether a file exists.
Creates a directory.
Builds another path from the directory.
Uses modern NIO APIs.
What should be the output of the following code?
import java.nio.file.*;
public class Main {
public static void main(String[] args) throws Exception {
// Create a path representing a directory.
Path directory = Path.of("data");
// Create the directory if it does not already exist.
Files.createDirectories(directory);
// Build a file path inside that directory.
Path file = directory.resolve("users.txt");
// Create the file if it does not exist.
if (Files.notExists(file)) {
Files.createFile(file);
}
// Check whether the file now exists.
System.out.println(Files.exists(file));
// Display the path.
System.out.println(file);
}
}Answer
The first line is:
trueThe second line represents:
data/users.txtOn some operating systems, the path separator may appear differently.
Step-by-step explanation
Path.of("data")creates aPathobject.createDirectories()creates the directory if necessary.resolve("users.txt")creates a path inside that directory.createFile()creates the file.Files.exists()confirms that the file exists.
How to read the important code
"Create a Path for the data directory."
"Resolve users.txt relative to that directory."
Beginner trap
A Path object is not the file itself. It represents where the file or directory is located.
Key takeaway
Java NIO's
PathandFilesAPIs provide the modern way to work with the file system.
Chapter 12 — Reading & Writing Text Files
Question
Given below is a code snippet that:
Writes text to a file.
Reads the text back.
Stores file contents in a string.
Uses
Files.
What should be the output of the following code?
import java.nio.file.*;
public class Main {
public static void main(String[] args) throws Exception {
// Choose the file location.
Path file = Path.of("message.txt");
// Write text into the file.
Files.writeString(
file,
"Java\nBackend\nSpring"
);
// Read the entire file as one String.
String content = Files.readString(file);
// Display the content.
System.out.println(content);
}
}Answer
Java
Backend
SpringStep-by-step explanation
writeString()writes three lines.\nrepresents a line break.readString()reads the entire file.println()displays the resulting text.
How to read the important code
"Write this string to message.txt."
"Read the entire file into a String."
Beginner trap
File operations can fail—for example, because of permissions, missing directories, or disk problems. That's why these operations can throw exceptions.
Key takeaway
For straightforward text files,
Files.writeString()andFiles.readString()are convenient modern APIs.
Chapter 13 — Byte Streams, Character Streams & Buffered I/O
Question
Given below is a code snippet that:
Uses character-based file I/O.
Buffers file operations.
Reads a file line by line.
Counts lines without loading unnecessary processing into separate operations.
What should be the output of the following code?
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception {
// Create text in a file using a character writer.
try (BufferedWriter writer =
new BufferedWriter(new FileWriter("data.txt"))) {
// Write separate lines.
writer.write("Java");
writer.newLine();
writer.write("Spring");
writer.newLine();
writer.write("SQL");
}
int count = 0;
// Open the file for character-based reading.
try (BufferedReader reader =
new BufferedReader(new FileReader("data.txt"))) {
String line;
// Read one line at a time until the end of the file.
while ((line = reader.readLine()) != null) {
// Count each line.
count++;
}
}
// Display the number of lines.
System.out.println(count);
}
}Answer
3Step-by-step explanation
Three lines are written.
BufferedWriterwrites text efficiently through a buffer.BufferedReaderreads text line by line.The loop continues until
readLine()returnsnull.Three lines are encountered.
countbecomes3.
How to read the important code
"Open a buffered reader and keep reading lines until there are no more lines."
Beginner trap
Character streams are designed for text. Byte streams are used for raw binary data such as images, PDFs, and other binary files.
Key takeaway
Use character-oriented APIs for text and byte-oriented APIs for binary data.
Chapter 14 — Try-with-Resources & Resource Management
Question
Given below is a code snippet that:
Opens a resource.
Uses try-with-resources.
Automatically closes the resource.
Handles the resource without manually calling
close().
What should be the output of the following code?
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception {
// Open a resource that must eventually be closed.
try (BufferedReader reader =
new BufferedReader(
new StringReader("Java\nBackend"))) {
// Read the first line.
System.out.println(reader.readLine());
// Read the second line.
System.out.println(reader.readLine());
}
// The reader has automatically been closed here.
System.out.println("Resource closed");
}
}Answer
Java
Backend
Resource closedStep-by-step explanation
Java creates the
BufferedReader.The first
readLine()returns"Java".The second returns
"Backend".The try block finishes.
Java automatically closes the reader.
Execution continues after the try block.
How to read the important code
"Open the reader in a try-with-resources block and automatically close it when the block finishes."
Beginner trap
Try-with-resources works with objects implementing AutoCloseable.
Key takeaway
If a resource must be closed, try-with-resources is usually the safest and cleanest approach.
Chapter 15 — Java Date & Time API
Question
Given below is a code snippet that:
Uses
LocalDate.Adds days to a date.
Calculates the difference between dates.
Uses
LocalDateTime.Formats a date.
What should be the output of the following code?
import java.time.*;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
// Create a date.
LocalDate start = LocalDate.of(2026, 9, 6);
// Add seven days without modifying the original date.
LocalDate nextWeek = start.plusDays(7);
// Calculate the number of days between the two dates.
long days = Duration.between(
start.atStartOfDay(),
nextWeek.atStartOfDay()
).toDays();
// Create a date and time.
LocalDateTime meeting =
LocalDateTime.of(2026, 9, 6, 10, 30);
// Define the display format.
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
// Display the results.
System.out.println(start);
System.out.println(nextWeek);
System.out.println(days);
System.out.println(meeting.format(formatter));
}
}Answer
2026-09-06
2026-09-13
7
06-09-2026 10:30Step-by-step explanation
LocalDate.of()creates September 6, 2026.plusDays(7)creates September 13.The difference is seven days.
LocalDateTimeadditionally contains time.The formatter changes the display format.
How to read the important code
"Create a LocalDate for September sixth, twenty twenty-six."
"Add seven days to get the next date."
Beginner trap
Java's modern date/time classes are generally immutable. Calling plusDays() produces another date rather than changing the original.
Key takeaway
Use the
java.timeAPI instead of old date/time APIs for modern Java applications.
Chapter 16 — Regular Expressions
Question
Given below is a code snippet that:
Creates a regular expression.
Checks whether text matches it.
Validates a simple username format.
Uses
PatternandMatcher.
What should be the output of the following code?
import java.util.regex.*;
public class Main {
public static void main(String[] args) {
// Username must contain 3 to 10 letters or digits.
Pattern pattern =
Pattern.compile("^[A-Za-z0-9]{3,10}$");
// Test two usernames.
String first = "Alice123";
String second = "A@lice";
// Create matchers for the two strings.
Matcher firstMatcher = pattern.matcher(first);
Matcher secondMatcher = pattern.matcher(second);
// Check whether each complete string matches.
System.out.println(firstMatcher.matches());
System.out.println(secondMatcher.matches());
}
}Answer
true
falseStep-by-step explanation
^means the pattern starts at the beginning.[A-Za-z0-9]allows letters and digits.{3,10}requires between 3 and 10 characters.$means the pattern ends there."Alice123"satisfies those rules."A@lice"contains@, which is not allowed.
How to read the important code
"Create a pattern that requires three to ten letters or digits for the entire string."
Beginner trap
Regular expressions are powerful but can become difficult to read. Don't use an extremely complicated regex when ordinary Java code would be clearer.
Key takeaway
Regex is useful for pattern matching and validation of structured text.
Chapter 17 — Annotations
Question
Given below is a code snippet that:
Uses a built-in annotation.
Creates a custom annotation.
Reads annotation metadata through reflection.
Demonstrates that annotations can describe code.
What should be the output of the following code?
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface EntityInfo {
// Store metadata about the class.
String name();
}
@EntityInfo(name = "users")
class User {
// This method can be safely renamed with IDE support.
@Override
public String toString() {
return "User";
}
}
public class Main {
public static void main(String[] args) {
// Ask Java for the annotation attached to User.
EntityInfo info =
User.class.getAnnotation(EntityInfo.class);
// Read the annotation value.
System.out.println(info.name());
}
}Answer
usersStep-by-step explanation
@EntityInfois a custom annotation.It stores the value
"users".RetentionPolicy.RUNTIMEmeans the annotation remains available at runtime.User.classrepresents theUserclass itself.getAnnotation()retrieves the annotation.info.name()retrieves"users".
How to read the important code
"Get the EntityInfo annotation from the User class."
Beginner trap
Annotations generally describe or configure code. They don't automatically perform an action just because they exist. Frameworks can inspect annotations and then act on them.
Key takeaway
Annotations attach metadata to Java code and are heavily used by frameworks such as Spring and JPA.
Chapter 18 — Reflection
Question
Given below is a code snippet that:
Obtains a class at runtime.
Inspects its methods.
Finds a method by name.
Invokes the method dynamically.
What should be the output of the following code?
import java.lang.reflect.Method;
class User {
// A normal method.
public void greet() {
System.out.println("Hello from User");
}
}
public class Main {
public static void main(String[] args) throws Exception {
// Obtain metadata describing the User class.
Class<?> type = User.class;
// Create a User object dynamically.
Object user = type.getDeclaredConstructor().newInstance();
// Find the greet method by its name.
Method method = type.getMethod("greet");
// Invoke that method on the User object.
method.invoke(user);
}
}Answer
Hello from UserStep-by-step explanation
User.classgives us aClassobject describingUser.Reflection allows Java to inspect classes at runtime.
getDeclaredConstructor()finds the constructor.newInstance()creates the object.getMethod("greet")finds the method.invoke(user)executes that method.
How to read the important code
"Get the User class, find its greet method, and invoke it on a User object."
Beginner trap
Reflection is powerful, but it can make code harder to understand and can introduce performance, security, and maintainability concerns. Frameworks use it heavily, but ordinary application code should not use it unnecessarily.
Key takeaway
Reflection allows Java programs and frameworks to inspect and interact with classes dynamically at runtime.
Chapter 19 — Java Modules
Question
Given below is a code snippet that:
Demonstrates the concept of a Java module.
Declares module dependencies.
Controls which packages are exposed.
Shows the role of
module-info.java.
What should be the output of the following code?
// module-info.java
// Declare the module's name.
module com.example.app {
// Allow this module to use java.sql.
requires java.sql;
// Make this package available to other modules.
exports com.example.users;
}There is no normal console output from this file.
Answer
No console outputStep-by-step explanation
module-info.javadescribes a Java module.module com.example.appgives the module its name.requires java.sqldeclares a dependency.exports com.example.userssays that package is accessible to other modules.The file is configuration for the Java module system, not a normal executable program.
How to read the important code
"Declare the module com.example.app, require java.sql, and export the users package."
Beginner trap
Packages and modules are not the same thing.
A package organizes Java classes.
A module organizes packages and explicitly describes dependencies and exported packages.
Key takeaway
Java modules provide stronger boundaries and explicit dependencies between parts of a Java application.
Chapter 20 — JVM, Bytecode, Stack, Heap & References
Question
Given below is a code snippet that:
Creates an object.
Uses a reference variable.
Creates a local primitive variable.
Demonstrates two references pointing to the same object.
Shows object mutation through a reference.
What should be the output of the following code?
class User {
// Store mutable object state.
String name;
}
public class Main {
public static void main(String[] args) {
// Local primitive variable.
int number = 10;
// Create a User object.
User first = new User();
// Store data inside the object.
first.name = "Alice";
// Copy the reference, not the object itself.
User second = first;
// Modify the same object through the second reference.
second.name = "Bob";
// Print the value through the first reference.
System.out.println(first.name);
// Print the primitive value.
System.out.println(number);
}
}Answer
Bob
10Step-by-step explanation
new User()creates a User object.firstrefers to that object.first.namebecomes"Alice".second = firstcopies the reference.Both
firstandsecondtherefore refer to the same object.second.name = "Bob"changes that object'sname.first.nametherefore also sees"Bob".numberis an independent primitive value and remains10.
How to read the important code
"Create a User object and make first refer to it."
"Make second refer to the same User object."
This is an important distinction:
first = object reference
second = same object referenceIt does not mean Java created a second User.
Beginner trap
A variable containing an object does not contain the entire object itself. It contains a reference to the object.
Key takeaway
Understanding references is essential for understanding Java memory behavior, objects, collections and bugs involving shared state.
Chapter 21 — Garbage Collection & Object Lifetime
Question
Given below is a code snippet that:
Creates objects.
Changes references.
Makes an object unreachable.
Demonstrates that
System.gc()is only a request.Shows that Java manages object memory automatically.
What should be the output of the following code?
class User {
// Store a user's name.
String name;
User(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
// Create the first object.
User user = new User("Alice");
// Make user refer to a different object.
user = new User("Bob");
// The original Alice object is now unreachable.
System.gc();
// The Bob object is still reachable through user.
System.out.println(user.name);
}
}Answer
BobStep-by-step explanation
The first
Userobject contains"Alice".userrefers to that object.A second object containing
"Bob"is created.useris changed to refer to the Bob object.Nothing can reach the original Alice object anymore.
It becomes eligible for garbage collection.
System.gc()requests garbage collection, but Java does not guarantee that it happens immediately.The Bob object is still reachable.
Therefore
"Bob"is printed.
How to read the important code
"Create Alice, then make user refer to Bob. Alice is no longer reachable."
Beginner trap
Do not think:
"
System.gc()means garbage collection happens now."
It doesn't guarantee immediate collection.
Key takeaway
Garbage collection automatically reclaims memory occupied by objects that are no longer reachable.
Chapter 22 — JVM Performance & Memory Problems
Question
Given below is a code snippet that:
Creates a large number of objects.
Keeps references to those objects in a collection.
Demonstrates why memory can continue being used even when objects are no longer logically needed.
Shows an important source of memory pressure.
What should be the output of the following code?
import java.util.*;
public class Main {
public static void main(String[] args) {
// This list keeps references to every object we create.
List<byte[]> data = new ArrayList<>();
// Create many arrays and keep them in the list.
for (int i = 0; i < 1000; i++) {
// Allocate 1 KB of memory.
byte[] block = new byte[1024];
// Keep the reference in the list.
data.add(block);
}
// The list still references every allocated array.
System.out.println(data.size());
// Remove all references held by the list.
data.clear();
// The arrays are now eligible for garbage collection
// if no other references exist.
System.out.println(data.size());
}
}Answer
1000
0Step-by-step explanation
datastarts as an empty list.The loop runs 1000 times.
Each iteration creates a new 1 KB byte array.
The array reference is added to
data.The list therefore holds 1000 references.
data.size()returns1000.clear()removes those references from the list.The arrays may now become eligible for garbage collection, assuming nothing else references them.
data.size()is now0.
How to read the important code
"Create a list that holds references to byte arrays."
"Add one array per iteration."
"Clear the list so it no longer keeps those references."
Beginner trap
Garbage collection only considers whether objects are reachable. If your application accidentally keeps references to objects it no longer needs, garbage collection cannot reclaim those objects.
This is one way applications can experience memory problems.
Key takeaway
Java manages memory automatically, but your program is still responsible for not unnecessarily retaining references.
Phase 3 — What You Should Now Understand
You have now covered the major Modern & Advanced Core Java layer.
The progression was:
Functional Interfaces
↓
Lambda Expressions
↓
Method References
↓
Optional
↓
Streams
↓
map / filter / flatMap
↓
Advanced Stream Operations
↓
Collectors
↓
Collections + Comparators
↓
Files + NIO
↓
Buffered I/O
↓
Resource Management
↓
Date & Time
↓
Regular Expressions
↓
Annotations
↓
Reflection
↓
Modules
↓
JVM + References
↓
Garbage Collection
↓
Memory + PerformanceThe most important mental models from Phase 3
1. Lambda
Think:
"I am passing behavior."
price -> price * 0.102. Stream
Think:
"I have data, and I'm building a pipeline to process it."
data.stream()
.filter(...)
.map(...)
.collect(...);3. map vs flatMap
Think:
map → one input → one transformed output
flatMap → one input → multiple values → flattened4. Collection vs Stream
Collection
↓
stores data
Stream
↓
processes data5. Optional
Think:
"This value might not exist."
6. Path + Files
Think:
"Path tells me where; Files performs the operation."
7. Reference
Think:
User first ─────┐
↓
[User]
↑
User second ────┘Two variables can refer to the same object.
8. Garbage collection
Think:
Reachable object
↓
stays alive
Unreachable object
↓
eligible for GCBut:
Eligible for garbage collection ≠ immediately garbage collected.
One important correction to your mental model
You don't need to memorize every API from this phase.
For professional Java, the high-value concepts to become really comfortable with are:
Lambdas → Functional Interfaces → Streams → Collectors → Collections → Generics → Optional → NIO → Date/Time → Exceptions → References → JVM/GC.
Reflection, modules, annotations and lower-level JVM details become particularly important when you start using frameworks such as Spring, Hibernate and testing libraries.
Phase 4 will build directly on this foundation: Concurrency + Networking + HTTP + JSON + APIs.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.