Deconstruction Patterns in Java: Complete Guide

Explore Java's powerful deconstruction patterns including Records, Pattern Matching, and advanced destructuring techniques.

Table of Contents

  1. Record Deconstruction
  2. Pattern Matching with instanceof
  3. Switch Expression Patterns
  4. Custom Deconstruction Patterns
  5. Advanced Nesting Patterns
  6. Real-World Use Cases

Record Deconstruction

1. Basic Record Deconstruction

// Basic record definition
public record Person(String name, int age, String email) {
// Compact constructor with validation
public Person {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
if (email != null && !email.contains("@")) {
throw new IllegalArgumentException("Invalid email format");
}
}
// Static factory method
public static Person of(String name, int age) {
return new Person(name, age, null);
}
}
// Deconstruction examples
public class RecordDeconstruction {
public static void main(String[] args) {
// Create record instance
Person person = new Person("Alice", 30, "[email protected]");
// Traditional accessors
String name = person.name();
int age = person.age();
String email = person.email();
// Deconstruction in Java 16+ (conceptual - not actual syntax)
// This demonstrates the concept that will be available in future versions
System.out.println("Name: " + name + ", Age: " + age + ", Email: " + email);
}
// Method that demonstrates deconstruction concept
public static void processPerson(Person person) {
// Imagine future Java version supporting this:
// Person(String name, int age, String email) = person;
// Current approach - using accessors
String name = person.name();
int age = person.age();
String email = person.email();
System.out.printf("Processing %s (%d years old) - %s%n", name, age, email);
}
}

2. Advanced Record Patterns

// Complex record with nested records
public record Address(String street, String city, String zipCode, String country) {
public Address {
if (street == null || street.isBlank()) {
throw new IllegalArgumentException("Street cannot be empty");
}
}
public String format() {
return String.format("%s, %s %s, %s", street, city, zipCode, country);
}
}
public record Employee(
String id,
Person person,
Address address,
String department,
double salary
) {
public Employee {
if (salary < 0) {
throw new IllegalArgumentException("Salary cannot be negative");
}
}
public boolean isRemote() {
return address.city().equals("REMOTE");
}
}
// Record pattern matching examples
public class AdvancedRecordPatterns {
// Traditional approach to extracting data
public static void printEmployeeInfoTraditional(Employee employee) {
Person person = employee.person();
Address address = employee.address();
String name = person.name();
String city = address.city();
System.out.printf("Employee %s works in %s%n", name, city);
}
// Using method to simulate pattern matching
public static void extractEmployeeData(Employee employee) {
// Simulating what pattern matching might look like
String id = employee.id();
Person person = employee.person();
Address address = employee.address();
String department = employee.department();
double salary = employee.salary();
// Process extracted data
if (salary > 100000) {
System.out.printf("High earner: %s in %s%n", 
person.name(), department);
}
}
// Process multiple records
public static void processEmployees(List<Employee> employees) {
for (Employee emp : employees) {
// Extract nested data
String empName = emp.person().name();
String empCity = emp.address().city();
double empSalary = emp.salary();
System.out.printf("%s in %s earns $%.2f%n", 
empName, empCity, empSalary);
}
}
}

Pattern Matching with instanceof

3. Type Pattern Matching

