You need to sort users by age. Writing a separate Comparator class is verbose. Lambda expressions let you write the comparison inline: (a, b) -> a.age - b.age. Anonymous functions in one line.

Basic lambda

Replace anonymous class with lambda.

Basic.java
import java.util.*;

public class Basic {
    public static void main(String[] args) {
        System.out.println("No parameters:\n");
        
        Runnable task = () -> System.out.println("  Hello from lambda!");
        task.run();
        
        Runnable oldWay = new Runnable() {
            @Override
            public void run() {
                System.out.println("  Hello from anonymous class");
            }
        };
        oldWay.run();
        
        
        System.out.println("\nSingle parameter:");
        
        interface Printer {
            void print(String message);
        }
        
        Printer p1 = message -> System.out.println("  " + message);
        p1.print("No parentheses");
        
        Printer p2 = (message) -> System.out.println("  " + message);
        p2.print("With parentheses");
        
        System.out.println("\nMultiple parameters:");
        
        interface Calculator {
            int calculate(int a, int b);
        }
        
        Calculator add = (a, b) -> a + b;
        Calculator subtract = (a, b) -> a - b;
        Calculator multiply = (a, b) -> a * b;
        
        int calcB = ;
        System.out.println("  5 + " + calcB + " = " + add.calculate(5, calcB));
        System.out.println("  5 - " + calcB + " = " + subtract.calculate(5, calcB));
        System.out.println("  5 * " + calcB + " = " + multiply.calculate(5, calcB));
        
        System.out.println("\nBlock body:");
        
        Calculator divide = (a, b) -> {
            if (b == 0) {
                System.out.println("  Error: Division by zero");
                return 0;
            }
            return a / b;
        };
        
        System.out.println("  10 / " + calcB + " = " + divide.calculate(10, calcB));
        
        System.out.println("\nExplicit types:");
        
        Calculator power = (int base, int exp) -> {
            int result = 1;
            for (int i = 0; i < exp; i++) {
                result *= base;
            }
            return result;
        };
        
        System.out.println("  2^3 = " + power.calculate(2, 3));
        System.out.println("  5^2 = " + power.calculate(5, 2));
        
        System.out.println("\nComparator:");
        
        List<String> names = new ArrayList<>(Arrays.asList("Charlie", "Alice", "Bob"));
        System.out.println("  Before: " + names);
        
        names.sort((a, b) -> a.compareTo(b));
        System.out.println("  Sorted: " + names);
        
        names.sort((a, b) -> b.compareTo(a));
        System.out.println("  Reverse: " + names);
    }
}
import java.util.*;

public class Basic {
    public static void main(String[] args) {
        System.out.println("No parameters:\n");
        
        Runnable task = () -> System.out.println("  Hello from lambda!");
        task.run();
        
        Runnable oldWay = new Runnable() {
            @Override
            public void run() {
                System.out.println("  Hello from anonymous class");
            }
        };
        oldWay.run();
        
        
        System.out.println("\nSingle parameter:");
        
        interface Printer {
            void print(String message);
        }
        
        Printer p1 = message -> System.out.println("  " + message);
        p1.print("No parentheses");
        
        Printer p2 = (message) -> System.out.println("  " + message);
        p2.print("With parentheses");
        
        System.out.println("\nMultiple parameters:");
        
        interface Calculator {
            int calculate(int a, int b);
        }
        
        Calculator add = (a, b) -> a + b;
        Calculator subtract = (a, b) -> a - b;
        Calculator multiply = (a, b) -> a * b;
        
        int calcB = ;
        System.out.println("  5 + " + calcB + " = " + add.calculate(5, calcB));
        System.out.println("  5 - " + calcB + " = " + subtract.calculate(5, calcB));
        System.out.println("  5 * " + calcB + " = " + multiply.calculate(5, calcB));
        
        System.out.println("\nBlock body:");
        
        Calculator divide = (a, b) -> {
            if (b == 0) {
                System.out.println("  Error: Division by zero");
                return 0;
            }
            return a / b;
        };
        
        System.out.println("  10 / " + calcB + " = " + divide.calculate(10, calcB));
        
        System.out.println("\nExplicit types:");
        
        Calculator power = (int base, int exp) -> {
            int result = 1;
            for (int i = 0; i < exp; i++) {
                result *= base;
            }
            return result;
        };
        
        System.out.println("  2^3 = " + power.calculate(2, 3));
        System.out.println("  5^2 = " + power.calculate(5, 2));
        
        System.out.println("\nComparator:");
        
        List<String> names = new ArrayList<>(Arrays.asList("Charlie", "Alice", "Bob"));
        System.out.println("  Before: " + names);
        
        names.sort((a, b) -> a.compareTo(b));
        System.out.println("  Sorted: " + names);
        
        names.sort((a, b) -> b.compareTo(a));
        System.out.println("  Reverse: " + names);
    }
}
import java.util.*;

