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 的核心价值不是"炫技",而是让代码意图更清晰。记住三个原则:
- 简单逻辑用方法引用
- 复杂逻辑提取成方法
- 有状态或多方法用类
模板不是万能的,但能帮你快速起步。