// Hierarchy of shapes
public sealed interface Shape 
permits Circle, Rectangle, Triangle, CompositeShape {
double area();
double perimeter();
}
public record Circle(double radius) implements Shape {
public Circle {
if (radius <= 0) {
throw new IllegalArgumentException("Radius must be positive");
}
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public double perimeter() {
return 2 * Math.PI * radius;
}
}
public record Rectangle(double width, double height) implements Shape {
public Rectangle {
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("Dimensions must be positive");
}
}
@Override
public double area() {
return width * height;
}
@Override
public double perimeter() {
return 2 * (width + height);
}
public boolean isSquare() {
return width == height;
}
}
public record Triangle(double side1, double side2, double side3) implements Shape {
public Triangle {
if (side1 <= 0 || side2 <= 0 || side3 <= 0) {
throw new IllegalArgumentException("Sides must be positive");
}
// Triangle inequality validation
if (side1 + side2 <= side3 || 
side1 + side3 <= side2 || 
side2 + side3 <= side1) {
throw new IllegalArgumentException("Invalid triangle sides");
}
}
@Override
public double area() {
// Heron's formula
double s = perimeter() / 2;
return Math.sqrt(s * (s - side1) * (s - side2) * (s - side3));
}
@Override
public double perimeter() {
return side1 + side2 + side3;
}
}
public record CompositeShape(String name, List<Shape> components) implements Shape {
public CompositeShape {
if (components == null || components.isEmpty()) {
throw new IllegalArgumentException("Components cannot be empty");
}
}
@Override
public double area() {
return components.stream()
.mapToDouble(Shape::area)
.sum();
}
@Override
public double perimeter() {
// For composite shapes, perimeter might not be well-defined
return components.stream()
.mapToDouble(Shape::perimeter)
.sum();
}
}
// Pattern matching with instanceof
public class InstanceOfPatternMatching {
// Traditional instanceof with casting
public static String describeShapeTraditional(Shape shape) {
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
return String.format("Circle with radius %.2f (area: %.2f)", 
circle.radius(), circle.area());
} else if (shape instanceof Rectangle) {
Rectangle rect = (Rectangle) shape;
return String.format("Rectangle %.2f x %.2f (area: %.2f)", 
rect.width(), rect.height(), rect.area());
} else if (shape instanceof Triangle) {
Triangle tri = (Triangle) shape;
return String.format("Triangle with sides %.2f, %.2f, %.2f", 
tri.side1(), tri.side2(), tri.side3());
} else {
return "Unknown shape";
}
}
// Modern pattern matching with instanceof (Java 16+)
public static String describeShapeModern(Shape shape) {
if (shape instanceof Circle circle) {
return String.format("Circle with radius %.2f (area: %.2f)", 
circle.radius(), circle.area());
} else if (shape instanceof Rectangle rect) {
String type = rect.isSquare() ? "Square" : "Rectangle";
return String.format("%s %.2f x %.2f (area: %.2f)", 
type, rect.width(), rect.height(), rect.area());
} else if (shape instanceof Triangle tri) {
return String.format("Triangle with sides %.2f, %.2f, %.2f (perimeter: %.2f)", 
tri.side1(), tri.side2(), tri.side3(), tri.perimeter());
} else if (shape instanceof CompositeShape comp) {
return String.format("Composite shape '%s' with %d components (total area: %.2f)",
comp.name(), comp.components().size(), comp.area());
} else {
return "Unknown shape";
}
}
// Pattern matching with additional conditions
public static String analyzeShape(Shape shape) {
if (shape instanceof Circle circle && circle.radius() > 10) {
return "Large circle: " + circle.radius();
} else if (shape instanceof Rectangle rect && rect.isSquare()) {
return "Square with side: " + rect.width();
} else if (shape instanceof Triangle tri) {
if (tri.side1() == tri.side2() && tri.side2() == tri.side3()) {
return "Equilateral triangle";
} else if (tri.side1() == tri.side2() || 
tri.side1() == tri.side3() || 
tri.side2() == tri.side3()) {
return "Isosceles triangle";
} else {
return "Scalene triangle";
}
} else {
return "Other shape";
}
}
// Processing collections with pattern matching
public static void processShapes(List<Shape> shapes) {
for (Shape shape : shapes) {
if (shape instanceof Circle circle) {
System.out.printf("Processing circle (r=%.2f)%n", circle.radius());
} else if (shape instanceof Rectangle rect) {
System.out.printf("Processing rectangle (%.2fx%.2f)%n", 
rect.width(), rect.height());
}
// Additional processing...
}
}
}

Switch Expression Patterns

4. Enhanced Switch Patterns

