Modern Java Types
Optional
Avoiding Null
Your findUser(id) method might not find a user. Returning null leads to
NullPointerException when callers forget to check. Optional
Create Optional values
Wrap values in Optional.
// Creating and checking Optional values
// Concept: Optional - container for potentially absent value
import java.util.Optional;
public class CreatingOptional {
public static void main(String[] args) {
// Create Optional with value
Optional<String> present = Optional.of("Hello");
System.out.println("Present: " + present);
// Create Optional from nullable value
String nullable = ;
Optional<String> maybe1 = Optional.ofNullable(nullable);
System.out.println("Maybe 1: " + maybe1);
nullable = null;
Optional<String> maybe2 = Optional.ofNullable(nullable);
System.out.println("Maybe 2: " + maybe2);
// Create empty Optional
Optional<String> empty = Optional.empty();
System.out.println("Empty: " + empty);
// Check if value is present
System.out.println("\nChecking presence:");
System.out.println("present.isPresent(): " + present.isPresent());
System.out.println("empty.isPresent(): " + empty.isPresent());
// isEmpty (Java 11+)
System.out.println("\npresent.isEmpty(): " + present.isEmpty());
System.out.println("empty.isEmpty(): " + empty.isEmpty());
// Get value if present
if (present.isPresent()) {
String value = present.get();
System.out.println("\nValue: " + value);
}
if (empty.isPresent()) {
System.out.println("This won't print");
} else {
System.out.println("Empty has no value");
}
// Example with numbers
Optional<Integer> num1 = Optional.of(42);
Optional<Integer> num2 = Optional.ofNullable(null);
System.out.println("\nNumbers:");
System.out.println("num1: " + num1);
System.out.println("num2: " + num2);
System.out.println("num1 present: " + num1.isPresent());
System.out.println("num2 present: " + num2.isPresent());
}
}
// Creating and checking Optional values
// Concept: Optional - container for potentially absent value
import java.util.Optional;
public class CreatingOptional {
public static void main(String[] args) {
// Create Optional with value
Optional<String> present = Optional.of("Hello");
System.out.println("Present: " + present);
// Create Optional from nullable value
String nullable = ;
Optional<String> maybe1 = Optional.ofNullable(nullable);
System.out.println("Maybe 1: " + maybe1);
nullable = null;
Optional<String> maybe2 = Optional.ofNullable(nullable);
System.out.println("Maybe 2: " + maybe2);
// Create empty Optional
Optional<String> empty = Optional.empty();
System.out.println("Empty: " + empty);
// Check if value is present
System.out.println("\nChecking presence:");
System.out.println("present.isPresent(): " + present.isPresent());
System.out.println("empty.isPresent(): " + empty.isPresent());
// isEmpty (Java 11+)
System.out.println("\npresent.isEmpty(): " + present.isEmpty());
System.out.println("empty.isEmpty(): " + empty.isEmpty());
// Get value if present
if (present.isPresent()) {
String value = present.get();
System.out.println("\nValue: " + value);
}
if (empty.isPresent()) {
System.out.println("This won't print");
} else {
System.out.println("Empty has no value");
}
// Example with numbers
Optional<Integer> num1 = Optional.of(42);
Optional<Integer> num2 = Optional.ofNullable(null);
System.out.println("\nNumbers:");
System.out.println("num1: " + num1);
System.out.println("num2: " + num2);
System.out.println("num1 present: " + num1.isPresent());
System.out.println("num2 present: " + num2.isPresent());
}
}
// Creating and checking Optional values
// Concept: Optional - container for potentially absent value
import java.util.Optional;
public class CreatingOptional {
public static void main(String[] args) {
// Create Optional with value
Optional<String> present = Optional.of("Hello");
System.out.println("Present: " + present);
// Create Optional from nullable value
String nullable = ;
Optional<String> maybe1 = Optional.ofNullable(nullable);
System.out.println("Maybe 1: " + maybe1);
nullable = null;
Optional<String> maybe2 = Optional.ofNullable(nullable);
System.out.println("Maybe 2: " + maybe2);
// Create empty Optional
Optional<String> empty = Optional.empty();
System.out.println("Empty: " + empty);
// Check if value is present
System.out.println("\nChecking presence:");
System.out.println("present.isPresent(): " + present.isPresent());
System.out.println("empty.isPresent(): " + empty.isPresent());
// isEmpty (Java 11+)
System.out.println("\npresent.isEmpty(): " + present.isEmpty());
System.out.println("empty.isEmpty(): " + empty.isEmpty());
// Get value if present
if (present.isPresent()) {
String value = present.get();
System.out.println("\nValue: " + value);
}
if (empty.isPresent()) {
System.out.println("This won't print");
} else {
System.out.println("Empty has no value");
}
// Example with numbers
Optional<Integer> num1 = Optional.of(42);
Optional<Integer> num2 = Optional.ofNullable(null);
System.out.println("\nNumbers:");
System.out.println("num1: " + num1);
System.out.println("num2: " + num2);
System.out.println("num1 present: " + num1.isPresent());
System.out.println("num2 present: " + num2.isPresent());
}
}
Optional.of() for non-null, Optional.ofNullable() for maybe-null, Optional.empty() for absent.
Check and use values
Handle present and absent cases.
// ifPresent and ifPresentOrElse
// Concept: ifPresent - execute action if value exists
import java.util.Optional;
public class IfPresent {
public static void main(String[] args) {
// ifPresent - do something if value exists
Optional<String> name = ;
System.out.println("Using ifPresent:");
name.ifPresent(value -> System.out.println(" Hello, " + value));
Optional<String> empty = Optional.empty();
empty.ifPresent(value -> System.out.println(" This won't print"));
// ifPresentOrElse (Java 9+)
System.out.println("\nUsing ifPresentOrElse:");
name.ifPresentOrElse(
value -> System.out.println(" Found: " + value),
() -> System.out.println(" Not found")
);
empty.ifPresentOrElse(
value -> System.out.println(" Found: " + value),
() -> System.out.println(" Not found")
);
// Process multiple optionals
Optional<Integer>[] scores = new Optional[] {
Optional.of(85),
Optional.empty(),
Optional.of(92),
Optional.of(78)
};
System.out.println("\nProcessing scores:");
for (int i = 0; i < scores.length; i++) {
int index = i;
scores[i].ifPresent(score ->
System.out.println(" Score " + index + ": " + score)
);
}
// Accumulate values
System.out.println("\nAccumulating:");
int[] sum = {0};
int[] count = {0};
for (Optional<Integer> score : scores) {
score.ifPresent(value -> {
sum[0] += value;
count[0]++;
});
}
if (count[0] > 0) {
double average = (double) sum[0] / count[0];
System.out.printf(" Average: %.1f%n", average);
}
// Log if missing
System.out.println("\nLogging:");
Optional<String> config = Optional.empty();
config.ifPresentOrElse(
value -> System.out.println(" Config: " + value),
() -> System.out.println(" WARNING: Config not found")
);
}
}
// ifPresent and ifPresentOrElse
// Concept: ifPresent - execute action if value exists
import java.util.Optional;
public class IfPresent {
public static void main(String[] args) {
// ifPresent - do something if value exists
Optional<String> name = ;
System.out.println("Using ifPresent:");
name.ifPresent(value -> System.out.println(" Hello, " + value));
Optional<String> empty = Optional.empty();
empty.ifPresent(value -> System.out.println(" This won't print"));
// ifPresentOrElse (Java 9+)
System.out.println("\nUsing ifPresentOrElse:");
name.ifPresentOrElse(
value -> System.out.println(" Found: " + value),
() -> System.out.println(" Not found")
);
empty.ifPresentOrElse(
value -> System.out.println(" Found: " + value),
() -> System.out.println(" Not found")
);
// Process multiple optionals
Optional<Integer>[] scores = new Optional[] {
Optional.of(85),
Optional.empty(),
Optional.of(92),
Optional.of(78)
};
System.out.println("\nProcessing scores:");
for (int i = 0; i < scores.length; i++) {
int index = i;
scores[i].ifPresent(score ->
System.out.println(" Score " + index + ": " + score)
);
}
// Accumulate values
System.out.println("\nAccumulating:");
int[] sum = {0};
int[] count = {0};
for (Optional<Integer> score : scores) {
score.ifPresent(value -> {
sum[0] += value;
count[0]++;
});
}
if (count[0] > 0) {
double average = (double) sum[0] / count[0];
System.out.printf(" Average: %.1f%n", average);
}
// Log if missing
System.out.println("\nLogging:");
Optional<String> config = Optional.empty();
config.ifPresentOrElse(
value -> System.out.println(" Config: " + value),
() -> System.out.println(" WARNING: Config not found")
);
}
}
// ifPresent and ifPresentOrElse
// Concept: ifPresent - execute action if value exists
import java.util.Optional;
public class IfPresent {
public static void main(String[] args) {
// ifPresent - do something if value exists
Optional<String> name = ;
System.out.println("Using ifPresent:");
name.ifPresent(value -> System.out.println(" Hello, " + value));
Optional<String> empty = Optional.empty();
empty.ifPresent(value -> System.out.println(" This won't print"));
// ifPresentOrElse (Java 9+)
System.out.println("\nUsing ifPresentOrElse:");
name.ifPresentOrElse(
value -> System.out.println(" Found: " + value),
() -> System.out.println(" Not found")
);
empty.ifPresentOrElse(
value -> System.out.println(" Found: " + value),
() -> System.out.println(" Not found")
);
// Process multiple optionals
Optional<Integer>[] scores = new Optional[] {
Optional.of(85),
Optional.empty(),
Optional.of(92),
Optional.of(78)
};
System.out.println("\nProcessing scores:");
for (int i = 0; i < scores.length; i++) {
int index = i;
scores[i].ifPresent(score ->
System.out.println(" Score " + index + ": " + score)
);
}
// Accumulate values
System.out.println("\nAccumulating:");
int[] sum = {0};
int[] count = {0};
for (Optional<Integer> score : scores) {
score.ifPresent(value -> {
sum[0] += value;
count[0]++;
});
}
if (count[0] > 0) {
double average = (double) sum[0] / count[0];
System.out.printf(" Average: %.1f%n", average);
}
// Log if missing
System.out.println("\nLogging:");
Optional<String> config = Optional.empty();
config.ifPresentOrElse(
value -> System.out.println(" Config: " + value),
() -> System.out.println(" WARNING: Config not found")
);
}
}
ifPresent() runs code only when value exists. Avoids null checks.
Provide defaults
Get value or use fallback.
// orElse, orElseGet, orElseThrow
// Concept: default values - providing fallbacks
import java.util.Optional;
public class Defaults {
public static void main(String[] args) {
// orElse - provide default value
Optional<String> name = ;
Optional<String> empty = Optional.empty();
String result1 = name.orElse("Unknown");
String result2 = empty.orElse("Unknown");
System.out.println("orElse:");
System.out.println(" name: " + result1);
System.out.println(" empty: " + result2);
// orElseGet - compute default lazily
System.out.println("\norElseGet:");
String r1 = name.orElseGet(() -> {
System.out.println(" Computing default...");
return "Generated";
});
System.out.println(" Result: " + r1);
String r2 = empty.orElseGet(() -> {
System.out.println(" Computing default...");
return "Generated";
});
System.out.println(" Result: " + r2);
// orElse vs orElseGet difference
System.out.println("\nDifference:");
System.out.println("With orElse:");
String x1 = name.orElse(expensiveDefault());
System.out.println("\nWith orElseGet:");
String x2 = name.orElseGet(() -> expensiveDefault());
// orElseThrow - require value
System.out.println("\norElseThrow:");
try {
String value = name.orElseThrow();
System.out.println(" Got value: " + value);
} catch (Exception e) {
System.out.println(" Error: " + e);
}
try {
String value = empty.orElseThrow();
System.out.println(" Got value: " + value);
} catch (Exception e) {
System.out.println(" Error: " + e.getClass().getSimpleName());
}
// orElseThrow with custom exception
try {
String value = empty.orElseThrow(() ->
new IllegalArgumentException("Value required")
);
} catch (IllegalArgumentException e) {
System.out.println(" Custom error: " + e.getMessage());
}
// Practical examples
System.out.println("\nPractical:");
Optional<Integer> port = Optional.empty();
int serverPort = port.orElse(8080);
System.out.println(" Server port: " + serverPort);
Optional<String> env = Optional.ofNullable(null);
String environment = env.orElseGet(() -> {
System.out.println(" Reading from config...");
return "development";
});
System.out.println(" Environment: " + environment);
Optional<String> apiKey = Optional.empty();
try {
String key = apiKey.orElseThrow(() ->
new RuntimeException("API key not configured")
);
} catch (RuntimeException e) {
System.out.println(" " + e.getMessage());
}
}
static String expensiveDefault() {
System.out.println(" Expensive computation!");
return "Default";
}
}
// orElse, orElseGet, orElseThrow
// Concept: default values - providing fallbacks
import java.util.Optional;
public class Defaults {
public static void main(String[] args) {
// orElse - provide default value
Optional<String> name = ;
Optional<String> empty = Optional.empty();
String result1 = name.orElse("Unknown");
String result2 = empty.orElse("Unknown");
System.out.println("orElse:");
System.out.println(" name: " + result1);
System.out.println(" empty: " + result2);
// orElseGet - compute default lazily
System.out.println("\norElseGet:");
String r1 = name.orElseGet(() -> {
System.out.println(" Computing default...");
return "Generated";
});
System.out.println(" Result: " + r1);
String r2 = empty.orElseGet(() -> {
System.out.println(" Computing default...");
return "Generated";
});
System.out.println(" Result: " + r2);
// orElse vs orElseGet difference
System.out.println("\nDifference:");
System.out.println("With orElse:");
String x1 = name.orElse(expensiveDefault());
System.out.println("\nWith orElseGet:");
String x2 = name.orElseGet(() -> expensiveDefault());
// orElseThrow - require value
System.out.println("\norElseThrow:");
try {
String value = name.orElseThrow();
System.out.println(" Got value: " + value);
} catch (Exception e) {
System.out.println(" Error: " + e);
}
try {
String value = empty.orElseThrow();
System.out.println(" Got value: " + value);
} catch (Exception e) {
System.out.println(" Error: " + e.getClass().getSimpleName());
}
// orElseThrow with custom exception
try {
String value = empty.orElseThrow(() ->
new IllegalArgumentException("Value required")
);
} catch (IllegalArgumentException e) {
System.out.println(" Custom error: " + e.getMessage());
}
// Practical examples
System.out.println("\nPractical:");
Optional<Integer> port = Optional.empty();
int serverPort = port.orElse(8080);
System.out.println(" Server port: " + serverPort);
Optional<String> env = Optional.ofNullable(null);
String environment = env.orElseGet(() -> {
System.out.println(" Reading from config...");
return "development";
});
System.out.println(" Environment: " + environment);
Optional<String> apiKey = Optional.empty();
try {
String key = apiKey.orElseThrow(() ->
new RuntimeException("API key not configured")
);
} catch (RuntimeException e) {
System.out.println(" " + e.getMessage());
}
}
static String expensiveDefault() {
System.out.println(" Expensive computation!");
return "Default";
}
}
orElse() provides default. orElseGet() computes default lazily.
Transform with map
Apply function to Optional's value.
// map and flatMap transformations
// Concept: transformation - converting Optional values
import java.util.Optional;
public class MapFlatmap {
public static void main(String[] args) {
// map - transform value if present
Optional<String> name = ;
Optional<String> upper = name.map(s -> s.toUpperCase());
System.out.println("Original: " + name);
System.out.println("Uppercase: " + upper);
Optional<Integer> length = name.map(s -> s.length());
System.out.println("Length: " + length);
// map on empty Optional
Optional<String> empty = Optional.empty();
Optional<String> result = empty.map(s -> s.toUpperCase());
System.out.println("\nEmpty mapped: " + result);
// Chain multiple maps
System.out.println("\nChained maps:");
Optional<String> processed = Optional.of(" hello ")
.map(s -> s.trim())
.map(s -> s.toUpperCase())
.map(s -> s + "!");
System.out.println("Result: " + processed.orElse(""));
// flatMap - when function returns Optional
Optional<String> userId = Optional.of("123");
Optional<User> user = userId.flatMap(id -> findUser(id));
System.out.println("\nUser: " + user);
Optional<String> email = userId
.flatMap(id -> findUser(id))
.map(u -> u.email);
System.out.println("Email: " + email);
// map vs flatMap
System.out.println("\nmap vs flatMap:");
// map wraps result in Optional
Optional<Optional<User>> nested = userId.map(id -> findUser(id));
System.out.println("map result: " + nested);
// flatMap doesn't wrap
Optional<User> flat = userId.flatMap(id -> findUser(id));
System.out.println("flatMap result: " + flat);
// Practical transformation pipeline
System.out.println("\nPipeline:");
Optional<String> input = Optional.of("42");
Optional<String> output = input
.map(s -> Integer.parseInt(s))
.map(n -> n * 2)
.map(n -> "Result: " + n);
output.ifPresent(System.out::println);
// Safe navigation
Optional<Integer> price = Optional.of("Product123")
.flatMap(id -> findProduct(id))
.map(p -> p.price);
System.out.println("\nProduct price: " + price.orElse(0));
}
static Optional<User> findUser(String id) {
if (id.equals("123")) {
return Optional.of(new User("Alice", "alice@example.com"));
}
return Optional.empty();
}
static Optional<Product> findProduct(String id) {
if (id.equals("Product123")) {
return Optional.of(new Product("Laptop", 999));
}
return Optional.empty();
}
static class User {
String name;
String email;
User(String name, String email) {
this.name = name;
this.email = email;
}
public String toString() {
return "User(" + name + ", " + email + ")";
}
}
static class Product {
String name;
int price;
Product(String name, int price) {
this.name = name;
this.price = price;
}
}
}
// map and flatMap transformations
// Concept: transformation - converting Optional values
import java.util.Optional;
public class MapFlatmap {
public static void main(String[] args) {
// map - transform value if present
Optional<String> name = ;
Optional<String> upper = name.map(s -> s.toUpperCase());
System.out.println("Original: " + name);
System.out.println("Uppercase: " + upper);
Optional<Integer> length = name.map(s -> s.length());
System.out.println("Length: " + length);
// map on empty Optional
Optional<String> empty = Optional.empty();
Optional<String> result = empty.map(s -> s.toUpperCase());
System.out.println("\nEmpty mapped: " + result);
// Chain multiple maps
System.out.println("\nChained maps:");
Optional<String> processed = Optional.of(" hello ")
.map(s -> s.trim())
.map(s -> s.toUpperCase())
.map(s -> s + "!");
System.out.println("Result: " + processed.orElse(""));
// flatMap - when function returns Optional
Optional<String> userId = Optional.of("123");
Optional<User> user = userId.flatMap(id -> findUser(id));
System.out.println("\nUser: " + user);
Optional<String> email = userId
.flatMap(id -> findUser(id))
.map(u -> u.email);
System.out.println("Email: " + email);
// map vs flatMap
System.out.println("\nmap vs flatMap:");
// map wraps result in Optional
Optional<Optional<User>> nested = userId.map(id -> findUser(id));
System.out.println("map result: " + nested);
// flatMap doesn't wrap
Optional<User> flat = userId.flatMap(id -> findUser(id));
System.out.println("flatMap result: " + flat);
// Practical transformation pipeline
System.out.println("\nPipeline:");
Optional<String> input = Optional.of("42");
Optional<String> output = input
.map(s -> Integer.parseInt(s))
.map(n -> n * 2)
.map(n -> "Result: " + n);
output.ifPresent(System.out::println);
// Safe navigation
Optional<Integer> price = Optional.of("Product123")
.flatMap(id -> findProduct(id))
.map(p -> p.price);
System.out.println("\nProduct price: " + price.orElse(0));
}
static Optional<User> findUser(String id) {
if (id.equals("123")) {
return Optional.of(new User("Alice", "alice@example.com"));
}
return Optional.empty();
}
static Optional<Product> findProduct(String id) {
if (id.equals("Product123")) {
return Optional.of(new Product("Laptop", 999));
}
return Optional.empty();
}
static class User {
String name;
String email;
User(String name, String email) {
this.name = name;
this.email = email;
}
public String toString() {
return "User(" + name + ", " + email + ")";
}
}
static class Product {
String name;
int price;
Product(String name, int price) {
this.name = name;
this.price = price;
}
}
}
// map and flatMap transformations
// Concept: transformation - converting Optional values
import java.util.Optional;
public class MapFlatmap {
public static void main(String[] args) {
// map - transform value if present
Optional<String> name = ;
Optional<String> upper = name.map(s -> s.toUpperCase());
System.out.println("Original: " + name);
System.out.println("Uppercase: " + upper);
Optional<Integer> length = name.map(s -> s.length());
System.out.println("Length: " + length);
// map on empty Optional
Optional<String> empty = Optional.empty();
Optional<String> result = empty.map(s -> s.toUpperCase());
System.out.println("\nEmpty mapped: " + result);
// Chain multiple maps
System.out.println("\nChained maps:");
Optional<String> processed = Optional.of(" hello ")
.map(s -> s.trim())
.map(s -> s.toUpperCase())
.map(s -> s + "!");
System.out.println("Result: " + processed.orElse(""));
// flatMap - when function returns Optional
Optional<String> userId = Optional.of("123");
Optional<User> user = userId.flatMap(id -> findUser(id));
System.out.println("\nUser: " + user);
Optional<String> email = userId
.flatMap(id -> findUser(id))
.map(u -> u.email);
System.out.println("Email: " + email);
// map vs flatMap
System.out.println("\nmap vs flatMap:");
// map wraps result in Optional
Optional<Optional<User>> nested = userId.map(id -> findUser(id));
System.out.println("map result: " + nested);
// flatMap doesn't wrap
Optional<User> flat = userId.flatMap(id -> findUser(id));
System.out.println("flatMap result: " + flat);
// Practical transformation pipeline
System.out.println("\nPipeline:");
Optional<String> input = Optional.of("42");
Optional<String> output = input
.map(s -> Integer.parseInt(s))
.map(n -> n * 2)
.map(n -> "Result: " + n);
output.ifPresent(System.out::println);
// Safe navigation
Optional<Integer> price = Optional.of("Product123")
.flatMap(id -> findProduct(id))
.map(p -> p.price);
System.out.println("\nProduct price: " + price.orElse(0));
}
static Optional<User> findUser(String id) {
if (id.equals("123")) {
return Optional.of(new User("Alice", "alice@example.com"));
}
return Optional.empty();
}
static Optional<Product> findProduct(String id) {
if (id.equals("Product123")) {
return Optional.of(new Product("Laptop", 999));
}
return Optional.empty();
}
static class User {
String name;
String email;
User(String name, String email) {
this.name = name;
this.email = email;
}
public String toString() {
return "User(" + name + ", " + email + ")";
}
}
static class Product {
String name;
int price;
Product(String name, int price) {
this.name = name;
this.price = price;
}
}
}
map() transforms value if present. flatMap() for nested Optionals.
Optional return types
Use Optional for methods that might not return a value.
// Optional in return types
// Concept: pattern - using Optional for method returns
import java.util.Optional;
import java.util.HashMap;
import java.util.Map;
public class ReturnTypes {
// Repository with Optional returns
static class UserRepository {
private Map<Integer, User> users = new HashMap<>();
UserRepository() {
users.put(1, new User(1, "Alice", "alice@example.com"));
users.put(2, new User(2, "Bob", "bob@example.com"));
}
// Return Optional instead of null
Optional<User> findById(int id) {
return Optional.ofNullable(users.get(id));
}
Optional<User> findByEmail(String email) {
return users.values().stream()
.filter(u -> u.email.equals(email))
.findFirst();
}
}
static class User {
int id;
String name;
String email;
User(int id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public String toString() {
return "User(" + id + ", " + name + ")";
}
}
public static void main(String[] args) {
UserRepository repo = new UserRepository();
// Call methods returning Optional
System.out.println("Finding users:");
Optional<User> user1 = repo.findById(1);
user1.ifPresent(u -> System.out.println(" Found: " + u));
Optional<User> user99 = repo.findById(99);
user99.ifPresentOrElse(
u -> System.out.println(" Found: " + u),
() -> System.out.println(" User 99 not found")
);
// Chain Optional operations
System.out.println("\nChained operations:");
String userName = repo.findById(1)
.map(u -> u.name)
.orElse("Unknown");
System.out.println(" User 1 name: " + userName);
String email = repo.findById(99)
.map(u -> u.email)
.orElse("no-email@example.com");
System.out.println(" User 99 email: " + email);
// Find by email
System.out.println("\nFind by email:");
repo.findByEmail("alice@example.com")
.ifPresent(u -> System.out.println(" Found: " + u));
repo.findByEmail("unknown@example.com")
.ifPresent(u -> System.out.println(" Won't print"));
// Configuration service
System.out.println("\nConfiguration:");
ConfigService config = new ConfigService();
int port = config.getPort().orElse(8080);
System.out.println(" Port: " + port);
String host = config.getHost().orElse("localhost");
System.out.println(" Host: " + host);
config.getApiKey().ifPresentOrElse(
key -> System.out.println(" API key: " + key),
() -> System.out.println(" WARNING: No API key configured")
);
// Error handling
System.out.println("\nWith error handling:");
try {
User user = repo.findById(99)
.orElseThrow(() -> new RuntimeException("User not found"));
} catch (RuntimeException e) {
System.out.println(" Error: " + e.getMessage());
}
// Transform to different type
Optional<String> welcomeMsg = repo.findById(2)
.map(u -> "Welcome, " + u.name + "!");
System.out.println("\n" + welcomeMsg.orElse("Welcome, Guest!"));
}
static class ConfigService {
Optional<Integer> getPort() {
return Optional.of(9090);
}
Optional<String> getHost() {
return Optional.empty(); // Not configured
}
Optional<String> getApiKey() {
return Optional.empty(); // Not configured
}
}
}
Return Optional<T> instead of nullable T. Caller knows to check.
Exercise: Practical.java
Refactor a service layer to use Optional