public class Basic {
    public static void main(String[] args) {
        System.out.println("No parameters:\n");
        
        Runnable task = () -> System.out.println("  Hello from lambda!");
        task.run();
        
        Runnable oldWay = new Runnable() {
            @Override
            public void run() {
                System.out.println("  Hello from anonymous class");
            }
        };
        oldWay.run();
        
        
        System.out.println("\nSingle parameter:");
        
        interface Printer {
            void print(String message);
        }
        
        Printer p1 = message -> System.out.println("  " + message);
        p1.print("No parentheses");
        
        Printer p2 = (message) -> System.out.println("  " + message);
        p2.print("With parentheses");
        
        System.out.println("\nMultiple parameters:");
        
        interface Calculator {
            int calculate(int a, int b);
        }
        
        Calculator add = (a, b) -> a + b;
        Calculator subtract = (a, b) -> a - b;
        Calculator multiply = (a, b) -> a * b;
        
        int calcB = ;
        System.out.println("  5 + " + calcB + " = " + add.calculate(5, calcB));
        System.out.println("  5 - " + calcB + " = " + subtract.calculate(5, calcB));
        System.out.println("  5 * " + calcB + " = " + multiply.calculate(5, calcB));
        
        System.out.println("\nBlock body:");
        
        Calculator divide = (a, b) -> {
            if (b == 0) {
                System.out.println("  Error: Division by zero");
                return 0;
            }
            return a / b;
        };
        
        System.out.println("  10 / " + calcB + " = " + divide.calculate(10, calcB));
        
        System.out.println("\nExplicit types:");
        
        Calculator power = (int base, int exp) -> {
            int result = 1;
            for (int i = 0; i < exp; i++) {
                result *= base;
            }
            return result;
        };
        
        System.out.println("  2^3 = " + power.calculate(2, 3));
        System.out.println("  5^2 = " + power.calculate(5, 2));
        
        System.out.println("\nComparator:");
        
        List<String> names = new ArrayList<>(Arrays.asList("Charlie", "Alice", "Bob"));
        System.out.println("  Before: " + names);
        
        names.sort((a, b) -> a.compareTo(b));
        System.out.println("  Sorted: " + names);
        
        names.sort((a, b) -> b.compareTo(a));
        System.out.println("  Reverse: " + names);
    }
}

(params) -> expression - concise syntax for single-method interfaces.

lambda Anonymous function: `(x, y) -> x + y`. Implements functional interface.

Lambda parameters

Different ways to specify parameters.

Parameters.java
import java.util.*;
import java.util.function.*;

public class Parameters {
    public static void main(String[] args) {
        System.out.println("Single parameter:\n");
        
        UnaryOperator<Integer> square = x -> x * x;
        UnaryOperator<Integer> doubler = x -> x * 2;
        UnaryOperator<String> upper = s -> s.toUpperCase();
        
        System.out.println("  square(5) = " + square.apply(5));
        System.out.println("  doubler(7) = " + doubler.apply(7));
        System.out.println("  upper('hello') = " + upper.apply("hello"));
        
        
        System.out.println("\nTwo parameters:");
        
        BinaryOperator<Integer> max = (a, b) -> a > b ? a : b;
        BinaryOperator<Integer> min = (a, b) -> a < b ? a : b;
        BinaryOperator<String> concat = (s1, s2) -> s1 + s2;
        
        System.out.println("  max(10, 20) = " + max.apply(10, 20));
        System.out.println("  min(10, 20) = " + min.apply(10, 20));
        System.out.println("  concat('Hello', ' World') = " + concat.apply("Hello", " World"));
        
        System.out.println("\nDifferent input/output types:");
        
        BiFunction<String, Integer, String> repeat = (str, n) -> {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < n; i++) {
                sb.append(str);
            }
            return sb.toString();
        };
        
        BiFunction<Integer, Integer, Double> divide = (a, b) -> (double) a / b;
        
        int repeatCount = ;
        System.out.println("  repeat('ab', " + repeatCount + ") = " +
                           repeat.apply("ab", repeatCount));
        System.out.println("  divide(10, 4) = " + divide.apply(10, 4));
        
        System.out.println("\nBlock with parameters:");
        
        BiFunction<Integer, Integer, String> compare = (a, b) -> {
            if (a > b) {
                return a + " is greater";
            } else if (a < b) {
                return b + " is greater";
            } else {
                return "Equal";
            }
        };
        
        System.out.println("  compare(10, 5): " + compare.apply(10, 5));
        System.out.println("  compare(3, 8): " + compare.apply(3, 8));
        System.out.println("  compare(7, 7): " + compare.apply(7, 7));
        
        System.out.println("\nList operations:");
        
        List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        
        System.out.print("  Numbers: ");
        numbers.forEach(n -> System.out.print(n + " "));
        System.out.println();
        
        numbers.removeIf(n -> n % 2 == 0);
        System.out.println("  After removing evens: " + numbers);
        
        System.out.println("\nCustom interface:");
        
        interface Validator {
            boolean validate(String input);
        }
        
        Validator notEmpty = s -> s != null && !s.isEmpty();
        Validator isEmail = s -> s.contains("@");
        Validator minLength = s -> s.length() >= 5;
        
        String test1 = "user@example.com";
        String test2 = "ab";
        
        System.out.println("  '" + test1 + "' not empty: " + notEmpty.validate(test1));
        System.out.println("  '" + test1 + "' is email: " + isEmail.validate(test1));
        System.out.println("  '" + test2 + "' min length: " + minLength.validate(test2));
    }
}
import java.util.*;
import java.util.function.*;