// Domain models for different types of events
public sealed interface Event 
permits UserEvent, SystemEvent, AuditEvent, ErrorEvent {
String id();
Instant timestamp();
String source();
}
public record UserEvent(
String id,
Instant timestamp,
String source,
String userId,
String action,
Map<String, Object> metadata
) implements Event {}
public record SystemEvent(
String id,
Instant timestamp,
String source,
String component,
String operation,
Duration duration
) implements Event {}
public record AuditEvent(
String id,
Instant timestamp,
String source,
String auditor,
String target,
String action,
boolean success
) implements Event {}
public record ErrorEvent(
String id,
Instant timestamp,
String source,
String errorType,
String message,
String stackTrace,
Severity severity
) implements Event {
public enum Severity {
LOW, MEDIUM, HIGH, CRITICAL
}
}
// Switch pattern matching examples
public class SwitchPatternMatching {
// Traditional switch statement
public static String processEventTraditional(Event event) {
if (event instanceof UserEvent) {
UserEvent userEvent = (UserEvent) event;
return "User action: " + userEvent.action();
} else if (event instanceof SystemEvent) {
SystemEvent sysEvent = (SystemEvent) event;
return "System operation: " + sysEvent.operation();
} else if (event instanceof AuditEvent) {
AuditEvent auditEvent = (AuditEvent) event;
return "Audit: " + auditEvent.action() + " - " + 
(auditEvent.success() ? "SUCCESS" : "FAILED");
} else if (event instanceof ErrorEvent) {
ErrorEvent errorEvent = (ErrorEvent) event;
return "Error: " + errorEvent.message();
} else {
return "Unknown event";
}
}
// Modern switch expression with pattern matching (Java 21+ preview)
public static String processEventModern(Event event) {
return switch (event) {
case UserEvent userEvent -> 
String.format("User %s performed: %s", 
userEvent.userId(), userEvent.action());
case SystemEvent sysEvent when sysEvent.duration().toMinutes() > 5 -> 
String.format("Long system operation: %s took %d minutes",
sysEvent.operation(), sysEvent.duration().toMinutes());
case SystemEvent sysEvent -> 
String.format("System operation: %s completed", sysEvent.operation());
case AuditEvent auditEvent when !auditEvent.success() -> 
String.format("AUDIT FAILURE: %s on %s", 
auditEvent.action(), auditEvent.target());
case AuditEvent auditEvent -> 
String.format("Audit: %s completed successfully", auditEvent.action());
case ErrorEvent errorEvent when errorEvent.severity() == ErrorEvent.Severity.CRITICAL -> 
String.format("CRITICAL ERROR: %s - %s", 
errorEvent.errorType(), errorEvent.message());
case ErrorEvent errorEvent -> 
String.format("Error [%s]: %s", 
errorEvent.severity(), errorEvent.message());
default -> "Unknown event type";
};
}
// Complex pattern matching with nested extraction
public static void analyzeEvents(List<Event> events) {
for (Event event : events) {
String analysis = switch (event) {
case UserEvent(var id, var timestamp, var source, 
var userId, var action, var metadata) -> {
if (action.equals("LOGIN")) {
yield String.format("User %s logged in from %s", userId, source);
} else if (action.equals("LOGOUT")) {
yield String.format("User %s logged out", userId);
} else {
yield String.format("User %s performed %s", userId, action);
}
}
case SystemEvent(var id, var timestamp, var source,
var component, var operation, var duration) 
when duration.toSeconds() > 60 -> {
yield String.format("Slow system operation: %s.%s took %d seconds",
component, operation, duration.toSeconds());
}
case ErrorEvent(var id, var timestamp, var source,
var errorType, var message, var stackTrace, var severity)
when severity == ErrorEvent.Severity.HIGH -> {
yield String.format("High severity error in %s: %s", source, message);
}
case null -> "Null event encountered";
default -> "Event type: " + event.getClass().getSimpleName();
};
System.out.println(analysis);
}
}
// Pattern matching with guards and complex conditions
public static String categorizeEvent(Event event) {
return switch (event) {
case UserEvent user when user.action().contains("DELETE") -> 
"DESTRUCTIVE_USER_ACTION";
case UserEvent user when user.action().contains("CREATE") -> 
"CREATIVE_USER_ACTION";
case SystemEvent sys when sys.duration().toMillis() > 5000 -> 
"LONG_RUNNING_SYSTEM_OPERATION";
case SystemEvent sys when sys.component().equals("DATABASE") -> 
"DATABASE_OPERATION";
case AuditEvent audit when !audit.success() -> 
"AUDIT_FAILURE";
case ErrorEvent error when error.severity() == ErrorEvent.Severity.CRITICAL -> 
"CRITICAL_FAILURE";
case ErrorEvent error when error.message().contains("timeout") -> 
"TIMEOUT_ERROR";
default -> "STANDARD_EVENT";
};
}
}

