Skip to content

Lambda 实践

学会语法是一回事,用好是另一回事。

这一节不讲语法,讲场景。每个场景都有对应的代码模板,拿去直接用就行。

场景一:回调模式

传统的回调用接口实现,写起来很啰嗦。Lambda 让它变简洁:

java
@FunctionalInterface
interface Callback<T> {
    void onResult(T result);
    default void onError(Exception e) {
        throw new RuntimeException(e);
    }
}

class DataService {
    public void fetchData(String id, Callback<String> callback) {
        try {
            String data = loadFromDatabase(id);
            callback.onResult(data);
        } catch (Exception e) {
            callback.onError(e);
        }
    }
    
    private String loadFromDatabase(String id) {
        return "Data for " + id;
    }
}

// 使用
DataService service = new DataService();

service.fetchData("001", result -> System.out.println("成功: " + result));

service.fetchData("002", new Callback<String>() {
    @Override
    public void onResult(String result) {
        System.out.println("成功: " + result);
    }
    
    @Override
    public void onError(Exception e) {
        System.out.println("失败: " + e.getMessage());
    }
});

场景二:策略模式

不用写一堆策略类实现,一个 Lambda 就够:

java
import java.util.*;

interface SortStrategy<T> {
    List<T> apply(List<T> input);
}

public class StrategyDemo {
    
    public static void main(String[] args) {
        List<Integer> data = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6);
        
        // 用 Lambda 定义策略,不用创建类
        SortStrategy<Integer> ascending = list -> {
            List<Integer> copy = new ArrayList<>(list);
            Collections.sort(copy);
            return copy;
        };
        
        SortStrategy<Integer> descending = list -> {
            List<Integer> copy = new ArrayList<>(list);
            copy.sort(Collections.reverseOrder());
            return copy;
        };
        
        SortStrategy<Integer> byAbs = list -> {
            List<Integer> copy = new ArrayList<>(list);
            copy.sort(Comparator.comparingInt(Math::abs));
            return copy;
        };
        
        System.out.println("升序: " + ascending.apply(data));
        System.out.println("降序: " + descending.apply(data));
    }
}

场景三:延迟执行

不想每次都计算结果?用 Supplier 包装:

java
import java.util.function.*;

public class LazyDemo {
    
    public static void main(String[] args) {
        // ❌ 立即计算
        long start = System.currentTimeMillis();
        long result1 = expensiveComputation();
        System.out.println("计算结果: " + result1 + 
            ", 耗时: " + (System.currentTimeMillis() - start) + "ms");
        
        // ✅ 延迟计算:需要时才执行
        Supplier<Long> lazyResult = this::expensiveComputationLazy;
        
        // 这里没有真正计算
        System.out.println("准备调用...");
        
        // 真正调用时才计算
        start = System.currentTimeMillis();
        long result2 = lazyResult.get();
        System.out.println("计算结果: " + result2 + 
            ", 耗时: " + (System.currentTimeMillis() - start) + "ms");
    }
    
    private static long expensiveComputation() {
        try { Thread.sleep(500); } catch (Exception e) {}
        return 42L;
    }
    
    private long expensiveComputationLazy() {
        try { Thread.sleep(500); } catch (Exception e) {}
        return 42L;
    }
}

场景四:Builder 模式

Lambda 让 Builder 更自然:

java
class Person {
    private String name;
    private int age;
    private String address;
    
    private Person(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + 
            ", address='" + address + "'}";
    }
}

class PersonBuilder {
    private String name;
    private int age;
    private String address;
    
    PersonBuilder name(String name) {
        this.name = name;
        return this;
    }
    
    PersonBuilder age(int age) {
        this.age = age;
        return this;
    }
    
    PersonBuilder address(String address) {
        this.address = address;
        return this;
    }
    
    Person build() {
        return new Person(name, age, address);
    }
}

public class BuilderLambdaDemo {
    public static void main(String[] args) {
        Person person = new PersonBuilder()
            .name("张三")
            .age(25)
            .address("北京")
            .build();
        
        System.out.println(person);
    }
}

场景五:条件执行

不用一堆 if-else:

java
import java.util.function.*;

public class ConditionalDemo {
    
    public static void main(String[] args) {
        boolean debugMode = true;
        
        // ❌ 传统方式
        if (debugMode) {
            logDebug("Starting process...");
        }
        
        // ✅ Lambda + 条件执行
        Runnable debugLog = () -> logDebug("Starting process...");
        
        if (debugMode) {
            debugLog.run();  // 有条件才执行
        }
        
        // ✅ 更优雅:Predicate + filter
        Optional.ofNullable(getConfig())
            .filter(cfg -> debugMode)  // 只在 debug 模式下保留
            .ifPresent(cfg -> System.out.println("Config: " + cfg));
    }
    
    private static void logDebug(String msg) {
        System.out.println("[DEBUG] " + msg);
    }
    
    private static String getConfig() {
        return "config_data";
    }
}

场景六:并行处理

简单任务并行化:

java
import java.util.*;
import java.util.concurrent.*;

public class ParallelDemo {
    
    public static void main(String[] args) throws Exception {
        List<String> urls = Arrays.asList(
            "https://api.example.com/1",
            "https://api.example.com/2",
            "https://api.example.com/3",
            "https://api.example.com/4"
        );
        
        ExecutorService executor = Executors.newFixedThreadPool(4);
        
        long start = System.currentTimeMillis();
        
        // 提交所有任务
        List<Future<String>> futures = new ArrayList<>();
        for (String url : urls) {
            futures.add(executor.submit(() -> fetchData(url)));
        }
        
        // 收集结果
        List<String> results = new ArrayList<>();
        for (Future<String> future : futures) {
            results.add(future.get());
        }
        
        System.out.println("耗时: " + 
            (System.currentTimeMillis() - start) + "ms");
        System.out.println("结果: " + results);
        
        executor.shutdown();
    }
    
    private static String fetchData(String url) {
        try { Thread.sleep(500); } catch (Exception e) {}
        return "Data from " + url;
    }
}

最佳实践清单

用 Lambda 时记住这些:

java
// ✅ 1. 保持简短:超过 3 行,考虑拆成方法
list.stream()
    .filter(s -> s.length() > 3)         // 短:直接写
    .map(this::transformComplex)          // 长:提取方法
    .collect(Collectors.toList());

// ✅ 2. 避免副作用
// ❌ Bad
List<String> result = new ArrayList<>();
list.stream()
    .filter(s -> s.length() > 3)
    .forEach(s -> result.add(s));  // 修改外部变量

// ✅ Good
List<String> result = list.stream()
    .filter(s -> s.length() > 3)
    .collect(Collectors.toList());

// ✅ 3. 注意泛型转义
// ❌ 会被解析为 HTML
// list.stream().filter(s -> s instanceof List<String>)

// ✅ 用转义符
// list.stream().filter(s -> s instanceof List)...

// ✅ 4. 方法引用 > Lambda
// 优先使用
list.forEach(System.out::println);

// Lambda 用于有逻辑的场景
list.forEach(s -> {
    if (s.length() > 5) System.out.println(s);
});

// ✅ 5. 用 var(JDK 10+)简化复杂 Lambda
var processor = (var s) -> s.toUpperCase().trim();
// 等价于
BiFunction<String, String, String> processor2 = 
    (String s1, String s2) -> s1 + s2;

小结

Lambda 的核心价值不是"炫技",而是让代码意图更清晰。记住三个原则:

  1. 简单逻辑用方法引用
  2. 复杂逻辑提取成方法
  3. 有状态或多方法用类

模板不是万能的,但能帮你快速起步。

基于 VitePress 构建