public class Parameters {
    public static void main(String[] args) {
        System.out.println("Single parameter:\n");
        
        UnaryOperator<Integer> square = x -> x * x;
        UnaryOperator<Integer> doubler = x -> x * 2;
        UnaryOperator<String> upper = s -> s.toUpperCase();
        
        System.out.println("  square(5) = " + square.apply(5));
        System.out.println("  doubler(7) = " + doubler.apply(7));
        System.out.println("  upper('hello') = " + upper.apply("hello"));
        
        
        System.out.println("\nTwo parameters:");
        
        BinaryOperator<Integer> max = (a, b) -> a > b ? a : b;
        BinaryOperator<Integer> min = (a, b) -> a < b ? a : b;
        BinaryOperator<String> concat = (s1, s2) -> s1 + s2;
        
        System.out.println("  max(10, 20) = " + max.apply(10, 20));
        System.out.println("  min(10, 20) = " + min.apply(10, 20));
        System.out.println("  concat('Hello', ' World') = " + concat.apply("Hello", " World"));
        
        System.out.println("\nDifferent input/output types:");
        
        BiFunction<String, Integer, String> repeat = (str, n) -> {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < n; i++) {
                sb.append(str);
            }
            return sb.toString();
        };
        
        BiFunction<Integer, Integer, Double> divide = (a, b) -> (double) a / b;
        
        int repeatCount = ;
        System.out.println("  repeat('ab', " + repeatCount + ") = " +
                           repeat.apply("ab", repeatCount));
        System.out.println("  divide(10, 4) = " + divide.apply(10, 4));
        
        System.out.println("\nBlock with parameters:");
        
        BiFunction<Integer, Integer, String> compare = (a, b) -> {
            if (a > b) {
                return a + " is greater";
            } else if (a < b) {
                return b + " is greater";
            } else {
                return "Equal";
            }
        };
        
        System.out.println("  compare(10, 5): " + compare.apply(10, 5));
        System.out.println("  compare(3, 8): " + compare.apply(3, 8));
        System.out.println("  compare(7, 7): " + compare.apply(7, 7));
        
        System.out.println("\nList operations:");
        
        List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        
        System.out.print("  Numbers: ");
        numbers.forEach(n -> System.out.print(n + " "));
        System.out.println();
        
        numbers.removeIf(n -> n % 2 == 0);
        System.out.println("  After removing evens: " + numbers);
        
        System.out.println("\nCustom interface:");
        
        interface Validator {
            boolean validate(String input);
        }
        
        Validator notEmpty = s -> s != null && !s.isEmpty();
        Validator isEmail = s -> s.contains("@");
        Validator minLength = s -> s.length() >= 5;
        
        String test1 = "user@example.com";
        String test2 = "ab";
        
        System.out.println("  '" + test1 + "' not empty: " + notEmpty.validate(test1));
        System.out.println("  '" + test1 + "' is email: " + isEmail.validate(test1));
        System.out.println("  '" + test2 + "' min length: " + minLength.validate(test2));
    }
}
import java.util.*;
import java.util.function.*;

public class Parameters {
    public static void main(String[] args) {
        System.out.println("Single parameter:\n");
        
        UnaryOperator<Integer> square = x -> x * x;
        UnaryOperator<Integer> doubler = x -> x * 2;
        UnaryOperator<String> upper = s -> s.toUpperCase();
        
        System.out.println("  square(5) = " + square.apply(5));
        System.out.println("  doubler(7) = " + doubler.apply(7));
        System.out.println("  upper('hello') = " + upper.apply("hello"));
        
        
        System.out.println("\nTwo parameters:");
        
        BinaryOperator<Integer> max = (a, b) -> a > b ? a : b;
        BinaryOperator<Integer> min = (a, b) -> a < b ? a : b;
        BinaryOperator<String> concat = (s1, s2) -> s1 + s2;
        
        System.out.println("  max(10, 20) = " + max.apply(10, 20));
        System.out.println("  min(10, 20) = " + min.apply(10, 20));
        System.out.println("  concat('Hello', ' World') = " + concat.apply("Hello", " World"));
        
        System.out.println("\nDifferent input/output types:");
        
        BiFunction<String, Integer, String> repeat = (str, n) -> {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < n; i++) {
                sb.append(str);
            }
            return sb.toString();
        };
        
        BiFunction<Integer, Integer, Double> divide = (a, b) -> (double) a / b;
        
        int repeatCount = ;
        System.out.println("  repeat('ab', " + repeatCount + ") = " +
                           repeat.apply("ab", repeatCount));
        System.out.println("  divide(10, 4) = " + divide.apply(10, 4));
        
        System.out.println("\nBlock with parameters:");
        
        BiFunction<Integer, Integer, String> compare = (a, b) -> {
            if (a > b) {
                return a + " is greater";
            } else if (a < b) {
                return b + " is greater";
            } else {
                return "Equal";
            }
        };
        
        System.out.println("  compare(10, 5): " + compare.apply(10, 5));
        System.out.println("  compare(3, 8): " + compare.apply(3, 8));
        System.out.println("  compare(7, 7): " + compare.apply(7, 7));
        
        System.out.println("\nList operations:");
        
        List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        
        System.out.print("  Numbers: ");
        numbers.forEach(n -> System.out.print(n + " "));
        System.out.println();
        
        numbers.removeIf(n -> n % 2 == 0);
        System.out.println("  After removing evens: " + numbers);
        
        System.out.println("\nCustom interface:");
        
        interface Validator {
            boolean validate(String input);
        }
        
        Validator notEmpty = s -> s != null && !s.isEmpty();
        Validator isEmail = s -> s.contains("@");
        Validator minLength = s -> s.length() >= 5;
        
        String test1 = "user@example.com";
        String test2 = "ab";
        
