Java 函数式编程是在 Java 8 中引入的重要特性,它使得编写更简洁、可读性更高的代码成为可能。下面是一个全面的介绍:
1. 核心概念
Lambda 表达式
// 传统方式
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
// Lambda 表达式
Runnable r2 = () -> System.out.println("Hello");
// 带参数的 Lambda
Comparator<String> comp = (s1, s2) -> s1.compareTo(s2);
函数式接口
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
}
// 使用
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;
System.out.println(add.calculate(5, 3)); // 8
System.out.println(multiply.calculate(5, 3)); // 15
2. Java 内置的函数式接口
常用接口
import java.util.function.*;
// Predicate - 接受参数返回boolean
Predicate<String> isEmpty = s -> s.isEmpty();
// Function - 接受参数返回结果
Function<String, Integer> stringLength = s -> s.length();
// Consumer - 接受参数无返回
Consumer<String> printer = s -> System.out.println(s);
// Supplier - 无参数返回结果
Supplier<Double> randomSupplier = () -> Math.random();
// UnaryOperator - 输入输出类型相同
UnaryOperator<String> toUpper = s -> s.toUpperCase();
// BinaryOperator - 两个相同类型的参数返回同类型结果
BinaryOperator<Integer> adder = (a, b) -> a + b;
3. Stream API
基本操作
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 过滤和映射
List<String> result = names.stream()
.filter(name -> name.length() > 4)
.map(String::toUpperCase)
.collect(Collectors.toList());
// [ALICE, CHARLIE, DAVID]
// 排序
List<String> sorted = names.stream()
.sorted()
.collect(Collectors.toList());
// 去重
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3);
List<Integer> distinct = numbers.stream()
.distinct()
.collect(Collectors.toList());
// [1, 2, 3]
终端操作
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
// 统计
long count = nums.stream().count();
int sum = nums.stream().mapToInt(Integer::intValue).sum();
Optional<Integer> max = nums.stream().max(Integer::compare);
// 匹配
boolean anyMatch = nums.stream().anyMatch(n -> n > 3); // true
boolean allMatch = nums.stream().allMatch(n -> n > 0); // true
boolean noneMatch = nums.stream().noneMatch(n -> n < 0); // true
// 归约
int total = nums.stream().reduce(0, (a, b) -> a + b);
int product = nums.stream().reduce(1, (a, b) -> a * b);
4. 方法引用
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 静态方法引用
names.forEach(System.out::println);
// 实例方法引用
names.stream()
.map(String::toUpperCase) // 等价于 s -> s.toUpperCase()
.forEach(System.out::println);
// 构造函数引用
Supplier<List<String>> listSupplier = ArrayList::new;
List<String> newList = listSupplier.get();
5. Optional 类
public class OptionalExample {
public static void main(String[] args) {
// 创建 Optional
Optional<String> optional = Optional.of("Hello");
Optional<String> emptyOptional = Optional.empty();
Optional<String> nullableOptional = Optional.ofNullable(null);
// 使用
optional.ifPresent(System.out::println); // 如果存在则打印
String result = optional.orElse("Default");
String result2 = emptyOptional.orElseGet(() -> "Generated Default");
// 链式调用
Optional<String> processed = optional
.filter(s -> s.length() > 3)
.map(String::toUpperCase);
// flatMap 用于嵌套 Optional
Optional<Optional<String>> nested = optional.map(Optional::of);
Optional<String> flattened = optional.flatMap(Optional::of);
}
}
6. 实际应用示例
示例1:数据处理
public class Employee {
private String name;
private int age;
private double salary;
private String department;
// 构造器、getter、setter
}
public class FunctionalExample {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("Alice", 30, 50000, "IT"),
new Employee("Bob", 25, 45000, "HR"),
new Employee("Charlie", 35, 60000, "IT"),
new Employee("David", 28, 48000, "HR")
);
// 按部门分组,计算平均工资
Map<String, Double> avgSalaryByDept = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.averagingDouble(Employee::getSalary)
));
// 找出IT部门年龄大于25的员工
List<Employee> itSeniors = employees.stream()
.filter(e -> "IT".equals(e.getDepartment()))
.filter(e -> e.getAge() > 25)
.sorted(Comparator.comparing(Employee::getSalary).reversed())
.collect(Collectors.toList());
// 并行处理
double totalSalary = employees.parallelStream()
.mapToDouble(Employee::getSalary)
.sum();
}
}
示例2:自定义函数式接口
@FunctionalInterface
interface TriFunction<T, U, V, R> {
R apply(T t, U u, V v);
}
public class CustomFunctional {
public static void main(String[] args) {
TriFunction<Integer, Integer, Integer, Integer> sumThree =
(a, b, c) -> a + b + c;
System.out.println(sumThree.apply(1, 2, 3)); // 6
// 函数组合
Function<Integer, Integer> add2 = x -> x + 2;
Function<Integer, Integer> multiply3 = x -> x * 3;
Function<Integer, Integer> composed = add2.andThen(multiply3);
System.out.println(composed.apply(5)); // (5+2)*3 = 21
}
}
7. 最佳实践和注意事项
优点:
- 简洁性:减少样板代码
- 可读性:表达更清晰
- 并行处理:更容易实现并行计算
- 延迟计算:提高性能
注意事项:
- 不要过度使用:保持代码可读性
- 避免副作用:函数式代码应该是无状态的
- 性能考虑:Stream 创建有开销,小数据集可能传统循环更快
- 调试困难:Lambda 表达式调试相对困难
何时使用:
- 集合处理和数据转换
- 事件处理
- 回调函数
- 并行处理
- 条件逻辑的简化
8. Java 9+ 增强
Java 9 及后续版本增加了更多函数式特性:
// Java 9: Stream API 增强
List.of(1, 2, 3, 4, 5).stream()
.takeWhile(n -> n < 4) // 取满足条件的元素
.forEach(System.out::println); // 1, 2, 3
// Java 10: var 与 Lambda
var list = List.of("a", "b", "c");
list.forEach((var s) -> System.out.println(s));
Java 函数式编程通过 Stream API、Lambda 表达式和函数式接口,大大提高了代码的表达能力和简洁性,是现代 Java 开发中必须掌握的重要技能。