Java Lambda表达式指南

一、Lambda表达式基础

1. 什么是Lambda表达式?

  • 匿名函数:没有名称的函数
  • 函数式编程:可作为参数传递的代码块
  • 简洁语法:替代匿名内部类的更紧凑写法

2. 基本语法

(parameters) -> expression
或
(parameters) -> { statements; }

3. 与传统匿名类的对比

// 传统方式
Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello World");
    }
};

// Lambda方式
Runnable r2 = () -> System.out.println("Hello World");

二、函数式接口

1. 什么是函数式接口?

  • 单抽象方法接口:只有一个抽象方法的接口
  • 可用@FunctionalInterface注解标记

2. Java内置核心函数式接口

接口方法用途
Supplier<T>T get()无参返回结果
Consumer<T>void accept(T t)接收单个参数无返回
Function<T,R>R apply(T t)接收T类型返回R类型
Predicate<T>boolean test(T t)接收T返回布尔值
UnaryOperator<T>T apply(T t)一元操作(同类型转换)
BiFunction<T,U,R>R apply(T t, U u)接收T,U返回R

3. 自定义函数式接口

@FunctionalInterface
interface StringProcessor {
    String process(String input);
    
    // 可以有默认方法
    default void info() {
        System.out.println("String processing interface");
    }
}

StringProcessor toUpper = s -> s.toUpperCase();
System.out.println(toUpper.process("hello")); // 输出: HELLO

三、Lambda使用场景

1. 集合遍历

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 传统方式
for (String name : names) {
    System.out.println(name);
}

// Lambda方式
names.forEach(name -> System.out.println(name));

// 方法引用方式
names.forEach(System.out::println);

2. 线程创建

// 传统方式
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Running in thread");
    }
}).start();

// Lambda方式
new Thread(() -> System.out.println("Running in thread")).start();

3. 条件过滤

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

// 过滤偶数
List<Integer> evens = numbers.stream()
                            .filter(n -> n % 2 == 0)
                            .collect(Collectors.toList());

4. 排序

List<String> words = Arrays.asList("banana", "apple", "pear");

// 传统方式
Collections.sort(words, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return a.compareTo(b);
    }
});

// Lambda方式
Collections.sort(words, (a, b) -> a.compareTo(b));

// 更简洁的方式
words.sort(Comparator.naturalOrder());

四、方法引用

1. 四种方法引用类型

类型语法对应的Lambda
静态方法ClassName::staticMethod(args) -> ClassName.staticMethod(args)
实例方法instance::method(args) -> instance.method(args)
任意对象的实例方法ClassName::method(obj, args) -> obj.method(args)
构造方法ClassName::new(args) -> new ClassName(args)

2. 使用示例

// 静态方法引用
Function<String, Integer> parser = Integer::parseInt;

// 实例方法引用
String str = "Hello";
Supplier<Integer> lengthSupplier = str::length;

// 任意对象方法引用
Function<String, String> upperCase = String::toUpperCase;

// 构造方法引用
Supplier<List<String>> listSupplier = ArrayList::new;

五、Stream API与Lambda

1. 流操作三阶段

  1. 创建流:集合、数组等数据源
  2. 中间操作:过滤、映射等处理
  3. 终止操作:收集、遍历等结果处理

2. 常用流操作

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

// 过滤并收集
List<String> longNames = names.stream()
                            .filter(name -> name.length() > 4)
                            .collect(Collectors.toList());

// 映射转换
List<Integer> nameLengths = names.stream()
                               .map(String::length)
                               .collect(Collectors.toList());

// 排序
List<String> sorted = names.stream()
                         .sorted((a, b) -> b.compareTo(a))
                         .collect(Collectors.toList());

// 聚合操作
Optional<String> longest = names.stream()
                              .max(Comparator.comparingInt(String::length));

3. 并行流

long count = names.parallelStream()
                .filter(name -> name.length() > 4)
                .count();

六、Lambda高级特性

1. 变量捕获

int threshold = 5; // 必须是final或事实上final
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);

List<Integer> aboveThreshold = numbers.stream()
                                    .filter(n -> n > threshold)
                                    .collect(Collectors.toList());

2. 组合函数

Function<String, Integer> strToInt = Integer::parseInt;
Function<Integer, Integer> square = n -> n * n;

Function<String, Integer> squareOfNumber = strToInt.andThen(square);
System.out.println(squareOfNumber.apply("5")); // 输出: 25

Predicate<String> isLong = s -> s.length() > 10;
Predicate<String> containsA = s -> s.contains("a");
Predicate<String> longAndContainsA = isLong.and(containsA);

3. 闭包示例

Function<Integer, Function<Integer, Integer>> adder = x -> y -> x + y;
Function<Integer, Integer> add5 = adder.apply(5);
System.out.println(add5.apply(3)); // 输出: 8

七、异常处理

1. Lambda中的异常处理

List<String> numbers = Arrays.asList("1", "2", "three", "4");

