java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java Stream 流

Java Stream 流基本概念和使用方式详解

作者:MadeInSQL

Stream是Java 8 引入的全新API,它基于函数式编程思想,为集合操作提供了一种声明式的处理方式,本文给大家介绍Java Stream流基本概念和核心特性,感兴趣的朋友一起看看吧

一、Stream 基础概念与核心特性

1.1 什么是 Stream 流

Stream 是 Java 8 引入的全新API,它基于函数式编程思想,为集合操作提供了一种声明式的处理方式。与传统的命令式集合操作不同,Stream API 使得数据处理更加高效且易于并行化。

核心特点详解:

典型使用场景:

示例代码:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 传统方式
for(String name : names) {
    if(name.startsWith("A")) {
        System.out.println(name.toUpperCase());
    }
}
// Stream方式
names.stream()
     .filter(name -> name.startsWith("A"))
     .map(String::toUpperCase)
     .forEach(System.out::println);

1.2 Stream 与集合的区别

特性集合(Collection)Stream(流)
存储存储实际数据不存储数据
操作方式外部迭代(foreach循环)内部迭代
数据处理立即执行延迟执行
可重用性可多次遍历只能遍历一次
并行能力需要手动实现内置并行支持

二、Stream 创建方式详解

2.1 从集合创建

// 从List创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream1 = list.stream();
// 从Set创建
Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3));
Stream<Integer> stream2 = set.stream();

2.2 从数组创建

String[] array = {"a", "b", "c"};
Stream<String> stream3 = Arrays.stream(array);
// 指定范围
Stream<String> stream4 = Arrays.stream(array, 1, 3); // "b", "c"

2.3 使用静态工厂方法

// 使用Stream.of()
Stream<String> stream5 = Stream.of("a", "b", "c");
// 创建空流
Stream<String> emptyStream = Stream.empty();
// 创建无限流
Stream<Integer> infiniteStream1 = Stream.iterate(0, n -> n + 2); // 0,2,4,6...
Stream<Double> infiniteStream2 = Stream.generate(Math::random); // 随机数流

2.4 其他创建方式

// 从文件创建
try (Stream<String> lines = Files.lines(Paths.get("data.txt"))) {
    lines.forEach(System.out::println);
}
// 从字符串创建
IntStream charStream = "Hello".chars();

三、Stream 核心操作全解析

3.1 中间操作(Intermediate Operations)

过滤操作

// filter() - 筛选偶数
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evens = numbers.stream()
                           .filter(n -> n % 2 == 0)
                           .collect(Collectors.toList()); // [2, 4]
// distinct() - 去重
List<String> names = Arrays.asList("John", "John", "Mary");
List<String> uniqueNames = names.stream()
                              .distinct()
                              .collect(Collectors.toList()); // ["John", "Mary"]

映射操作

// map() - 字符串转大写
List<String> upperNames = names.stream()
                             .map(String::toUpperCase)
                             .collect(Collectors.toList());
// flatMap() - 扁平化处理
List<List<String>> nestedList = Arrays.asList(
    Arrays.asList("a", "b"),
    Arrays.asList("c", "d")
);
List<String> flatList = nestedList.stream()
                                .flatMap(Collection::stream)
                                .collect(Collectors.toList()); // ["a", "b", "c", "d"]

限制与跳过

// limit() - 限制数量
List<Integer> limited = numbers.stream()
                             .limit(3)
                             .collect(Collectors.toList()); // [1, 2, 3]
// skip() - 跳过元素
List<Integer> skipped = numbers.stream()
                            .skip(2)
                            .collect(Collectors.toList()); // [3, 4, 5]

排序操作

// sorted() - 自然排序
List<String> sortedNames = names.stream()
                              .sorted()
                              .collect(Collectors.toList());
// sorted(Comparator) - 自定义排序
List<Person> people = Arrays.asList(
    new Person("John", 25),
    new Person("Mary", 20)
);
List<Person> sortedByAge = people.stream()
                               .sorted(Comparator.comparing(Person::getAge))
                               .collect(Collectors.toList());

3.2 终端操作(Terminal Operations)

匹配与查找

// anyMatch() - 是否有元素匹配
boolean hasEven = numbers.stream()
                       .anyMatch(n -> n % 2 == 0); // true
// findFirst() - 获取第一个元素
Optional<Integer> first = numbers.stream()
                               .findFirst(); // Optional[1]

聚合操作

// count() - 计数
long count = numbers.stream().count(); // 5
// max()/min() - 最大最小值
Optional<Integer> max = numbers.stream()
                             .max(Integer::compare); // Optional[5]
// reduce() - 归约操作
Optional<Integer> sum = numbers.stream()
                             .reduce(Integer::sum); // Optional[15]

收集操作

// collect() - 转换为集合
Set<Integer> numberSet = numbers.stream()
                              .collect(Collectors.toSet());
// joining() - 字符串连接
String joined = names.stream()
                   .collect(Collectors.joining(", ")); // "John, John, Mary"
// groupingBy() - 分组
Map<Integer, List<Person>> peopleByAge = people.stream()
                                             .collect(Collectors.groupingBy(Person::getAge));

遍历操作

// forEach() - 遍历消费
numbers.stream().forEach(System.out::println);
// forEachOrdered() - 保证顺序
numbers.parallelStream().forEachOrdered(System.out::println);

