JAVAEE Stream流

发布于:2025-07-11 ⋅ 阅读:(21) ⋅ 点赞:(0)
一、Stream流的概念
Stream流是一种顺序的元素集合,它允许你以声明式方式处理集合数据,使代码更简洁、更易读。Stream 流不是一个数据结构,而是对数据源(如集合、数组等)进行一系列聚合操作的工具。
流的特点
  • 不存储数据:流只是在数据源上进行操作,不存储元素。
  • 函数式编程:流的操作不会修改数据源,而是返回一个新的流。
  • 延迟执行:中间操作(如 filter、map)总是延迟执行,直到终端操作(如 collect、forEach)被调用。
  • 可消费性:流只能被消费一次,消费后需要重新创建。

流的创建

你可以通过多种方式创建流:
import java.util.*;
import java.util.stream.*;

public class StreamExample {
    public static void main(String[] args) {
        // 1. 从集合创建
        List<String> list = Arrays.asList("apple", "banana", "cherry");
        Stream<String> streamFromList = list.stream();
        
        // 2. 从数组创建
        String[] array = {"apple", "banana", "cherry"};
        Stream<String> streamFromArray = Arrays.stream(array);
        
        // 3. 使用Stream.of()
        Stream<String> streamOf = Stream.of("apple", "banana", "cherry");
        
        // 4. 创建空流
        Stream<String> emptyStream = Stream.empty();
        
        // 5. 创建无限流(通过生成器或迭代器)
        Stream<Integer> infiniteStream = Stream.generate(() -> 1); // 生成无限个1
        Stream<Integer> iterateStream = Stream.iterate(0, n -> n + 2); // 生成偶数序列
    }
}

流的操作

Java中的Stream流主要包含两种类型:中间操作和终端操作。中间操作用于对流进行一系列的转换和操作,而终端操作用于从流中获取结果。
中间操作
中间操作返回一个新的流,允许你链式调用多个操作。常见的中间操作有:
import java.util.*;
import java.util.stream.*;

public class StreamIntermediateOperations {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");
        
        // 1. filter:过滤元素
        Stream<String> filteredStream = fruits.stream()
                .filter(fruit -> fruit.startsWith("a"));
        
        // 2. map:转换元素
        Stream<Integer> lengthStream = fruits.stream()
                .map(String::length);
        
        // 3. distinct:去重
        Stream<String> distinctStream = Stream.of("apple", "apple", "banana")
                .distinct();
        
        // 4. sorted:排序
        Stream<String> sortedStream = fruits.stream()
                .sorted();
        
        // 5. limit:限制元素数量
        Stream<String> limitedStream = fruits.stream()
                .limit(3);
        
        // 6. skip:跳过元素
        Stream<String> skippedStream = fruits.stream()
                .skip(2);
        
        // 7. flatMap:将流中的每个元素转换为另一个流并合并
        Stream<String> words = Stream.of("Hello World", "Java Stream")
                .flatMap(s -> Arrays.stream(s.split(" ")));
    }
}
终端操作
终端操作会触发流的执行并产生结果。常见的终端操作有:
import java.util.*;
import java.util.stream.*;

public class StreamTerminalOperations {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");
        
        // 1. forEach:遍历元素
        fruits.stream()
                .forEach(System.out::println);
        
        // 2. collect:收集元素到集合
        List<String> filteredFruits = fruits.stream()
                .filter(fruit -> fruit.length() > 5)
                .collect(Collectors.toList());
        
        // 3. toArray:转换为数组
        String[] fruitArray = fruits.stream()
                .toArray(String[]::new);
        
        // 4. reduce:归约操作,将元素组合成一个值
        Optional<String> concatenated = fruits.stream()
                .reduce((a, b) -> a + ", " + b);
        
        // 5. count:统计元素数量
        long count = fruits.stream()
                .count();
        
        // 6. anyMatch、allMatch、noneMatch:匹配检查
        boolean anyStartsWithA = fruits.stream()
                .anyMatch(fruit -> fruit.startsWith("a"));
        
        boolean allStartsWithA = fruits.stream()
                .allMatch(fruit -> fruit.startsWith("a"));
        
        boolean noneStartsWithZ = fruits.stream()
                .noneMatch(fruit -> fruit.startsWith("z"));
        
        // 7. findFirst、findAny:查找元素
        Optional<String> first = fruits.stream()
                .findFirst();
        
        Optional<String> any = fruits.stream()
                .findAny();
    }
}

流的使用示例

List<String> list = Arrays.asList("apple", "banana", "cherry");

// List 转 Map
Map<Integer, String> listToMap = list.stream()
        //Collectors.toMap是一个终端操作,将流中的元素收集到一个Map中
        .collect(Collectors.toMap(
                String::length,  // 键:字符串长度,"cherry".length() → 6(与 "banana" 冲突)
                s -> s,          // 值:字符串本身
                (existing, replacement) -> existing  // 处理键冲突的策略
        ));
System.out.println("List 转 Map: " + listToMap);
执行流程:
list.stream()
  • List转换为Stream,为后续的流式操作做准备。
.collect(Collectors.toMap(...))
  • Collectors.toMap是一个终端操作,将流中的元素收集到一个Map中。
  • 该方法接收三个核心参数:
String::length
  • 使用方法引用,将字符串的长度作为 Map 的键。
  • 例如:"apple" 的长度为 5,"banana" 的长度为 6。
s -> s
  • 使用 Lambda 表达式,直接将字符串本身作为 Map 的值。
  • 等效于Function.identity()
(existing, replacement) -> existing
  • 当两个不同的字符串具有相同长度时(如 "apple" 和 "cherry" 均为 5),保留先出现的元素(existing),丢弃后出现的元素(replacement)。
  • 若改为(e, r) -> r,则保留后出现的元素。
处理"cherry"时:
  • 键:"cherry".length() → 6(与 "banana" 冲突)
  • 值:"cherry"
  • 冲突策略:保留existing("banana"),丢弃replacement("cherry")
  • 最终 Map:{5=apple, 6=banana}
输出:

网站公告

今日签到

点亮在社区的每一天
去签到