        System.out.println("  '" + test1 + "' not empty: " + notEmpty.validate(test1));
        System.out.println("  '" + test1 + "' is email: " + isEmail.validate(test1));
        System.out.println("  '" + test2 + "' min length: " + minLength.validate(test2));
    }
}

x -> x*2 (one param, no parens), (x, y) -> x+y (multiple), (int x) -> x*2 (typed).

Block lambda

Multiple statements in lambda body.

Block.java
import java.util.*;
import java.util.function.*;

public class Block {
    public static void main(String[] args) {
        System.out.println("Single vs block:\n");
        
        Function<Integer, Integer> single = x -> x * 2;
        
        Function<Integer, Integer> block = x -> {
            int result = x * 2;
            return result;
        };
        
        System.out.println("  Single: " + single.apply(5));
        System.out.println("  Block: " + block.apply(5));
        
        
        System.out.println("\nComplex logic:");
        
        Function<Integer, String> classify = n -> {
            if (n < 0) {
                return "negative";
            } else if (n == 0) {
                return "zero";
            } else if (n % 2 == 0) {
                return "positive even";
            } else {
                return "positive odd";
            }
        };
        
        System.out.println("  classify(-5): " + classify.apply(-5));
        System.out.println("  classify(0): " + classify.apply(0));
        System.out.println("  classify(4): " + classify.apply(4));
        System.out.println("  classify(7): " + classify.apply(7));
        
        System.out.println("\nLocal variables:");
        
        BiFunction<Integer, Integer, Integer> gcd = (a, b) -> {
            int temp;
            while (b != 0) {
                temp = b;
                b = a % b;
                a = temp;
            }
            return a;
        };
        
        System.out.println("  gcd(48, 18) = " + gcd.apply(48, 18));
        System.out.println("  gcd(100, 35) = " + gcd.apply(100, 35));
        
        System.out.println("\nValidation:");
        
        Function<String, Boolean> isValidPassword = password -> {
            if (password == null || password.length() < 8) {
                return false;
            }
            
            boolean hasDigit = false;
            boolean hasLetter = false;
            
            for (char c : password.toCharArray()) {
                if (Character.isDigit(c)) hasDigit = true;
                if (Character.isLetter(c)) hasLetter = true;
            }
            
            return hasDigit && hasLetter;
        };
        
        String passwordToCheck = ;
        System.out.println("  '" + passwordToCheck + "' valid: " +
                           isValidPassword.apply(passwordToCheck));
        System.out.println("  'short' valid: " + isValidPassword.apply("short"));
        System.out.println("  'onlyletters' valid: " + isValidPassword.apply("onlyletters"));
        
        System.out.println("\nMulti-step processing:");
        
        Function<List<Integer>, Double> average = list -> {
            if (list.isEmpty()) {
                return 0.0;
            }
            
            int sum = 0;
            for (int n : list) {
                sum += n;
            }
            
            return (double) sum / list.size();
        };
        
        List<Integer> scores = Arrays.asList(85, 90, 78, 92, 88);
        System.out.println("  Average score: " + average.apply(scores));
        
        System.out.println("\nException handling:");
        
        BiFunction<Integer, Integer, Integer> safeDivide = (a, b) -> {
            try {
                return a / b;
            } catch (ArithmeticException e) {
                System.out.println("  Error: " + e.getMessage());
                return 0;
            }
        };
        
        System.out.println("  10 / 2 = " + safeDivide.apply(10, 2));
        System.out.println("  10 / 0 = " + safeDivide.apply(10, 0));
    }
}
import java.util.*;
import java.util.function.*;

public class Block {
    public static void main(String[] args) {
        System.out.println("Single vs block:\n");
        
        Function<Integer, Integer> single = x -> x * 2;
        
        Function<Integer, Integer> block = x -> {
            int result = x * 2;
            return result;
        };
        
        System.out.println("  Single: " + single.apply(5));
        System.out.println("  Block: " + block.apply(5));
        
        
        System.out.println("\nComplex logic:");
        
        Function<Integer, String> classify = n -> {
            if (n < 0) {
                return "negative";
            } else if (n == 0) {
                return "zero";
            } else if (n % 2 == 0) {
                return "positive even";
            } else {
                return "positive odd";
            }
        };
        
        System.out.println("  classify(-5): " + classify.apply(-5));
        System.out.println("  classify(0): " + classify.apply(0));
        System.out.println("  classify(4): " + classify.apply(4));
        System.out.println("  classify(7): " + classify.apply(7));
        
        System.out.println("\nLocal variables:");
        
        BiFunction<Integer, Integer, Integer> gcd = (a, b) -> {
            int temp;
            while (b != 0) {
                temp = b;
                b = a % b;
                a = temp;
            }
            return a;
        };
        
        System.out.println("  gcd(48, 18) = " + gcd.apply(48, 18));
        System.out.println("  gcd(100, 35) = " + gcd.apply(100, 35));
        
        System.out.println("\nValidation:");
        
        Function<String, Boolean> isValidPassword = password -> {
            if (password == null || password.length() < 8) {
                return false;
            }
            
            boolean hasDigit = false;
            boolean hasLetter = false;
            
            for (char c : password.toCharArray()) {
                if (Character.isDigit(c)) hasDigit = true;
                if (Character.isLetter(c)) hasLetter = true;
            }
            
            return hasDigit && hasLetter;
        };
        
        String passwordToCheck = ;
        System.out.println("  '" + passwordToCheck + "' valid: " +
                           isValidPassword.apply(passwordToCheck));
        System.out.println("  'short' valid: " + isValidPassword.apply("short"));
        System.out.println("  'onlyletters' valid: " + isValidPassword.apply("onlyletters"));
        
        System.out.println("\nMulti-step processing:");
        
        Function<List<Integer>, Double> average = list -> {
            if (list.isEmpty()) {
                return 0.0;
            }
            
            int sum = 0;
            for (int n : list) {
                sum += n;
            }
            
            return (double) sum / list.size();
        };
        
        List<Integer> scores = Arrays.asList(85, 90, 78, 92, 88);
        System.out.println("  Average score: " + average.apply(scores));
        
        System.out.println("\nException handling:");
        
        BiFunction<Integer, Integer, Integer> safeDivide = (a, b) -> {
            try {
                return a / b;
            } catch (ArithmeticException e) {
                System.out.println("  Error: " + e.getMessage());
                return 0;
            }
        };
        
        System.out.println("  10 / 2 = " + safeDivide.apply(10, 2));
        System.out.println("  10 / 0 = " + safeDivide.apply(10, 0));
    }
}
import java.util.*;
import java.util.function.*;