Custom Deconstruction Patterns

5. Creating Custom Destructuring Methods

// Traditional class with custom deconstruction
public class ComplexNumber {
private final double real;
private final double imaginary;
public ComplexNumber(double real, double imaginary) {
this.real = real;
this.imaginary = imaginary;
}
// Traditional getters
public double getReal() { return real; }
public double getImaginary() { return imaginary; }
// Custom deconstruction method
public ComplexParts deconstruct() {
return new ComplexParts(real, imaginary);
}
// Static factory method for construction
public static ComplexNumber of(double real, double imaginary) {
return new ComplexNumber(real, imaginary);
}
// Record for deconstructed parts
public record ComplexParts(double real, double imaginary) {
public ComplexNumber toComplexNumber() {
return new ComplexNumber(real, imaginary);
}
}
@Override
public String toString() {
return String.format("%.2f + %.2fi", real, imaginary);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ComplexNumber that)) return false;
return Double.compare(that.real, real) == 0 && 
Double.compare(that.imaginary, imaginary) == 0;
}
@Override
public int hashCode() {
return Objects.hash(real, imaginary);
}
}
// Custom container with deconstruction support
public class Pair<A, B> {
private final A first;
private final B second;
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
public A first() { return first; }
public B second() { return second; }
// Deconstruction method
public Object[] deconstruct() {
return new Object[]{first, second};
}
// Pattern matching support method
public boolean matches(Class<A> firstType, Class<B> secondType) {
return firstType.isInstance(first) && secondType.isInstance(second);
}
@Override
public String toString() {
return String.format("Pair[%s, %s]", first, second);
}
// Static factory
public static <A, B> Pair<A, B> of(A first, B second) {
return new Pair<>(first, second);
}
}
// Custom deconstruction examples
public class CustomDeconstruction {
public static void processComplexNumber(ComplexNumber cn) {
// Traditional approach
double real = cn.getReal();
double imaginary = cn.getImaginary();
// Using custom deconstruction
ComplexNumber.ComplexParts parts = cn.deconstruct();
double r = parts.real();
double i = parts.imaginary();
System.out.printf("Complex number: %.2f + %.2fi%n", r, i);
}
public static void processPair(Pair<?, ?> pair) {
Object[] components = pair.deconstruct();
Object first = components[0];
Object second = components[1];
System.out.printf("Pair contains: %s and %s%n", first, second);
// Type-safe processing with pattern matching simulation
if (pair.matches(String.class, Integer.class)) {
@SuppressWarnings("unchecked")
Pair<String, Integer> stringIntPair = (Pair<String, Integer>) pair;
processStringIntPair(stringIntPair);
}
}
private static void processStringIntPair(Pair<String, Integer> pair) {
String name = pair.first();
Integer value = pair.second();
System.out.printf("String-Integer pair: %s -> %d%n", name, value);
}
// Advanced deconstruction with multiple return values
public static class DataPoint {
private final String label;
private final double[] values;
private final Map<String, Object> metadata;
public DataPoint(String label, double[] values, Map<String, Object> metadata) {
this.label = label;
this.values = values.clone(); // Defensive copy
this.metadata = new HashMap<>(metadata);
}
// Multiple deconstruction options
public BasicComponents deconstructBasic() {
return new BasicComponents(label, values.length);
}
public FullComponents deconstructFull() {
return new FullComponents(label, values, metadata);
}
public record BasicComponents(String label, int valueCount) {}
public record FullComponents(String label, double[] values, Map<String, Object> metadata) {}
public String label() { return label; }
public double[] values() { return values.clone(); } // Defensive copy
public Map<String, Object> metadata() { return new HashMap<>(metadata); }
}
}