四、并行流与性能优化

4.1 并行流基础

// 创建并行流
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 方式1:从集合创建
Stream<Integer> parallelStream1 = numbers.parallelStream();
// 方式2:将顺序流转并行
Stream<Integer> parallelStream2 = numbers.stream().parallel();
// 示例:并行处理
long count = numbers.parallelStream()
                  .filter(n -> n % 2 == 0)
                  .count();

4.2 性能考量

适合使用并行流的场景

注意事项

4.3 自定义线程池

// 使用自定义ForkJoinPool
ForkJoinPool customPool = new ForkJoinPool(4);
long result = customPool.submit(() -> 
    numbers.parallelStream()
         .filter(n -> n % 2 == 0)
         .count()
).get();

五、实战应用案例

5.1 数据处理案例

// 案例1:统计单词频率
List<String> words = Arrays.asList("hello", "world", "hello", "java");
Map<String, Long> wordCounts = words.stream()
                                  .collect(Collectors.groupingBy(
                                      Function.identity(),
                                      Collectors.counting()
                                  ));
// 案例2:多级分组
List<Employee> employees = ...;
Map<String, Map<String, List<Employee>>> byDeptAndCity = employees.stream()
    .collect(Collectors.groupingBy(Employee::getDepartment,
             Collectors.groupingBy(Employee::getCity)));

5.2 文件处理案例

// 读取文件并处理
try (Stream<String> lines = Files.lines(Paths.get("data.txt"))) {
    List<String> filteredLines = lines
        .filter(line -> !line.startsWith("#")) // 过滤注释行
        .map(String::trim)                     // 去除空格
        .collect(Collectors.toList());
}
// 查找文件中最长的行
Optional<String> longest = Files.lines(Paths.get("data.txt"))
    .max(Comparator.comparing(String::length));

5.3 数据库查询结果处理

// 使用Stream处理JDBC结果
List<Person> persons = new ArrayList<>();
try (Connection conn = DriverManager.getConnection(url, user, pass);
     Statement stmt = conn.createStatement();
     ResultSet rs = stmt.executeQuery("SELECT * FROM persons")) {
    Stream<ResultSet> stream = StreamSupport.stream(
        new Spliterators.AbstractSpliterator<ResultSet>(
            Long.MAX_VALUE, Spliterator.ORDERED) {
            public boolean tryAdvance(Consumer<? super ResultSet> action) {
                try {
                    if (!rs.next()) return false;
                    action.accept(rs);
                    return true;
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }, false);
    persons = stream.map(rs -> new Person(rs.getString("name"), rs.getInt("age")))
                   .collect(Collectors.toList());
}

六、常见问题与最佳实践

6.1 常见陷阱

  1. 重复使用Stream

    Stream<String> stream = Stream.of("a", "b", "c");
    stream.forEach(System.out::println);
    stream.forEach(System.out::println); // 抛出IllegalStateException
    
  2. 修改源集合

    List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
    Stream<String> stream = list.stream();
    list.add("d"); // 可能导致ConcurrentModificationException
    
  3. 无限流未限制

    Stream.iterate(0, i -> i + 1)
        .forEach(System.out::println); // 无限循环
    

6.2 性能优化建议

  1. 优先使用基本类型流

    // 使用IntStream代替Stream<Integer>
    IntStream.range(0, 100).sum();
    
  2. 短路操作优化

    // 使用anyMatch代替filter+findFirst
    boolean hasNegative = numbers.stream().anyMatch(n -> n < 0);
    
  3. 合并中间操作

    // 合并多个filter
    list.stream().filter(s -> s != null && s.length() > 3);
    

6.3 调试技巧

  1. 使用peek()调试

    List<String> result = list.stream()
        .peek(System.out::println)  // 调试输出
        .filter(s -> s.length() > 3)
        .peek(System.out::println)  // 调试输出
        .collect(Collectors.toList());
    
  2. 转换为并行流查找问题

    list.stream()
        .parallel()
        .map(s -> {throw new RuntimeException();}) // 更容易暴露线程安全问题
        .collect(Collectors.toList());
    

七、高级特性与未来展望

7.1 Java 9+ 增强特性

// takeWhile/dropWhile (Java 9+)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 3, 2, 1);
List<Integer> taken = numbers.stream()
                           .takeWhile(n -> n < 4) // [1, 2, 3]
                           .collect(Collectors.toList());
// ofNullable (Java 9+)
Stream<String> stream = Stream.ofNullable(System.getProperty("key"));
// iterate增强 (Java 9+)
Stream.iterate(0, n -> n < 10, n -> n + 1) // 类似for循环
      .forEach(System.out::println);

7.2 响应式编程结合

// 与RxJava/Reactor结合示例
Flux.fromStream(Stream.generate(() -> "data"))
    .delayElements(Duration.ofMillis(100))
    .take(10)
    .subscribe(System.out::println);

7.3 未来发展方向

  1. 值类型流:对基本类型更高效的支持
  2. 模式匹配:增强流处理表达能力
  3. 更强大的收集器:提供更多内置收集操作

到此这篇关于Java Stream 流详解的文章就介绍到这了,更多相关Java Stream 流内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

到此这篇关于Java Stream 流基本概念和使用方式详解的文章就介绍到这了,更多相关Java Stream 流内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文