public class Block {
    public static void main(String[] args) {
        System.out.println("Single vs block:\n");
        
        Function<Integer, Integer> single = x -> x * 2;
        
        Function<Integer, Integer> block = x -> {
            int result = x * 2;
            return result;
        };
        
        System.out.println("  Single: " + single.apply(5));
        System.out.println("  Block: " + block.apply(5));
        
        
        System.out.println("\nComplex logic:");
        
        Function<Integer, String> classify = n -> {
            if (n < 0) {
                return "negative";
            } else if (n == 0) {
                return "zero";
            } else if (n % 2 == 0) {
                return "positive even";
            } else {
                return "positive odd";
            }
        };
        
        System.out.println("  classify(-5): " + classify.apply(-5));
        System.out.println("  classify(0): " + classify.apply(0));
        System.out.println("  classify(4): " + classify.apply(4));
        System.out.println("  classify(7): " + classify.apply(7));
        
        System.out.println("\nLocal variables:");
        
        BiFunction<Integer, Integer, Integer> gcd = (a, b) -> {
            int temp;
            while (b != 0) {
                temp = b;
                b = a % b;
                a = temp;
            }
            return a;
        };
        
        System.out.println("  gcd(48, 18) = " + gcd.apply(48, 18));
        System.out.println("  gcd(100, 35) = " + gcd.apply(100, 35));
        
        System.out.println("\nValidation:");
        
        Function<String, Boolean> isValidPassword = password -> {
            if (password == null || password.length() < 8) {
                return false;
            }
            
            boolean hasDigit = false;
            boolean hasLetter = false;
            
            for (char c : password.toCharArray()) {
                if (Character.isDigit(c)) hasDigit = true;
                if (Character.isLetter(c)) hasLetter = true;
            }
            
            return hasDigit && hasLetter;
        };
        
        String passwordToCheck = ;
        System.out.println("  '" + passwordToCheck + "' valid: " +
                           isValidPassword.apply(passwordToCheck));
        System.out.println("  'short' valid: " + isValidPassword.apply("short"));
        System.out.println("  'onlyletters' valid: " + isValidPassword.apply("onlyletters"));
        
        System.out.println("\nMulti-step processing:");
        
        Function<List<Integer>, Double> average = list -> {
            if (list.isEmpty()) {
                return 0.0;
            }
            
            int sum = 0;
            for (int n : list) {
                sum += n;
            }
            
            return (double) sum / list.size();
        };
        
        List<Integer> scores = Arrays.asList(85, 90, 78, 92, 88);
        System.out.println("  Average score: " + average.apply(scores));
        
        System.out.println("\nException handling:");
        
        BiFunction<Integer, Integer, Integer> safeDivide = (a, b) -> {
            try {
                return a / b;
            } catch (ArithmeticException e) {
                System.out.println("  Error: " + e.getMessage());
                return 0;
            }
        };
        
        System.out.println("  10 / 2 = " + safeDivide.apply(10, 2));
        System.out.println("  10 / 0 = " + safeDivide.apply(10, 0));
    }
}

(x) -> { statements; return value; } - braces and return for complex logic.

Effectively final

Lambda can access local variables if effectively final.

EffectivelyFinal.java
import java.util.*;
import java.util.function.*;

public class EffectivelyFinal {
    public static void main(String[] args) {
        System.out.println("Effectively final:\n");
        
        int multiplier = ;
        
        Function<Integer, Integer> multiply = x -> x * multiplier;
        
        System.out.println("  5 * 10 = " + multiply.apply(5));
        System.out.println("  7 * 10 = " + multiply.apply(7));
        
        
        
        System.out.println("\nMultiple captures:");
        
        String prefix = "Value: ";
        String suffix = "!";
        
        Function<Integer, String> format = n -> prefix + n + suffix;
        
        System.out.println("  " + format.apply(42));
        System.out.println("  " + format.apply(99));
        
        System.out.println("\nMethod parameters:");
        
        processList(Arrays.asList(1, 2, 3, 4, 5), 3);
        
        System.out.println("\nInstance variables:");
        
        Counter counter = new Counter();
        counter.demonstrate();
        
        System.out.println("\nExplicit final:");
        
        final int factor = 5;
        
        BinaryOperator<Integer> scale = (a, b) -> (a + b) * factor;
        
        System.out.println("  (2 + 3) * 5 = " + scale.apply(2, 3));
        
        System.out.println("\nArray capture:");
        
        int[] counters = {0};  // Effectively final reference, mutable content
        
        Runnable increment = () -> counters[0]++;
        
        increment.run();
        increment.run();
        increment.run();
        
        System.out.println("  Counter: " + counters[0]);
    }
    
