### Java函数式编程Lambda表达式与StreamAPI实战指南

#### 一、Lambda表达式基础

Lambda表达式是Java 8引入的核心特性,用于简化匿名内部类的写法,使代码更简洁清晰。

基本语法:

```java

(parameters) -> expression

(parameters) -> { statements; }

```

示例:

```java

// 传统匿名内部类

Runnable task1 = new Runnable() {

@Override

public void run() {

System.out.println(Hello World);

}

};

// Lambda表达式

Runnable task2 = () -> System.out.println(Hello World);

// 带参数的Lambda

Comparator comparator = (s1, s2) -> s1.compareTo(s2);

```

#### 二、函数式接口

函数式接口是只包含一个抽象方法的接口,可以使用`@FunctionalInterface`注解标记。

常用函数式接口:

- `Function`:接受T类型参数,返回R类型结果

- `Consumer`:接受T类型参数,无返回值

- `Supplier`:无参数,返回T类型结果

- `Predicate`:接受T类型参数,返回boolean结果

示例:

```java

// Predicate示例

Predicate isEmpty = s -> s == null || s.trim().isEmpty();

System.out.println(isEmpty.test()); // true

// Function示例

Function stringToInt = Integer::parseInt;

Integer result = stringToInt.apply(123);

```

#### 三、方法引用

方法引用是Lambda表达式的简化写法,有四种形式:

1. 静态方法引用:`ClassName::staticMethod`

2. 实例方法引用:`instance::method`

3. 特定类型的任意对象方法引用:`ClassName::method`

4. 构造器引用:`ClassName::new`

示例:

```java

// 静态方法引用

List numbers = Arrays.asList(1, 2, 3);

numbers.stream()

.map(Integer::parseInt)

.forEach(System.out::println);

// 构造器引用

Supplier> listSupplier = ArrayList::new;

List newList = listSupplier.get();

```

#### 四、Stream API核心操作

Stream API提供对集合数据的函数式处理,支持顺序和并行处理。

创建Stream:

```java

// 从集合创建

List list = Arrays.asList(a, b, c);

Stream stream1 = list.stream();

// 从数组创建

String[] array = {a, b, c};

Stream stream2 = Arrays.stream(array);

// 使用Stream.of

Stream stream3 = Stream.of(a, b, c);

```

#### 五、Stream中间操作

中间操作返回新的Stream,可以链式调用。

常用中间操作:

```java

List names = Arrays.asList(Alice, Bob, Charlie, David);

// filter - 过滤

List longNames = names.stream()

.filter(name -> name.length() > 4)

.collect(Collectors.toList());

// map - 转换

List nameLengths = names.stream()

.map(String::length)

.collect(Collectors.toList());

// sorted - 排序

List sortedNames = names.stream()

.sorted()

.collect(Collectors.toList());

// distinct - 去重

List uniqueNames = names.stream()

.distinct()

.collect(Collectors.toList());

```

#### 六、Stream终端操作

终端操作会触发Stream的处理并返回结果。

常用终端操作:

```java

List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// forEach - 遍历

numbers.stream()

.filter(n -> n % 2 == 0)

.forEach(System.out::println);

// collect - 收集结果

List evenNumbers = numbers.stream()

.filter(n -> n % 2 == 0)

.collect(Collectors.toList());

// reduce - 归约

Integer sum = numbers.stream()

.reduce(0, Integer::sum);

// count - 计数

long count = numbers.stream().count();

// anyMatch/allMatch/noneMatch - 匹配检查

boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0);

```

#### 七、实战案例

案例1:员工数据处理

```java

class Employee {

private String name;

private String department;

private double salary;

private int age;

// 构造方法、getter、setter省略

}

List employees = Arrays.asList(

new Employee(Alice, IT, 5000, 25),

new Employee(Bob, HR, 4000, 30),

new Employee(Charlie, IT, 6000, 35)

);

// 按部门分组,计算平均薪资

Map avgSalaryByDept = employees.stream()

.collect(Collectors.groupingBy(

Employee::getDepartment,

Collectors.averagingDouble(Employee::getSalary)

));

// 找出IT部门薪资最高的员工

Optional highestPaidInIT = employees.stream()

.filter(e -> IT.equals(e.getDepartment()))

.max(Comparator.comparingDouble(Employee::getSalary));

// 按年龄排序,获取前3名

List top3ByAge = employees.stream()

.sorted(Comparator.comparingInt(Employee::getAge).reversed())

.limit(3)

.collect(Collectors.toList());

```

案例2:复杂数据处理

```java

List sentences = Arrays.asList(

Java is a programming language,

Stream API makes collection processing easy,

Lambda expressions simplify code

);

// 统计所有句子中不同单词的数量

long uniqueWordCount = sentences.stream()

.flatMap(sentence -> Arrays.stream(sentence.split( )))

.map(String::toLowerCase)

.distinct()

.count();

// 按单词长度分组

Map> wordsByLength = sentences.stream()

.flatMap(sentence -> Arrays.stream(sentence.split( )))

.collect(Collectors.groupingBy(String::length));

// 找出出现频率最高的单词

Optional mostFrequentWord = sentences.stream()

.flatMap(sentence -> Arrays.stream(sentence.split( )))

.collect(Collectors.groupingBy(String::toLowerCase, Collectors.counting()))

.entrySet().stream()

.max(Map.Entry.comparingByValue())

.map(Map.Entry::getKey);

```

#### 八、并行Stream

利用多核处理器提高处理效率。

```java

List largeList = // 大量数据

// 顺序处理

long startTime = System.currentTimeMillis();

long count1 = largeList.stream().filter(n -> n % 2 == 0).count();

long sequentialTime = System.currentTimeMillis() - startTime;

// 并行处理

startTime = System.currentTimeMillis();

long count2 = largeList.parallelStream().filter(n -> n % 2 == 0).count();

long parallelTime = System.currentTimeMillis() - startTime;

System.out.println(顺序处理时间: + sequentialTime + ms);

System.out.println(并行处理时间: + parallelTime + ms);

```

#### 九、最佳实践

1. 保持Lambda简洁:复杂的逻辑应提取为方法

2. 避免副作用:不要在Lambda中修改外部状态

3. 使用方法引用:使代码更清晰

4. 注意性能:小数据集使用顺序Stream,大数据集考虑并行

5. 合理使用Optional:避免空指针异常

#### 十、常见陷阱

1. 在Lambda中修改外部变量:只能使用final或等效final的变量

2. 过度使用并行Stream:注意线程安全和性能开销

3. 忽略异常处理:在Lambda中妥善处理受检异常

通过掌握Lambda表达式和Stream API,可以显著提升Java代码的可读性和开发效率,实现更加函数式的编程风格。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