Advanced Nesting Patterns

6. Complex Nested Pattern Matching

// Complex domain model for e-commerce
public record Customer(
String id,
String name,
Address address,
List<Order> orders,
CustomerPreferences preferences
) {
public Customer {
if (orders == null) orders = new ArrayList<>();
if (preferences == null) preferences = new CustomerPreferences();
}
public boolean hasOrders() {
return !orders.isEmpty();
}
}
public record CustomerPreferences(
boolean emailNotifications,
boolean smsNotifications,
String currency,
String language,
List<String> favoriteCategories
) {
public CustomerPreferences {
if (favoriteCategories == null) favoriteCategories = new ArrayList<>();
if (currency == null) currency = "USD";
if (language == null) language = "en";
}
}
public record Order(
String orderId,
Instant orderDate,
List<OrderItem> items,
OrderStatus status,
PaymentInfo payment,
ShippingInfo shipping
) {
public double totalAmount() {
return items.stream()
.mapToDouble(item -> item.price() * item.quantity())
.sum();
}
public boolean isShippable() {
return status == OrderStatus.CONFIRMED || status == OrderStatus.PROCESSING;
}
}
public record OrderItem(
String productId,
String productName,
int quantity,
double price,
Map<String, String> attributes
) {
public double subtotal() {
return price * quantity;
}
}
public enum OrderStatus {
PENDING, CONFIRMED, PROCESSING, SHIPPED, DELIVERED, CANCELLED
}
public record PaymentInfo(
String paymentMethod,
String transactionId,
boolean paid,
Instant paymentDate
) {}
public record ShippingInfo(
Address shippingAddress,
String carrier,
String trackingNumber,
Instant estimatedDelivery
) {}
// Advanced nested pattern matching
public class NestedPatternMatching {
// Process customer with nested pattern matching simulation
public static void analyzeCustomer(Customer customer) {
// Extract nested data
String customerName = customer.name();
Address address = customer.address();
List<Order> orders = customer.orders();
CustomerPreferences prefs = customer.preferences();
// Process address
String city = address.city();
String country = address.country();
// Process preferences
boolean wantsEmails = prefs.emailNotifications();
String preferredCurrency = prefs.currency();
System.out.printf("Customer %s in %s, %s%n", customerName, city, country);
System.out.printf("Preferences: email=%s, currency=%s%n", wantsEmails, preferredCurrency);
// Process orders with nested data
for (Order order : orders) {
processOrder(order);
}
}
private static void processOrder(Order order) {
String orderId = order.orderId();
OrderStatus status = order.status();
double total = order.totalAmount();
List<OrderItem> items = order.items();
PaymentInfo payment = order.payment();
ShippingInfo shipping = order.shipping();
System.out.printf("Order %s: %s, Total: $%.2f%n", orderId, status, total);
// Process payment info
if (payment.paid()) {
System.out.printf("  Paid via %s on %s%n", 
payment.paymentMethod(), payment.paymentDate());
}
// Process shipping if applicable
if (order.isShippable() && shipping != null) {
System.out.printf("  Shipping to %s via %s%n", 
shipping.shippingAddress().city(), shipping.carrier());
}
// Process items
for (OrderItem item : items) {
processOrderItem(item);
}
}
private static void processOrderItem(OrderItem item) {
String productName = item.productName();
int quantity = item.quantity();
double price = item.price();
double subtotal = item.subtotal();
System.out.printf("  %d x %s @ $%.2f = $%.2f%n", 
quantity, productName, price, subtotal);
}
// Complex analysis with multiple levels of nesting
public static CustomerReport generateCustomerReport(Customer customer) {
String customerId = customer.id();
String customerName = customer.name();
Address address = customer.address();
List<Order> orders = customer.orders();
// Calculate statistics
long totalOrders = orders.size();
double totalSpent = orders.stream()
.mapToDouble(Order::totalAmount)
.sum();
double averageOrderValue = totalOrders > 0 ? totalSpent / totalOrders : 0;
// Analyze order status distribution
Map<OrderStatus, Long> statusCount = orders.stream()
.collect(Collectors.groupingBy(Order::status, Collectors.counting()));
// Find most expensive order
Optional<Order> mostExpensiveOrder = orders.stream()
.max(Comparator.comparing(Order::totalAmount));
return new CustomerReport(
customerId,
customerName,
address.city(),
address.country(),
totalOrders,
totalSpent,
averageOrderValue,
statusCount,
mostExpensiveOrder.map(Order::totalAmount).orElse(0.0)
);
}
public record CustomerReport(
String customerId,
String customerName,
String city,
String country,
long totalOrders,
double totalSpent,
double averageOrderValue,
Map<OrderStatus, Long> orderStatusDistribution,
double mostExpensiveOrder
) {
public void print() {
System.out.printf("Customer Report: %s (%s)%n", customerName, customerId);
System.out.printf("Location: %s, %s%n", city, country);
System.out.printf("Orders: %d, Total Spent: $%.2f, Avg Order: $%.2f%n", 
totalOrders, totalSpent, averageOrderValue);
System.out.println("Order Status Distribution:");
orderStatusDistribution.forEach((status, count) -> 
System.out.printf("  %s: %d%n", status, count));
System.out.printf("Most Expensive Order: $%.2f%n", mostExpensiveOrder);
}
}
// Pattern matching with collections
public static void processCustomerOrders(List<Customer> customers) {
for (Customer customer : customers) {
// Extract customer data
String customerName = customer.name();
List<Order> orders = customer.orders();
// Filter and process orders
List<Order> recentOrders = orders.stream()
.filter(order -> order.orderDate().isAfter(Instant.now().minusSeconds(30 * 24 * 60 * 60)))
.collect(Collectors.toList());
List<Order> highValueOrders = recentOrders.stream()
.filter(order -> order.totalAmount() > 1000)
.collect(Collectors.toList());
// Process high-value orders
for (Order order : highValueOrders) {
processHighValueOrder(customerName, order);
}
}
}
private static void processHighValueOrder(String customerName, Order order) {
System.out.printf("High value order from %s: %s - $%.2f%n", 
customerName, order.orderId(), order.totalAmount());
// Check if order needs special shipping
if (order.totalAmount() > 5000) {
System.out.println("  -> Requires premium shipping");
}
}
}