    static void processList(List<Integer> numbers, int threshold) {
        numbers.forEach(n -> {
            if (n > threshold) {
                System.out.println("  " + n + " exceeds " + threshold);
            }
        });
    }
}

class Counter {
    private int count = 0;
    
    void demonstrate() {
        Runnable inc = () -> count++;
        
        inc.run();
        inc.run();
        inc.run();
        
        System.out.println("  Count: " + count);
        
        Supplier<Integer> getCount = () -> this.count;
        System.out.println("  Get count: " + getCount.get());
    }
}
import java.util.*;
import java.util.function.*;

public class EffectivelyFinal {
    public static void main(String[] args) {
        System.out.println("Effectively final:\n");
        
        int multiplier = ;
        
        Function<Integer, Integer> multiply = x -> x * multiplier;
        
        System.out.println("  5 * 10 = " + multiply.apply(5));
        System.out.println("  7 * 10 = " + multiply.apply(7));
        
        
        
        System.out.println("\nMultiple captures:");
        
        String prefix = "Value: ";
        String suffix = "!";
        
        Function<Integer, String> format = n -> prefix + n + suffix;
        
        System.out.println("  " + format.apply(42));
        System.out.println("  " + format.apply(99));
        
        System.out.println("\nMethod parameters:");
        
        processList(Arrays.asList(1, 2, 3, 4, 5), 3);
        
        System.out.println("\nInstance variables:");
        
        Counter counter = new Counter();
        counter.demonstrate();
        
        System.out.println("\nExplicit final:");
        
        final int factor = 5;
        
        BinaryOperator<Integer> scale = (a, b) -> (a + b) * factor;
        
        System.out.println("  (2 + 3) * 5 = " + scale.apply(2, 3));
        
        System.out.println("\nArray capture:");
        
        int[] counters = {0};  // Effectively final reference, mutable content
        
        Runnable increment = () -> counters[0]++;
        
        increment.run();
        increment.run();
        increment.run();
        
        System.out.println("  Counter: " + counters[0]);
    }
    
    static void processList(List<Integer> numbers, int threshold) {
        numbers.forEach(n -> {
            if (n > threshold) {
                System.out.println("  " + n + " exceeds " + threshold);
            }
        });
    }
}

class Counter {
    private int count = 0;
    
    void demonstrate() {
        Runnable inc = () -> count++;
        
        inc.run();
        inc.run();
        inc.run();
        
        System.out.println("  Count: " + count);
        
        Supplier<Integer> getCount = () -> this.count;
        System.out.println("  Get count: " + getCount.get());
    }
}
import java.util.*;
import java.util.function.*;

public class EffectivelyFinal {
    public static void main(String[] args) {
        System.out.println("Effectively final:\n");
        
        int multiplier = ;
        
        Function<Integer, Integer> multiply = x -> x * multiplier;
        
        System.out.println("  5 * 10 = " + multiply.apply(5));
        System.out.println("  7 * 10 = " + multiply.apply(7));
        
        
        
        System.out.println("\nMultiple captures:");
        
        String prefix = "Value: ";
        String suffix = "!";
        
        Function<Integer, String> format = n -> prefix + n + suffix;
        
        System.out.println("  " + format.apply(42));
        System.out.println("  " + format.apply(99));
        
        System.out.println("\nMethod parameters:");
        
        processList(Arrays.asList(1, 2, 3, 4, 5), 3);
        
        System.out.println("\nInstance variables:");
        
        Counter counter = new Counter();
        counter.demonstrate();
        
        System.out.println("\nExplicit final:");
        
        final int factor = 5;
        
        BinaryOperator<Integer> scale = (a, b) -> (a + b) * factor;
        
        System.out.println("  (2 + 3) * 5 = " + scale.apply(2, 3));
        
        System.out.println("\nArray capture:");
        
        int[] counters = {0};  // Effectively final reference, mutable content
        
        Runnable increment = () -> counters[0]++;
        
        increment.run();
        increment.run();
        increment.run();
        
        System.out.println("  Counter: " + counters[0]);
    }
    
    static void processList(List<Integer> numbers, int threshold) {
        numbers.forEach(n -> {
            if (n > threshold) {
                System.out.println("  " + n + " exceeds " + threshold);
            }
        });
    }
}

class Counter {
    private int count = 0;
    
    void demonstrate() {
        Runnable inc = () -> count++;
        
        inc.run();
        inc.run();
        inc.run();
        
        System.out.println("  Count: " + count);
        
        Supplier<Integer> getCount = () -> this.count;
        System.out.println("  Get count: " + getCount.get());
    }
}

Variables accessed in lambda can't be modified. Effectively final = never reassigned.

effectively final Variable never reassigned after initialization. Required for lambda capture.

Common use cases

Where lambdas shine.

UseCases.java
import java.util.*;
import java.util.function.*;

