目录
引言:为什么需要Stream流
想象一下,你需要从一堆水果中挑选出所有红色的、重量超过200克的苹果,并按重量排序取前三个。传统方式需要你写多个循环和条件判断,而使用Stream流,你可以这样做:
List<Apple> result = apples.stream()
.filter(a -> a.getColor().equals("红色"))
.filter(a -> a.getWeight() > 200)
.sorted((a1, a2) -> a1.getWeight() - a2.getWeight())
.limit(3)
.collect(Collectors.toList());
Stream流就像一条传送带,数据放上去后可以经过多个处理站,最终得到你想要的结果,让代码更简洁、可读性更强。
一、Stream流基础
1.1 什么是Stream流
Stream流是Java 8引入的处理集合数据的API,它让我们以声明式(描述要做什么,而不是怎么做)的方式处理数据。
核心特点:
- 声明式编程:更关注做什么,而不是怎么做
- 支持链式操作:可以像搭积木一样组合多个操作
- 支持并行处理:轻松切换到并行模式,提高性能
- 延迟执行:在最后一步(终端操作)才会真正执行
1.2 Stream流与集合的区别
简单对比:
- 集合就像一个仓库,专注于存储和访问数据
- Stream就像一条流水线,专注于对数据进行操作
| 特性 | 集合 Collection | Stream流 |
|---|---|---|
| 存储方式 | 存储元素 | 不存储元素 |
| 操作时机 | 立即执行 | 延迟执行(惰性) |
| 遍历次数 | 可多次遍历 | 只能遍历一次 |
| 关注点 | 数据 | 计算 |
1.3 Stream流的使用步骤
Stream流的使用分为三个步骤:
- 创建Stream流:获取一个数据流
- 使用中间方法:对流中的数据进行操作
- 使用终结方法:对流水线上的数据进行最终操作
// 一个完整的Stream操作示例
List<String> names = Arrays.asList("小明", "小红", "小刚", "小华");
List<String> filteredNames = names.stream() // 1.创建Stream流
.filter(name -> name.length() > 1) // 2.中间操作
.collect(Collectors.toList()); // 3.终端操作
二、创建Stream流
2.1 从不同数据源创建Stream
我们可以从多种数据源创建Stream:
| 获取方式 | 方法名 | 说明 |
|---|---|---|
| 单列集合 | default Stream<E> stream() | Collection中的默认方法 |
| 双列集合 | 无 | 无法直接使用stream流 |
| 数组 | public static <T> Stream<T> stream(T[] array) | Arrays工具类中的静态方法 |
| 一堆零散数据 | public static<T> Stream<T> of(T... values) | Stream接口中的静态方法 |
2.1.1 从单列集合创建Stream(最常用)
// 1.单列集合获取Stream流
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c", "d", "e");
// 获取一条流水线,并把集合中的数据放到流水线上
Stream<String> stream1 = list.stream();
// 使用终结方法打印一下流水线上的所有数据
stream1.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
// s:依次表示流水线上的每一个数据
System.out.println(s);
}
});
// 使用Lambda简化
list.stream().forEach(s -> System.out.println(s));
2.1.2 从双列集合创建Stream
双列集合没有直接获取Stream流的方法,但可以间接获取:
// 1.创建双列集合
HashMap<String, Integer> hm = new HashMap<>();
// 2.添加数据
hm.put("红楼梦", 111);
hm.put("西游记", 222);
hm.put("水浒传", 333);
hm.put("三国演义", 444);
// 3.第一种获取stream流的方式:通过键
hm.keySet().stream().forEach(s -> System.out.println(s));
// 4.第二种获取stream流的方式:通过值
hm.values().stream().forEach(i -> System.out.println(i));
// 5.第三种获取stream流的方式:通过键值对
hm.entrySet().stream().forEach(entry -> System.out.println(entry.getKey() + "=" + entry.getValue()));
2.1.3 从数组创建Stream
// 1.创建数组
int[] arr1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
String[] arr2 = {"a", "b", "c"};
// 2.获取stream流
Arrays.stream(arr1).forEach(s -> System.out.println(s));
System.out.println("========================");
Arrays.stream(arr2).forEach(s -> System.out.println(s));
2.1.4 从零散数据创建Stream
// 一堆零散数据 public static<T> Stream<T> of(T... values) Stream接口中的静态方法
Stream.of(1, 2, 3, 4, 5).forEach(s -> System.out.println(s));
Stream.of("a", "b", "c", "d", "e").forEach(s -> System.out.println(s));
三、Stream流的中间操作
中间操作会返回一个新的Stream,可以链式调用。中间操作不会立即执行,而是等到终端操作时才一起执行。
Stream的中间方法包括:
| 名称 | 说明 |
|---|---|
| filter(Predicate<?> predicate) | 过滤 |
| limit(long maxSize) | 获取前几个元素 |
| skip(long n) | 跳过前几个元素 |
| distinct() | 元素去重(依赖hashCode和equals方法) |
| concat(Stream a, Stream b) | 合并a和b两个流为一个流 |
| map(Function<T, R> mapper) | 转换流中的数据类型 |
3.1 筛选和切片操作
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 5);
// filter: 过滤元素
List<Integer> greaterThan3 = numbers.stream()
.filter(n -> n > 3)
.collect(Collectors.toList());
System.out.println("大于3的数: " + greaterThan3); // [4, 5]
// distinct: 去除重复
List<Integer> uniqueNumbers = numbers.stream()
.distinct()
.collect(Collectors.toList());
System.out.println("去重后: " + uniqueNumbers); // [1, 2, 3, 4, 5]
// limit: 限制数量
List<Integer> firstThree = numbers.stream()
.limit(3)
.collect(Collectors.toList());
System.out.println("前三个数: " + firstThree); // [1, 2, 2]
// skip: 跳过元素
List<Integer> skipFirst2 = numbers.stream()
.skip(2)
.collect(Collectors.toList());
System.out.println("跳过前两个: " + skipFirst2); // [2, 3, 4, 5]
// 组合使用
List<Integer> result = numbers.stream()
.distinct() // 先去重
.skip(1) // 跳过第一个
.limit(3) // 取3个
.collect(Collectors.toList());
System.out.println("去重后跳过第一个,再取三个: " + result); // [2, 3, 4]
3.2 映射操作
List<String> words = Arrays.asList("Java", "Stream", "API");
// map: 转换元素
List<Integer> wordLengths = words.stream()
.map(word -> word.length()) // 获取每个单词的长度
.collect(Collectors.toList());
System.out.println("单词长度: " + wordLengths); // [4, 6, 3]
// map的另一个示例:转换大写
List<String> upperCaseWords = words.stream()
.map(word -> word.toUpperCase())
.collect(Collectors.toList());
System.out.println("转换为大写: " + upperCaseWords); // [JAVA, STREAM, API]
// flatMap: 扁平化处理(将多个流合并为一个流)
List<List<Integer>> nestedList = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4, 5)
);
List<Integer> flatList = nestedList.stream()
.flatMap(list -> list.stream()) // 将每个内部List转为Stream然后合并
.collect(Collectors.toList());
System.out.println("扁平化后: " + flatList); // [1, 2, 3, 4, 5]
// fl

最低0.47元/天 解锁文章
3188

被折叠的 条评论
为什么被折叠?