numbers.forEach(s -> {
    try {
        System.out.println(Integer.parseInt(s));
    } catch (NumberFormatException e) {
        System.out.println("Invalid number: " + s);
    }
});

2. 编写可抛出异常的Lambda

@FunctionalInterface
interface ThrowingConsumer<T, E extends Exception> {
    void accept(T t) throws E;
}

static <T> Consumer<T> wrap(ThrowingConsumer<T, Exception> consumer) {
    return t -> {
        try {
            consumer.accept(t);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
}

// 使用
List<String> files = Arrays.asList("file1.txt", "file2.txt");
files.forEach(wrap(file -> {
    // 可能抛出IOException的代码
    Files.readAllLines(Paths.get(file)).forEach(System.out::println);
}));

八、实际应用案例

1. 事件处理

// Swing按钮点击事件
JButton button = new JButton("Click");
button.addActionListener(e -> System.out.println("Button clicked"));

// JavaFX事件处理
Button fxButton = new Button("Click");
fxButton.setOnAction(event -> System.out.println("FX Button clicked"));

2. 缓存模式

public class Cache<K, V> {
    private final Map<K, V> map = new HashMap<>();
    private final Function<K, V> loader;
    
    public Cache(Function<K, V> loader) {
        this.loader = loader;
    }
    
    public V get(K key) {
        return map.computeIfAbsent(key, loader);
    }
}

// 使用
Cache<String, BigDecimal> priceCache = new Cache<>(productId -> 
    fetchPriceFromDatabase(productId));
BigDecimal price = priceCache.get("P1001");

3. 策略模式

interface PaymentStrategy {
    void pay(BigDecimal amount);
}

class PaymentProcessor {
    private PaymentStrategy strategy;
    
    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void processPayment(BigDecimal amount) {
        strategy.pay(amount);
    }
}

// 使用
PaymentProcessor processor = new PaymentProcessor();

// 信用卡支付
processor.setStrategy(amount -> 
    System.out.println("Paying " + amount + " via Credit Card"));
processor.processPayment(new BigDecimal("100.00"));

// 支付宝支付
processor.setStrategy(amount -> 
    System.out.println("Paying " + amount + " via Alipay"));
processor.processPayment(new BigDecimal("200.00"));

九、性能考虑

1. Lambda vs 匿名类

  • 初始化性能:Lambda首次调用稍慢,后续调用更快
  • 内存占用:Lambda通常占用更少内存
  • 最佳实践:在热点代码中避免频繁创建Lambda

2. 方法引用优化

// 较慢 - 每次创建新Lambda
list.stream().map(x -> x.toString()).collect(Collectors.toList());

// 更快 - 使用方法引用
list.stream().map(Object::toString).collect(Collectors.toList());

3. 并行流注意事项

  • 数据量小(<1000元素)时顺序流更快
  • 确保操作是无状态的
  • 避免共享可变状态

十、常见问题与陷阱

1. 变量修改

int sum = 0;
numbers.forEach(n -> {
    sum += n; // 编译错误 - 不能修改捕获的变量
});

// 正确方式
int[] sumHolder = {0};
numbers.forEach(n -> sumHolder[0] += n);

2. this关键字

public class LambdaThis {
    private String value = "Enclosing";
    
    public void doWork() {
        Runnable r = () -> {
            System.out.println(this.value); // 输出"Enclosing"
        };
        r.run();
    }
}

3. 重载问题

interface Adder {
    int add(int a, int b);
}

interface SmartAdder {
    int add(double a, double b);
}

class Calculator {
    void calculate(Adder adder) { /* ... */ }
    void calculate(SmartAdder adder) { /* ... */ }
}

// 调用时会产生歧义
// calculator.calculate((x, y) -> x + y); // 编译错误

十一、Java 8+ Lambda增强

1. Java 8 - 基本Lambda支持

  • 引入函数式接口
  • 方法引用
  • Stream API

2. Java 11 - 局部变量语法

var list = List.of("a", "b", "c");
list.forEach((var s) -> System.out.println(s));

3. Java 17 - 密封接口

sealed interface MathOperation permits Add, Subtract {
    int operate(int a, int b);
}

final class Add implements MathOperation {
    public int operate(int a, int b) { return a + b; }
}

final class Subtract implements MathOperation {
    public int operate(int a, int b) { return a - b; }
}

// 使用
MathOperation add = (a, b) -> a + b;

十二、最佳实践

  1. 保持简洁:Lambda体最好不超过3行
  2. 使用方法引用:使代码更清晰
  3. 避免副作用:纯函数式操作更安全
  4. 命名参数:复杂Lambda应使用有意义的参数名
  5. 类型推断:通常省略参数类型,必要时显式声明
  6. 文档注释:复杂Lambda应添加注释说明

通过掌握Lambda表达式,您可以编写出更简洁、更易读的Java代码,特别是在处理集合和并发编程时。随着函数式编程在Java中的不断演进,Lambda已成为现代Java开发不可或缺的部分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值