public class UseCases {
    public static void main(String[] args) {
        System.out.println("Thread creation:\n");
        
        Thread oldThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("  Old way thread");
            }
        });
        
        Thread newThread = new Thread(() -> {
            System.out.println("  Lambda thread");
        });
        
        try {
            oldThread.start();
            oldThread.join();
            newThread.start();
            newThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        
        System.out.println("\nSorting:");
        
        List<String> names = new ArrayList<>(
            Arrays.asList("Charlie", "Alice", "Bob", "David"));
        
        names.sort((a, b) -> a.compareTo(b));
        System.out.println("  By name: " + names);
        
        names.sort((a, b) -> Integer.compare(a.length(), b.length()));
        System.out.println("  By length: " + names);
        
        names.sort((a, b) -> {
            char lastA = a.charAt(a.length() - 1);
            char lastB = b.charAt(b.length() - 1);
            return Character.compare(lastA, lastB);
        });
        System.out.println("  By last char: " + names);
        
        System.out.println("\nList processing:");
        
        List<Integer> numbers = new ArrayList<>(
            Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
        
        System.out.print("  All: ");
        numbers.forEach(n -> System.out.print(n + " "));
        System.out.println();
        
        numbers.removeIf(n -> n % 2 == 0);
        System.out.println("  After removing evens: " + numbers);
        
        numbers.replaceAll(n -> n * 10);
        System.out.println("  After * 10: " + numbers);
        
        System.out.println("\nMap operations:");
        
        Map<String, Integer> scores = new LinkedHashMap<>();
        scores.put("Alice", 85);
        scores.put("Bob", 92);
        scores.put("Charlie", 78);
        
        scores.forEach((name, score) -> 
            System.out.println("  " + name + ": " + score));
        
        scores.replaceAll((name, score) -> score + 5);  // Curve grades
        System.out.println("  After curve: " + scores);
        
        scores.computeIfAbsent("David", k -> 80);
        System.out.println("  After adding David: " + scores);
        
        System.out.println("\nCustom callbacks:");
        
        processData(Arrays.asList(1, 2, 3, 4, 5),
            n -> n * 2,
            n -> System.out.println("  Processed: " + n)
        );
        
        System.out.println("\nEvent handlers:");
        
        Button button = new Button("Click me");
        
        button.setOnClick(() -> System.out.println("  Button clicked!"));
        button.setOnClick(() -> System.out.println("  Action performed"));
        
        button.click();
        
        System.out.println("\nConditional logic:");
        
        List<Integer> values = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        
        int cutoff = ;
        filterAndPrint(values, n -> n > cutoff, "Greater than " + cutoff);
        filterAndPrint(values, n -> n % 2 == 0, "Even numbers");
        filterAndPrint(values, n -> n % 3 == 0, "Divisible by 3");
    }
    
    static void processData(List<Integer> data,
                           Function<Integer, Integer> processor,
                           Consumer<Integer> outputter) {
        for (Integer item : data) {
            Integer processed = processor.apply(item);
            outputter.accept(processed);
        }
    }
    
    static void filterAndPrint(List<Integer> list, 
                               Predicate<Integer> filter,
                               String label) {
        System.out.print("  " + label + ": ");
        list.stream()
            .filter(filter)
            .forEach(n -> System.out.print(n + " "));
        System.out.println();
    }
}

class Button {
    private String text;
    private Runnable onClick;
    
    Button(String text) {
        this.text = text;
    }
    
    void setOnClick(Runnable action) {
        this.onClick = action;
    }
    
    void click() {
        if (onClick != null) {
            onClick.run();
        }
    }
}
import java.util.*;
import java.util.function.*;

public class UseCases {
    public static void main(String[] args) {
        System.out.println("Thread creation:\n");
        
        Thread oldThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("  Old way thread");
            }
        });
        
        Thread newThread = new Thread(() -> {
            System.out.println("  Lambda thread");
        });
        
        try {
            oldThread.start();
            oldThread.join();
            newThread.start();
            newThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        
        System.out.println("\nSorting:");
        
        List<String> names = new ArrayList<>(
            Arrays.asList("Charlie", "Alice", "Bob", "David"));
        
        names.sort((a, b) -> a.compareTo(b));
        System.out.println("  By name: " + names);
        
        names.sort((a, b) -> Integer.compare(a.length(), b.length()));
        System.out.println("  By length: " + names);
        
        names.sort((a, b) -> {
            char lastA = a.charAt(a.length() - 1);
            char lastB = b.charAt(b.length() - 1);
            return Character.compare(lastA, lastB);
        });
        System.out.println("  By last char: " + names);
        
        System.out.println("\nList processing:");
        
        List<Integer> numbers = new ArrayList<>(
            Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
        
        System.out.print("  All: ");
        numbers.forEach(n -> System.out.print(n + " "));
        System.out.println();
        
        numbers.removeIf(n -> n % 2 == 0);
        System.out.println("  After removing evens: " + numbers);
        
        numbers.replaceAll(n -> n * 10);
        System.out.println("  After * 10: " + numbers);
        
        System.out.println("\nMap operations:");
        
        Map<String, Integer> scores = new LinkedHashMap<>();
        scores.put("Alice", 85);
        scores.put("Bob", 92);
        scores.put("Charlie", 78);
        
        scores.forEach((name, score) -> 
            System.out.println("  " + name + ": " + score));
        
        scores.replaceAll((name, score) -> score + 5);  // Curve grades
        System.out.println("  After curve: " + scores);
        
        scores.computeIfAbsent("David", k -> 80);
        System.out.println("  After adding David: " + scores);
        
        System.out.println("\nCustom callbacks:");
        
        processData(Arrays.asList(1, 2, 3, 4, 5),
            n -> n * 2,
            n -> System.out.println("  Processed: " + n)
        );
        
        System.out.println("\nEvent handlers:");
        
        Button button = new Button("Click me");
        
        button.setOnClick(() -> System.out.println("  Button clicked!"));
        button.setOnClick(() -> System.out.println("  Action performed"));
        
        button.click();
        
        System.out.println("\nConditional logic:");
        
        List<Integer> values = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        
        int cutoff = ;
        filterAndPrint(values, n -> n > cutoff, "Greater than " + cutoff);
        filterAndPrint(values, n -> n % 2 == 0, "Even numbers");
        filterAndPrint(values, n -> n % 3 == 0, "Divisible by 3");
    }
    
    static void processData(List<Integer> data,
                           Function<Integer, Integer> processor,
                           Consumer<Integer> outputter) {
        for (Integer item : data) {
            Integer processed = processor.apply(item);
            outputter.accept(processed);
        }
    }
    
    static void filterAndPrint(List<Integer> list, 
                               Predicate<Integer> filter,
                               String label) {
        System.out.print("  " + label + ": ");
        list.stream()
            .filter(filter)
            .forEach(n -> System.out.print(n + " "));
        System.out.println();
    }
}

