Lambda Expressions Syntax in Java

Lambda expressions provide a clear and concise way to represent instances of single-method interfaces (functional interfaces) using expressions.

1. Basic Lambda Syntax

Basic Syntax Structure

import java.util.*; public class LambdaBasicSyntax { // Functional interfaces for demonstration @FunctionalInterface interface SimpleFunction { void execute(); } @FunctionalInterface interface StringProcessor { String process(String input); } @FunctionalInterface interface MathOperation { int operate(int a, int b); } @FunctionalInterface interface Validator { boolean isValid(String value); } public static void main(String[] args) { System.out.println("=== Basic Lambda Syntax ==="); // 1. No parameters, no return value SimpleFunction greet = () -> System.out.println("Hello, World!"); greet.execute(); // 2. Single parameter, no type declaration StringProcessor toUpper = s -> s.toUpperCase(); System.out.println("Uppercase: " + toUpper.process("hello")); // 3. Single parameter with parentheses (optional for single parameter) StringProcessor toLower = (s) -> s.toLowerCase(); System.out.println("Lowercase: " + toLower.process("HELLO")); // 4. Multiple parameters MathOperation addition = (a, b) -> a + b; System.out.println("5 + 3 = " + addition.operate(5, 3)); // 5. Multiple parameters with explicit types MathOperation subtraction = (int a, int b) -> a - b; System.out.println("5 - 3 = " + subtraction.operate(5, 3)); // 6. With return statement and curly braces MathOperation multiplication = (a, b) -> { int result = a * b; return result; }; System.out.println("5 * 3 = " + multiplication.operate(5, 3)); // 7. Single expression without return statement MathOperation division = (a, b) -> a / b; System.out.println("6 / 3 = " + division.operate(6, 3)); demonstrateMethodReferences(); } public static void demonstrateMethodReferences() { System.out.println("\n=== Method References vs Lambdas ==="); List<String> names = Arrays.asList("John", "Alice", "Bob", "Carol"); // Lambda expression names.forEach(name -> System.out.println(name)); // Method reference (equivalent) names.forEach(System.out::println); // Lambda for string transformation List<String> upperNames = new ArrayList<>(); names.forEach(name -> upperNames.add(name.toUpperCase())); // Method reference equivalent List<String> lowerNames = new ArrayList<>(); names.forEach(lowerNames::add); // Instance method reference System.out.println("Uppercase: " + upperNames); System.out.println("Lowercase: " + lowerNames); } }

Lambda vs Anonymous Class

import java.util.*; public class LambdaVsAnonymous { @FunctionalInterface interface Calculator { int calculate(int x, int y); } @FunctionalInterface interface Greeter { String greet(String name); } @FunctionalInterface interface Condition { boolean test(int number); } public static void main(String[] args) { System.out.println("=== Lambda vs Anonymous Class ==="); // Anonymous class implementation Calculator anonymousAdd = new Calculator() { @Override public int calculate(int x, int y) { return x + y; } }; // Lambda equivalent Calculator lambdaAdd = (x, y) -> x + y; System.out.println("Anonymous: 5 + 3 = " + anonymousAdd.calculate(5, 3)); System.out.println("Lambda: 5 + 3 = " + lambdaAdd.calculate(5, 3)); // More complex example Greeter anonymousGreet = new Greeter() { @Override public String greet(String name) { return "Hello, " + name + "!"; } }; Greeter lambdaGreet = name -> "Hello, " + name + "!"; System.out.println("Anonymous: " + anonymousGreet.greet("John")); System.out.println("Lambda: " + lambdaGreet.greet("John")); // With multiple statements Condition anonymousCondition = new Condition() { @Override public boolean test(int number) { boolean isEven = number % 2 == 0; boolean isPositive = number > 0; return isEven && isPositive; } }; Condition lambdaCondition = number -> { boolean isEven = number % 2 == 0; boolean isPositive = number > 0; return isEven && isPositive; }; System.out.println("Anonymous test(4): " + anonymousCondition.test(4)); System.out.println("Lambda test(4): " + lambdaCondition.test(4)); demonstrateRunnableExample(); } public static void demonstrateRunnableExample() { System.out.println("\n=== Runnable Example ==="); // Anonymous class Runnable anonymousRunnable = new Runnable() { @Override public void run() { System.out.println("Running from anonymous class"); System.out.println("Thread: " + Thread.currentThread().getName()); } }; // Lambda equivalent Runnable lambdaRunnable = () -> { System.out.println("Running from lambda"); System.out.println("Thread: " + Thread.currentThread().getName()); }; // Execute both new Thread(anonymousRunnable).start(); new Thread(lambdaRunnable).start(); // Even shorter lambda new Thread(() -> System.out.println("Ultra short lambda")).start(); } }

2. Lambda Parameters and Return Types

Various Parameter Scenarios

import java.util.*; import java.util.function.*; public class LambdaParameters { public static void main(String[] args) { System.out.println("=== Lambda Parameters and Return Types ==="); // 1. No parameters Supplier<String> messageSupplier = () -> "Hello from supplier!"; System.out.println(messageSupplier.get()); Runnable noParamRunnable = () -> System.out.println("No parameters"); noParamRunnable.run(); // 2. Single parameter - type inference Function<String, Integer> stringLength = s -> s.length(); System.out.println("Length of 'Hello': " + stringLength.apply("Hello")); Consumer<String> printer = s -> System.out.println("Value: " + s); printer.accept("Test"); // 3. Single parameter with explicit type Function<String, String> explicitType = (String s) -> s.toUpperCase(); System.out.println("Explicit type: " + explicitType.apply("hello")); // 4. Multiple parameters BiFunction<Integer, Integer, Integer> adder = (a, b) -> a + b; System.out.println("5 + 3 = " + adder.apply(5, 3)); // 5. Multiple parameters with explicit types BiFunction<String, String, String> concatenator = (String s1, String s2) -> s1 + " " + s2; System.out.println("Concatenated: " + concatenator.apply("Hello", "World")); // 6. No parameters with block body Supplier<Double> randomSupplier = () -> { Random random = new Random(); return random.nextDouble(); }; System.out.println("Random number: " + randomSupplier.get()); // 7. Complex multi-parameter lambda TriFunction<Integer, Integer, Integer, Integer> complexOperation = (a, b, c) -> { int sum = a + b + c; int product = a * b * c; return sum + product; }; System.out.println("Complex operation: " + complexOperation.apply(1, 2, 3)); demonstrateReturnTypes(); } // Custom functional interface for three parameters @FunctionalInterface interface TriFunction<T, U, V, R> { R apply(T t, U u, V v); } public static void demonstrateReturnTypes() { System.out.println("\n=== Return Type Examples ==="); // Implicit return (single expression) Function<Integer, Integer> square = x -> x * x; System.out.println("Square of 5: " + square.apply(5)); // Explicit return with block Function<Integer, String> numberInfo = x -> { if (x % 2 == 0) { return x + " is even"; } else { return x + " is odd"; } }; System.out.println(numberInfo.apply(4)); System.out.println(numberInfo.apply(7)); // Returning collections Function<Integer, List<Integer>> numberList = count -> { List<Integer> list = new ArrayList<>(); for (int i = 1; i <= count; i++) { list.add(i); } return list; }; System.out.println("Number list: " + numberList.apply(5)); // Void return type Consumer<List<String>> listProcessor = list -> { for (String item : list) { System.out.println("Processing: " + item.toUpperCase()); } }; listProcessor.accept(Arrays.asList("apple", "banana", "cherry")); } }

3. Built-in Functional Interfaces with Lambdas

java.util.function Package Examples

import java.util.*; import java.util.function.*; import java.util.stream.Collectors; public class BuiltInFunctionalInterfaces { public static void main(String[] args) { System.out.println("=== Built-in Functional Interfaces ==="); List<String> names = Arrays.asList("John", "Alice", "Bob", "Carol", "David", "Eve"); List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // 1. Predicate - boolean valued function System.out.println("\n=== Predicate Examples ==="); Predicate<String> startsWithA = s -> s.startsWith("A"); Predicate<String> lengthGreaterThan3 = s -> s.length() > 3; List<String> filteredNames = names.stream() .filter(startsWithA.or(lengthGreaterThan3)) .collect(Collectors.toList()); System.out.println("Filtered names: " + filteredNames); // Predicate composition Predicate<Integer> isEven = n -> n % 2 == 0; Predicate<Integer> isGreaterThan5 = n -> n > 5; List<Integer> evenAndGreaterThan5 = numbers.stream() .filter(isEven.and(isGreaterThan5)) .collect(Collectors.toList()); System.out.println("Even and > 5: " + evenAndGreaterThan5); // 2. Function - transforms input to output System.out.println("\n=== Function Examples ==="); Function<String, Integer> stringLength = String::length; Function<String, String> toUpperCase = String::toUpperCase; Function<String, String> addPrefix = s -> "Mr. " + s; List<Integer> nameLengths = names.stream() .map(stringLength) .collect(Collectors.toList()); System.out.println("Name lengths: " + nameLengths); // Function chaining Function<String, String> nameTransformer = toUpperCase.andThen(addPrefix); List<String> transformedNames = names.stream() .map(nameTransformer) .collect(Collectors.toList()); System.out.println("Transformed names: " + transformedNames); // 3. Consumer - accepts input, returns void System.out.println("\n=== Consumer Examples ==="); Consumer<String> simplePrinter = System.out::println; Consumer<String> detailedPrinter = s -> System.out.println("Name: " + s + ", Length: " + s.length()); System.out.println("Simple printing:"); names.forEach(simplePrinter); System.out.println("\nDetailed printing:"); names.forEach(detailedPrinter); // Consumer chaining Consumer<String> chainedConsumer = simplePrinter.andThen(detailedPrinter); System.out.println("\nChained consumer:"); chainedConsumer.accept("Test"); // 4. Supplier - provides results System.out.println("\n=== Supplier Examples ==="); Supplier<Double> randomSupplier = Math::random; Supplier<List<String>> listSupplier = ArrayList::new; Supplier<String> constantSupplier = () -> "Constant Value"; System.out.println("Random: " + randomSupplier.get()); System.out.println("Constant: " + constantSupplier.get()); System.out.println("New list: " + listSupplier.get()); // 5. UnaryOperator and BinaryOperator System.out.println("\n=== Operator Examples ==="); UnaryOperator<String> stringDoubler = s -> s + s; BinaryOperator<Integer> multiplier = (a, b) -> a * b; System.out.println("Double 'Hi': " + stringDoubler.apply("Hi")); System.out.println("5 * 3 = " + multiplier.apply(5, 3)); demonstrateMoreFunctionalInterfaces(); } public static void demonstrateMoreFunctionalInterfaces() { System.out.println("\n=== More Functional Interfaces ==="); List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // BiFunction - two inputs, one output BiFunction<Integer, Integer, String> sumFormatter = (a, b) -> String.format("%d + %d = %d", a, b, a + b); System.out.println("Sum format: " + sumFormatter.apply(5, 3)); // BiConsumer - two inputs, no output BiConsumer<String, Integer> nameAgePrinter = (name, age) -> System.out.println(name + " is " + age + " years old"); nameAgePrinter.accept("John", 25); // BiPredicate - two inputs, boolean output BiPredicate<String, String> sameLength = (s1, s2) -> s1.length() == s2.length(); System.out.println("Same length? " + sameLength.test("hello", "world")); // Specialized functional interfaces IntFunction<String> intToString = i -> "Number: " + i; ToIntFunction<String> stringToLength = String::length; IntUnaryOperator square = x -> x * x; System.out.println(intToString.apply(42)); System.out.println("Length of 'Hello': " + stringToLength.applyAsInt("Hello")); System.out.println("Square of 9: " + square.applyAsInt(9)); } }

4. Lambda Expressions with Collections

Using Lambdas with Java Collections

import java.util.*; import java.util.stream.Collectors; public class LambdaWithCollections { static class Person { String name; int age; String city; public Person(String name, int age, String city) { this.name = name; this.age = age; this.city = city; } public String getName() { return name; } public int getAge() { return age; } public String getCity() { return city; } @Override public String toString() { return String.format("Person{name='%s', age=%d, city='%s'}", name, age, city); } } public static void main(String[] args) { System.out.println("=== Lambda Expressions with Collections ==="); List<Person> people = Arrays.asList( new Person("John", 25, "New York"), new Person("Alice", 30, "Boston"), new Person("Bob", 22, "Chicago"), new Person("Carol", 35, "New York"), new Person("David", 28, "Boston"), new Person("Eve", 19, "Chicago") ); // 1. Sorting with Comparator lambda System.out.println("\n=== Sorting ==="); // Sort by age (ascending) people.sort((p1, p2) -> Integer.compare(p1.getAge(), p2.getAge())); System.out.println("Sorted by age:"); people.forEach(System.out::println); // Sort by name (descending) people.sort((p1, p2) -> p2.getName().compareTo(p1.getName())); System.out.println("\nSorted by name (descending):"); people.forEach(System.out::println); // Using Comparator.comparing with method reference people.sort(Comparator.comparing(Person::getCity).thenComparing(Person::getAge)); System.out.println("\nSorted by city then age:"); people.forEach(System.out::println); // 2. Filtering with Predicate System.out.println("\n=== Filtering ==="); List<Person> adults = people.stream() .filter(p -> p.getAge() >= 25) .collect(Collectors.toList()); System.out.println("Adults (25+): " + adults); List<Person> newYorkers = people.stream() .filter(p -> "New York".equals(p.getCity())) .collect(Collectors.toList()); System.out.println("New York residents: " + newYorkers); // 3. Mapping with Function System.out.println("\n=== Mapping ==="); List<String> names = people.stream() .map(Person::getName) .collect(Collectors.toList()); System.out.println("Names: " + names); List<String> nameAgeCombinations = people.stream() .map(p -> p.getName() + " (" + p.getAge() + ")") .collect(Collectors.toList()); System.out.println("Name with age: " + nameAgeCombinations); // 4. Grouping with Collectors System.out.println("\n=== Grouping ==="); Map<String, List<Person>> peopleByCity = people.stream() .collect(Collectors.groupingBy(Person::getCity)); System.out.println("People by city:"); peopleByCity.forEach((city, cityPeople) -> { System.out.println(city + ": " + cityPeople); }); Map<String, Long> countByCity = people.stream() .collect(Collectors.groupingBy(Person::getCity, Collectors.counting())); System.out.println("Count by city: " + countByCity); demonstrateMapOperations(); } public static void demonstrateMapOperations() { System.out.println("\n=== Map Operations with Lambdas ==="); Map<String, Integer> wordCounts = new HashMap<>(); wordCounts.put("apple", 3); wordCounts.put("banana", 5); wordCounts.put("cherry", 2); // forEach with BiConsumer System.out.println("Word counts:"); wordCounts.forEach((word, count) -> System.out.println(word + ": " + count)); // computeIfAbsent wordCounts.computeIfAbsent("date", k -> 1); wordCounts.computeIfAbsent("apple", k -> 10); // Won't compute, already exists System.out.println("After computeIfAbsent: " + wordCounts); // computeIfPresent wordCounts.computeIfPresent("banana", (word, count) -> count + 10); wordCounts.computeIfPresent("grape", (word, count) -> count + 1); // Won't compute, doesn't exist System.out.println("After computeIfPresent: " + wordCounts); // merge wordCounts.merge("apple", 5, (oldValue, newValue) -> oldValue + newValue); wordCounts.merge("fig", 1, (oldValue, newValue) -> oldValue + newValue); System.out.println("After merge: " + wordCounts); // replaceAll wordCounts.replaceAll((word, count) -> count * 2); System.out.println("After replaceAll (doubled): " + wordCounts); } }

5. Variable Capture in Lambdas

Effectively Final and Variable Capture

import java.util.*; import java.util.function.*; public class LambdaVariableCapture { private String instanceVariable = "Instance Variable"; private static String staticVariable = "Static Variable"; public static void main(String[] args) { System.out.println("=== Variable Capture in Lambdas ==="); LambdaVariableCapture example = new LambdaVariableCapture(); example.demonstrateLocalVariableCapture(); example.demonstrateInstanceAndStaticCapture(); example.demonstrateEffectivelyFinal(); } public void demonstrateLocalVariableCapture() { System.out.println("\n=== Local Variable Capture ==="); // Effectively final local variable final String finalLocal = "Final Local"; String effectivelyFinal = "Effectively Final"; // Lambda capturing local variables Supplier<String> localCapture = () -> { // Can read both final and effectively final variables return finalLocal + " and " + effectivelyFinal; }; System.out.println("Local capture: " + localCapture.get()); // Trying to modify captured variable (will cause compile error) // effectivelyFinal = "Modified"; // Uncommenting this will break the lambda // Array capture (array reference is effectively final, but contents can be modified) int[] counter = {0}; IntSupplier counterLambda = () -> ++counter[0]; // Modifying array content is allowed System.out.println("Counter: " + counterLambda.getAsInt()); System.out.println("Counter: " + counterLambda.getAsInt()); System.out.println("Counter: " + counterLambda.getAsInt()); } public void demonstrateInstanceAndStaticCapture() { System.out.println("\n=== Instance and Static Variable Capture ==="); // Lambda capturing instance variable Supplier<String> instanceCapture = () -> this.instanceVariable; System.out.println("Instance capture: " + instanceCapture.get()); // Lambda capturing static variable Supplier<String> staticCapture = () -> staticVariable; System.out.println("Static capture: " + staticCapture.get()); // Modifying instance variables from lambda Runnable instanceModifier = () -> { this.instanceVariable = "Modified from lambda"; staticVariable = "Static modified from lambda"; }; instanceModifier.run(); System.out.println("After modification:"); System.out.println("Instance: " + instanceCapture.get()); System.out.println("Static: " + staticCapture.get()); } public void demonstrateEffectivelyFinal() { System.out.println("\n=== Effectively Final Concept ==="); List<String> names = Arrays.asList("John", "Alice", "Bob"); // This works - list reference is effectively final names.forEach(name -> System.out.println(name)); // This would cause compile error - modifying effectively final variable // String prefix = "Mr. "; // names.forEach(name -> { // prefix = "Dr. "; // Compile error - cannot assign to effectively final variable // System.out.println(prefix + name); // }); // Workaround using array or wrapper String[] prefixArray = {"Mr. "}; names.forEach(name -> { System.out.println(prefixArray[0] + name); // Can modify array content, but not the array reference prefixArray[0] = "Dr. "; // This is allowed! }); // Using AtomicReference as wrapper java.util.concurrent.atomic.AtomicReference<String> prefixRef = new java.util.concurrent.atomic.AtomicReference<>("Hello "); names.forEach(name -> { String currentPrefix = prefixRef.get(); System.out.println(currentPrefix + name); prefixRef.set("Hi "); // This is allowed! }); } public void demonstrateThisInLambda() { System.out.println("\n=== 'this' in Lambda ==="); // In lambda, 'this' refers to the enclosing instance Runnable lambdaWithThis = () -> { System.out.println("Lambda this: " + this); System.out.println("Lambda this class: " + this.getClass().getSimpleName()); }; lambdaWithThis.run(); // Compare with anonymous class Runnable anonymousWithThis = new Runnable() { @Override public void run() { System.out.println("Anonymous this: " + this); System.out.println("Anonymous this class: " + this.getClass().getSimpleName()); } }; anonymousWithThis.run(); } }

6. Real-World Lambda Examples

Practical Lambda Usage Scenarios

import java.util.*; import java.util.concurrent.*; import java.util.function.*; import java.util.stream.*; public class RealWorldLambdaExamples { static class Product { String name; double price; String category; int stock; public Product(String name, double price, String category, int stock) { this.name = name; this.price = price; this.category = category; this.stock = stock; } public String getName() { return name; } public double getPrice() { return price; } public String getCategory() { return category; } public int getStock() { return stock; } @Override public String toString() { return String.format("Product{name='%-12s', price=$%-6.2f, category='%-10s', stock=%d}", name, price, category, stock); } } public static void main(String[] args) throws Exception { System.out.println("=== Real-World Lambda Examples ==="); List<Product> products = Arrays.asList( new Product("Laptop", 999.99, "Electronics", 10), new Product("Smartphone", 699.99, "Electronics", 25), new Product("Headphones", 149.99, "Electronics", 50), new Product("T-Shirt", 19.99, "Clothing", 100), new Product("Jeans", 49.99, "Clothing", 75), new Product("Book", 12.99, "Education", 200), new Product("Desk Lamp", 29.99, "Home", 30) ); // 1. E-commerce product filtering and transformation demonstrateECommerceOperations(products); // 2. Data processing pipeline demonstrateDataProcessing(products); // 3. Asynchronous operations with CompletableFuture demonstrateAsyncOperations(); // 4. Event handling and callbacks demonstrateEventHandling(); } public static void demonstrateECommerceOperations(List<Product> products) { System.out.println("\n=== E-Commerce Operations ==="); // Filter electronics products List<Product> electronics = products.stream() .filter(p -> "Electronics".equals(p.getCategory())) .collect(Collectors.toList()); System.out.println("Electronics products:"); electronics.forEach(System.out::println); // Apply discount to clothing products Function<Product, Product> applyClothingDiscount = p -> { if ("Clothing".equals(p.getCategory())) { return new Product(p.getName(), p.getPrice() * 0.8, p.getCategory(), p.getStock()); } return p; }; List<Product> discountedProducts = products.stream() .map(applyClothingDiscount) .collect(Collectors.toList()); System.out.println("\nProducts with clothing discount:"); discountedProducts.forEach(System.out::println); // Group products by category Map<String, List<Product>> productsByCategory = products.stream() .collect(Collectors.groupingBy(Product::getCategory)); System.out.println("\nProducts by category:"); productsByCategory.forEach((category, productList) -> { System.out.println(category + ": " + productList.size() + " products"); }); // Calculate total inventory value double totalValue = products.stream() .mapToDouble(p -> p.getPrice() * p.getStock()) .sum(); System.out.printf("\nTotal inventory value: $%.2f%n", totalValue); } public static void demonstrateDataProcessing(List<Product> products) { System.out.println("\n=== Data Processing Pipeline ==="); // Complex data processing pipeline Map<String, Double> categoryAveragePrice = products.stream() .collect(Collectors.groupingBy( Product::getCategory, Collectors.averagingDouble(Product::getPrice) )); System.out.println("Average price by category:"); categoryAveragePrice.forEach((category, avgPrice) -> System.out.printf("%-12s: $%.2f%n", category, avgPrice)); // Products that need restocking (stock < 20) Predicate<Product> needsRestocking = p -> p.getStock() < 20; List<String> productsToRestock = products.stream() .filter(needsRestocking) .map(Product::getName) .collect(Collectors.toList()); System.out.println("\nProducts needing restock: " + productsToRestock); // Price range analysis DoubleSummaryStatistics priceStats = products.stream() .mapToDouble(Product::getPrice) .summaryStatistics(); System.out.println("\nPrice statistics:"); System.out.printf("Count: %d, Min: $%.2f, Max: $%.2f, Average: $%.2f%n", priceStats.getCount(), priceStats.getMin(), priceStats.getMax(), priceStats.getAverage()); } public static void demonstrateAsyncOperations() throws Exception { System.out.println("\n=== Asynchronous Operations ==="); // Simulate async tasks with CompletableFuture CompletableFuture<String> asyncTask1 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000); return "Result from async task 1"; } catch (InterruptedException e) { throw new RuntimeException(e); } }); CompletableFuture<String> asyncTask2 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(500); return "Result from async task 2"; } catch (InterruptedException e) { throw new RuntimeException(e); } }); // Combine results when both complete CompletableFuture<String> combined = asyncTask1.thenCombine(asyncTask2, (result1, result2) -> result1 + " + " + result2); System.out.println("Combined result: " + combined.get()); // Chain async operations CompletableFuture<Integer> chainedOperation = CompletableFuture.supplyAsync(() -> 5) .thenApplyAsync(x -> x * 2) .thenApplyAsync(x -> x + 10) .thenApplyAsync(x -> x * x); System.out.println("Chained operation result: " + chainedOperation.get()); } public static void demonstrateEventHandling() { System.out.println("\n=== Event Handling ==="); // Simple event system class EventManager { private Map<String, List<Consumer<String>>> listeners = new HashMap<>(); public void addListener(String eventType, Consumer<String> listener) { listeners.computeIfAbsent(eventType, k -> new ArrayList<>()).add(listener); } public void fireEvent(String eventType, String data) { List<Consumer<String>> eventListeners = listeners.get(eventType); if (eventListeners != null) { eventListeners.forEach(listener -> listener.accept(data)); } } } EventManager eventManager = new EventManager(); // Register lambda event handlers eventManager.addListener("login", username -> System.out.println("User logged in: " + username)); eventManager.addListener("purchase", product -> System.out.println("Purchase made: " + product)); eventManager.addListener("error", errorMessage -> System.err.println("Error occurred: " + errorMessage)); // Fire events eventManager.fireEvent("login", "john_doe"); eventManager.fireEvent("purchase", "Laptop"); eventManager.fireEvent("error", "Connection timeout"); // Button click simulation (like in GUI programming) class Button { private String text; private Runnable onClick; public Button(String text) { this.text = text; } public void setOnClick(Runnable onClick) { this.onClick = onClick; } public void click() { System.out.println("Button '" + text + "' clicked"); if (onClick != null) { onClick.run(); } } } Button saveButton = new Button("Save"); saveButton.setOnClick(() -> { System.out.println("Saving data..."); System.out.println("Data saved successfully!"); }); Button cancelButton = new Button("Cancel"); cancelButton.setOnClick(() -> System.out.println("Operation cancelled")); // Simulate button clicks saveButton.click(); cancelButton.click(); } }

Summary

Key Lambda Syntax Rules:

  1. Basic Syntax: (parameters) -> expression
  2. Parameter Rules:
  • No parameters: () -> expression
  • Single parameter: param -> expression or (param) -> expression
  • Multiple parameters: (param1, param2) -> expression
  1. Body Rules:
  • Single expression: implicit return
  • Block body: { statements; return value; }

Important Concepts:

  1. Functional Interfaces: Lambdas work with interfaces having exactly one abstract method
  2. Type Inference: Compiler can often infer parameter types
  3. Variable Capture: Lambdas can capture effectively final variables
  4. Method References: Shorthand for common lambda patterns

Common Use Cases:

  1. Collection operations: filtering, mapping, sorting
  2. Event handling: GUI events, callbacks
  3. Asynchronous programming: CompletableFuture, threads
  4. Stream processing: data transformation pipelines
  5. Functional programming: higher-order functions

Best Practices:

  1. Keep lambdas short and focused
  2. Use method references when possible
  3. Avoid complex logic in lambdas
  4. Be mindful of variable capture
  5. Use meaningful parameter names

Lambda expressions make Java code more concise, readable, and functional, enabling modern programming paradigms while maintaining type safety.

Leave a Reply

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


Macro Nepal Helper