强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Java 完全指南 / 16 - Lambda:函数式接口、方法引用、Comparator

16 - Lambda:函数式接口、方法引用、Comparator

Lambda 表达式

public class LambdaDemo {
    public static void main(String[] args) {
        // 传统匿名内部类
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello");
            }
        };

        // Lambda 写法
        Runnable r2 = () -> System.out.println("Hello");

        // Lambda 多行
        Runnable r3 = () -> {
            String name = "Java";
            System.out.println("Hello, " + name);
        };

        // 带参数
        java.util.function.Consumer<String> printer = s -> System.out.println(s);
        java.util.function.Function<String, Integer> len = s -> s.length();
        java.util.function.Predicate<String> notEmpty = s -> !s.isEmpty();
        java.util.function.Supplier<List<String>> listFactory = ArrayList::new;

        // 使用
        printer.accept("Hello");
        System.out.println(len.apply("Java"));
        System.out.println(notEmpty.test(""));
    }
}

函数式接口(@FunctionalInterface)

@FunctionalInterface
interface MathOperation {
    int operate(int a, int b);

    // 可以有默认方法
    default MathOperation andThen(MathOperation after) {
        return (a, b) -> after.operate(operate(a, b), b);
    }
}

// 使用
public class FunctionalInterfaceDemo {
    public static void main(String[] args) {
        MathOperation add = Integer::sum;
        MathOperation multiply = (a, b) -> a * b;

        System.out.println(add.operate(3, 5));        // 8
        System.out.println(multiply.operate(3, 5));    // 15
    }
}

java.util.function 核心接口

接口签名示例
Function<T,R>R apply(T t)String::length
Predicate<T>boolean test(T t)s -> s.isEmpty()
Consumer<T>void accept(T t)System.out::println
Supplier<T>T get()ArrayList::new
UnaryOperator<T>T apply(T t)String::toUpperCase
BinaryOperator<T>T apply(T a, T b)Integer::sum
BiFunction<T,U,R>R apply(T t, U u)(a,b) -> a+b
BiPredicate<T,U>boolean test(T t, U u)Objects::equals
BiConsumer<T,U>void accept(T t, U u)Map::put
import java.util.function.*;

public class FunctionDemo {
    public static void main(String[] args) {
        // Function 组合
        Function<String, String> trim = String::trim;
        Function<String, String> upper = String::toUpperCase;
        Function<String, String> process = trim.andThen(upper);
        System.out.println(process.apply("  hello  "));  // HELLO

        Function<Integer, Integer> doubleIt = n -> n * 2;
        Function<Integer, Integer> addOne = n -> n + 1;
        Function<Integer, Integer> doubleThenAdd = doubleIt.andThen(addOne);
        Function<Integer, Integer> addThenDouble = doubleIt.compose(addOne);
        System.out.println(doubleThenAdd.apply(5));  // 11 (5*2+1)
        System.out.println(addThenDouble.apply(5));  // 12 ((5+1)*2)

        // Predicate 组合
        Predicate<String> isLong = s -> s.length() > 5;
        Predicate<String> startsWithH = s -> s.startsWith("H");
        Predicate<String> combined = isLong.and(startsWithH);
        Predicate<String> negated = isLong.negate();

        System.out.println(combined.test("Hello World"));  // true
        System.out.println(combined.test("Hi"));            // false

        // BiFunction
        BiFunction<String, Integer, String> repeat = (s, n) -> s.repeat(n);
        System.out.println(repeat.apply("Ha", 3));  // HaHaHa
    }
}

方法引用

public class MethodRefDemo {
    static void print(String s) { System.out.println(s); }

    public static void main(String[] args) {
        List<String> names = List.of("Charlie", "Alice", "Bob");

        // 1. 静态方法引用: ClassName::staticMethod
        names.forEach(MethodRefDemo::print);

        // 2. 实例方法引用: instance::method
        String prefix = "Hello, ";
        Function<String, String> greeter = prefix::concat;

        // 3. 任意对象方法引用: ClassName::instanceMethod
        names.stream()
            .map(String::toLowerCase)
            .forEach(System.out::println);

        // 4. 构造器引用: ClassName::new
        Function<String, StringBuilder> sbFactory = StringBuilder::new;
        Supplier<ArrayList<String>> listFactory = ArrayList::new;
        BiFunction<String, Integer, record_> recFactory = SomeRecord::new;

        // 数组构造器引用
        IntFunction<String[]> arrayFactory = String[]::new;
        String[] arr = arrayFactory.apply(5);  // new String[5]
    }

    record SomeRecord(String name, int age) {}
}

Comparator 详解

import java.util.*;

public class ComparatorDemo {
    record Student(String name, int age, double score) {}

    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(List.of(
            new Student("张三", 20, 92.5),
            new Student("李四", 22, 85.0),
            new Student("王五", 21, 92.5),
            new Student("赵六", 20, 78.0)
        ));

        // 自然排序
        List<String> names = new ArrayList<>(List.of("Charlie", "Alice", "Bob"));
        names.sort(Comparator.naturalOrder());
        names.sort(Comparator.reverseOrder());

        // Comparator.comparing
        students.sort(Comparator.comparing(Student::name));
        students.sort(Comparator.comparingDouble(Student::score).reversed());

        // 多条件排序
        students.sort(
            Comparator.comparingDouble(Student::score).reversed()  // 分数降序
                      .thenComparing(Student::name)                // 姓名升序
        );

        // nullsFirst / nullsLast
        students.sort(Comparator.comparing(Student::name, Comparator.nullsLast(String::compareTo)));

        // 自定义 Comparator
        Comparator<Student> byAge = (a, b) -> Integer.compare(a.age(), b.age());
        students.sort(byAge);

        students.forEach(s -> System.out.printf("%s: %.1f%n", s.name(), s.score()));
    }
}

实用 Lambda 模式

public class LambdaPatterns {
    // 条件过滤器构建器
    static <T> Predicate<T> not(Predicate<T> predicate) {
        return predicate.negate();
    }

    // 缓存/记忆化
    static <T, R> Function<T, R> memoize(Function<T, R> fn) {
        Map<T, R> cache = new HashMap<>();
        return t -> cache.computeIfAbsent(t, fn);
    }

    // 重试机制
    static <T> T retry(int maxAttempts, Supplier<T> action) {
        Exception lastException = null;
        for (int i = 0; i < maxAttempts; i++) {
            try {
                return action.get();
            } catch (Exception e) {
                lastException = e;
            }
        }
        throw new RuntimeException("重试" + maxAttempts + "次后失败", lastException);
    }

    public static void main(String[] args) {
        // 条件过滤
        List<String> items = List.of("A", "", "B", " ", "C");
        List<String> nonEmpty = items.stream().filter(not(String::isBlank)).toList();

        // 记忆化斐波那契
        Function<Integer, Long> fib = memoize(n -> {
            if (n <= 1) return (long) n;
            return fib.apply(n - 1) + fib.apply(n - 2);
        });
        System.out.println(fib.apply(50));  // 快速计算

        // 重试
        String result = retry(3, () -> {
            if (Math.random() < 0.7) throw new RuntimeException("失败");
            return "成功";
        });
    }
}

⚠️ 注意事项

  1. Lambda 中只能访问 effectively final 变量 — 不能修改外部局部变量。
  2. 不要过度使用 Lambda — 复杂逻辑仍应使用方法引用或普通方法。
  3. Lambda 没有 checked exception — 需要包装为 unchecked 或使用辅助方法。
  4. Lambda 序列化问题 — Lambda 不能直接序列化,需要特殊处理。

💡 技巧

  1. 处理 checked exception 的 Lambda

    @FunctionalInterface
    interface ThrowingFunction<T, R> {
        R apply(T t) throws Exception;
    }
    static <T, R> Function<T, R> unchecked(ThrowingFunction<T, R> fn) {
        return t -> { try { return fn.apply(t); } catch (Exception e) { throw new RuntimeException(e); } };
    }
    // 使用: list.stream().map(unchecked(File::getCanonicalPath))
    
  2. 链式条件构建

    Predicate<User> isVip = User::isVip;
    Predicate<User> isAdult = u -> u.getAge() >= 18;
    Predicate<User> canAccess = isVip.and(isAdult);
    

🏢 业务场景

  • 策略模式: 使用 Lambda 替代策略接口实现。
  • 事件处理: Swing/JavaFX 事件回调。
  • 数据处理: Stream + Lambda 进行集合过滤、转换。
  • 异步编程: CompletableFuture 的回调函数。

📖 扩展阅读