class Button {
    private String text;
    private Runnable onClick;
    
    Button(String text) {
        this.text = text;
    }
    
    void setOnClick(Runnable action) {
        this.onClick = action;
    }
    
    void click() {
        if (onClick != null) {
            onClick.run();
        }
    }
}
import java.util.*;
import java.util.function.*;

public class UseCases {
    public static void main(String[] args) {
        System.out.println("Thread creation:\n");
        
        Thread oldThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("  Old way thread");
            }
        });
        
        Thread newThread = new Thread(() -> {
            System.out.println("  Lambda thread");
        });
        
        try {
            oldThread.start();
            oldThread.join();
            newThread.start();
            newThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        
        System.out.println("\nSorting:");
        
        List<String> names = new ArrayList<>(
            Arrays.asList("Charlie", "Alice", "Bob", "David"));
        
        names.sort((a, b) -> a.compareTo(b));
        System.out.println("  By name: " + names);
        
        names.sort((a, b) -> Integer.compare(a.length(), b.length()));
        System.out.println("  By length: " + names);
        
        names.sort((a, b) -> {
            char lastA = a.charAt(a.length() - 1);
            char lastB = b.charAt(b.length() - 1);
            return Character.compare(lastA, lastB);
        });
        System.out.println("  By last char: " + names);
        
        System.out.println("\nList processing:");
        
        List<Integer> numbers = new ArrayList<>(
            Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
        
        System.out.print("  All: ");
        numbers.forEach(n -> System.out.print(n + " "));
        System.out.println();
        
        numbers.removeIf(n -> n % 2 == 0);
        System.out.println("  After removing evens: " + numbers);
        
        numbers.replaceAll(n -> n * 10);
        System.out.println("  After * 10: " + numbers);
        
        System.out.println("\nMap operations:");
        
        Map<String, Integer> scores = new LinkedHashMap<>();
        scores.put("Alice", 85);
        scores.put("Bob", 92);
        scores.put("Charlie", 78);
        
        scores.forEach((name, score) -> 
            System.out.println("  " + name + ": " + score));
        
        scores.replaceAll((name, score) -> score + 5);  // Curve grades
        System.out.println("  After curve: " + scores);
        
        scores.computeIfAbsent("David", k -> 80);
        System.out.println("  After adding David: " + scores);
        
        System.out.println("\nCustom callbacks:");
        
        processData(Arrays.asList(1, 2, 3, 4, 5),
            n -> n * 2,
            n -> System.out.println("  Processed: " + n)
        );
        
        System.out.println("\nEvent handlers:");
        
        Button button = new Button("Click me");
        
        button.setOnClick(() -> System.out.println("  Button clicked!"));
        button.setOnClick(() -> System.out.println("  Action performed"));
        
        button.click();
        
        System.out.println("\nConditional logic:");
        
        List<Integer> values = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        
        int cutoff = ;
        filterAndPrint(values, n -> n > cutoff, "Greater than " + cutoff);
        filterAndPrint(values, n -> n % 2 == 0, "Even numbers");
        filterAndPrint(values, n -> n % 3 == 0, "Divisible by 3");
    }
    
    static void processData(List<Integer> data,
                           Function<Integer, Integer> processor,
                           Consumer<Integer> outputter) {
        for (Integer item : data) {
            Integer processed = processor.apply(item);
            outputter.accept(processed);
        }
    }
    
    static void filterAndPrint(List<Integer> list, 
                               Predicate<Integer> filter,
                               String label) {
        System.out.print("  " + label + ": ");
        list.stream()
            .filter(filter)
            .forEach(n -> System.out.print(n + " "));
        System.out.println();
    }
}

class Button {
    private String text;
    private Runnable onClick;
    
    Button(String text) {
        this.text = text;
    }
    
    void setOnClick(Runnable action) {
        this.onClick = action;
    }
    
    void click() {
        if (onClick != null) {
            onClick.run();
        }
    }
}

Collections, streams, event handlers, callbacks - anywhere functional interfaces are used.

Exercise: Practical.java

Refactor anonymous classes to lambdas