Real-World Use Cases

7. Practical Application Examples

// API Response processing with pattern matching
public class ApiResponseProcessor {
public sealed interface ApiResponse<T> 
permits Success, Error, Loading, Empty {
boolean isSuccess();
default boolean isError() { return !isSuccess(); }
}
public record Success<T>(T data, String message, int statusCode) implements ApiResponse<T> {
@Override
public boolean isSuccess() { return true; }
}
public record Error<T>(String errorCode, String message, Throwable cause) implements ApiResponse<T> {
@Override
public boolean isSuccess() { return false; }
}
public record Loading<T>(String progressMessage) implements ApiResponse<T> {
@Override
public boolean isSuccess() { return false; }
}
public record Empty<T>() implements ApiResponse<T> {
@Override
public boolean isSuccess() { return false; }
}
// Process API responses with pattern matching
public static <T> void handleApiResponse(ApiResponse<T> response) {
switch (response) {
case Success<T> success -> {
T data = success.data();
String message = success.message();
int statusCode = success.statusCode();
System.out.printf("Success (%d): %s%n", statusCode, message);
processSuccessData(data);
}
case Error<T> error -> {
String errorCode = error.errorCode();
String errorMessage = error.message();
Throwable cause = error.cause();
System.err.printf("Error %s: %s%n", errorCode, errorMessage);
if (cause != null) {
cause.printStackTrace();
}
}
case Loading<T> loading -> {
String progress = loading.progressMessage();
System.out.println("Loading: " + progress);
}
case Empty<T> empty -> {
System.out.println("No data available");
}
}
}
private static <T> void processSuccessData(T data) {
// Type-specific processing based on data type
if (data instanceof List<?> list) {
System.out.println("Received list with " + list.size() + " items");
} else if (data instanceof Map<?, ?> map) {
System.out.println("Received map with " + map.size() + " entries");
} else if (data instanceof String str) {
System.out.println("Received string: " + str);
} else {
System.out.println("Received data: " + data);
}
}
// Process multiple API responses
public static void processMultipleResponses(List<ApiResponse<?>> responses) {
for (ApiResponse<?> response : responses) {
if (response instanceof Success<?> success) {
Object data = success.data();
System.out.println("Processing successful response with data: " + data);
} else if (response instanceof Error<?> error) {
System.err.println("Error encountered: " + error.message());
}
}
}
}
// Configuration processing with deconstruction
public class ConfigurationProcessor {
public record DatabaseConfig(
String url,
String username,
String password,
int poolSize,
Map<String, String> properties
) {
public DatabaseConfig {
if (poolSize <= 0) {
throw new IllegalArgumentException("Pool size must be positive");
}
if (properties == null) {
properties = new HashMap<>();
}
}
}
public record ServerConfig(
String host,
int port,
boolean sslEnabled,
int maxConnections,
List<String> allowedOrigins
) {
public ServerConfig {
if (port < 1 || port > 65535) {
throw new IllegalArgumentException("Invalid port number");
}
if (allowedOrigins == null) {
allowedOrigins = new ArrayList<>();
}
}
}
public record AppConfig(
String name,
String version,
DatabaseConfig database,
ServerConfig server,
Map<String, Object> features
) {
public AppConfig {
if (features == null) {
features = new HashMap<>();
}
}
}
public static void validateAndProcessConfig(AppConfig config) {
// Deconstruct configuration
String appName = config.name();
String version = config.version();
DatabaseConfig dbConfig = config.database();
ServerConfig serverConfig = config.server();
Map<String, Object> features = config.features();
// Validate database configuration
validateDatabaseConfig(dbConfig);
// Validate server configuration  
validateServerConfig(serverConfig);
// Process features
processFeatures(features);
System.out.printf("Configuration validated for %s v%s%n", appName, version);
}
private static void validateDatabaseConfig(DatabaseConfig dbConfig) {
String url = dbConfig.url();
String username = dbConfig.username();
int poolSize = dbConfig.poolSize();
if (url == null || url.isBlank()) {
throw new IllegalArgumentException("Database URL is required");
}
if (username == null || username.isBlank()) {
throw new IllegalArgumentException("Database username is required");
}
if (poolSize > 100) {
System.out.println("Warning: Large connection pool size: " + poolSize);
}
}
private static void validateServerConfig(ServerConfig serverConfig) {
String host = serverConfig.host();
int port = serverConfig.port();
boolean sslEnabled = serverConfig.sslEnabled();
if (host == null || host.isBlank()) {
throw new IllegalArgumentException("Server host is required");
}
if (sslEnabled && port == 80) {
System.out.println("Warning: SSL enabled but using HTTP port 80");
}
}
private static void processFeatures(Map<String, Object> features) {
for (Map.Entry<String, Object> entry : features.entrySet()) {
String featureName = entry.getKey();
Object featureConfig = entry.getValue();
// Pattern matching on feature configuration type
if (featureConfig instanceof Boolean enabled) {
System.out.printf("Feature %s: %s%n", featureName, enabled ? "ENABLED" : "DISABLED");
} else if (featureConfig instanceof Map<?, ?> nestedConfig) {
System.out.printf("Feature %s has nested configuration with %d settings%n", 
featureName, nestedConfig.size());
} else if (featureConfig instanceof List<?> list) {
System.out.printf("Feature %s has list configuration with %d items%n", 
featureName, list.size());
}
}
}
}

This comprehensive guide covers Java's deconstruction patterns from basic record usage to advanced nested pattern matching, providing practical examples and real-world use cases for modern Java development.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper