在 Java 编程领域,Lambda 表达式与 Stream API 的组合堪称一对强大的搭档,极大地简化了集合数据处理的过程。本文将深入探讨如何借助 Lambda 表达式实现各种常见的 Stream 流操作。
List 转 Set
将 List 转换为 Set 是去除重复元素的便捷方式。利用 Stream 流,代码如下:
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class ListToSetExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(2);
list.add(3);
Set<Integer> set = list.stream()
.collect(Collectors.toSet());
System.out.println(set);
}
}
通过stream()
方法创建流,再使用collect(Collectors.toSet())
将流中的元素收集到 Set 中,Set 的特性会自动剔除重复元素。
List 转 Map
当我们有一个对象 List,想以对象的某个属性为键构建 Map 时,可这样操作:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class ListToMapExample {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person("Alice", 25));
personList.add(new Person("Bob", 30));
Map<String, Person> personMap = personList.stream()
.collect(Collectors.toMap(Person::getName, p -> p));
System.out.println(personMap);
}
}
Collectors.toMap()
的第一个参数指定键的提取方式,这里是Person::getName
,第二个参数p -> p
表示值就是对象本身。
Map 转 List
把 Map 的键值对转换为 List,能方便后续对键值对进行统一处理:
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class MapToListExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("key1", 1);
map.put("key2", 2);
List<Map.Entry<String, Integer>> entryList = map.entrySet()
.stream()
.collect(Collectors.toList());
System.out.println(entryList);
}
}
先通过entrySet()
获取键值对集合,再用 Stream 流和collect(Collectors.toList())
将其收集为 List。
过滤、求和与分组
(一)过滤:筛选符合条件元素
从 List 中筛选出偶数 此时我们会借助.filter方法:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class FilterExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
List<Integer> evenList = list.stream()
.filter(num -> num % 2 == 0)
.collect(Collectors.toList());
System.out.println(evenList);
}
}
(二)求和:计算数值总和
对 List 中的整数求和:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class SumExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
int sum = list.stream()
.mapToInt(Integer::intValue)
.sum();
System.out.println(sum);
}
}
mapToInt()
将 Integer 流转换为 IntStream,再用sum()
方法计算总和。
分组:按特定属性归类
对 Person 对象按年龄分组:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class GroupingExample {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person("Alice", 25));
personList.add(new Person("Bob", 25));
personList.add(new Person("Charlie", 30));
Map<Integer, List<Person>> groupedMap = personList.stream()
.collect(Collectors.groupingBy(Person::getAge));
System.out.println(groupedMap);
}
}
map 与 reduce:元素转换与累积
(一)map:元素映射转换
将字符串 List 中的元素转为大写:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class MapExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
List<String> upperList = list.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upperList);
}
}
map()
方法根据 Lambda 表达式String::toUpperCase
将每个元素进行转换。
(二)reduce:元素累积操作
reduce
是一个用于对流中的元素进行累积操作的终端操作(Terminal Operation)。它的主要作用是将流中的元素组合成一个单个的值,通过指定的二元操作符(Binary Operator)来不断地将元素进行合并和累积。
reduce
方法的传参情况
两个参数
这种形式的 reduce
方法签名如下:
<U> U reduce(U identity, BinaryOperator<U> accumulator)
- 参数说明:
identity
:初始值,也称为 “标识值”。它是一个与流中元素类型兼容的初始对象,在累积操作开始时作为起始点。如果流为空,reduce
操作会直接返回这个初始值。accumulator
:一个二元操作符,是一个BinaryOperator<U>
类型的函数。它接受两个参数,第一个参数是累积结果(从初始值开始),第二个参数是流中的元素,用于将流中的元素逐步累积到结果中。
一个参数
Optional<T> reduce(BinaryOperator<T> accumulator)
- 参数说明:
accumulator
:同样是一个二元操作符,用于将流中的元素两两组合,逐步累积得到最终结果。
计算整数 List 中所有元素的乘积
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class ReduceExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Optional<Integer> product = list.stream()
.reduce((a, b) -> a * b);
product.ifPresent(System.out::println);
}
}
reduce()
方法按照 Lambda 表达式(a, b) -> a * b
对元素进行累积计算。
查找最大值或最小值:
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
public class FindMaxWithReduce {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> max = numbers.stream()
.reduce((a, b) -> a > b? a : b);
if (max.isPresent()) {
System.out.println("Max: " + max.get());
}
}
}
连接字符串
对于一个包含字符串的 Stream
,可以使用 reduce
来连接所有的字符串。
import java.util.Arrays;
import java.util.List;
public class ConcatenateStringsWithReduce {
public static void main(String[] args) {
List<String> words = Arrays.asList("Hello", "World", "Java", "Stream");
String result = words.stream()
.reduce("", (accumulator, word) -> accumulator + word);
System.out.println("Concatenated String: " + result);
}
}
Lambda 表达式和 Stream API 的结合,为 Java 开发者提供了简洁高效的数据处理方式,熟练运用这些操作,能让代码更加优雅和易维护。