← 返回首页
🌊

Java Stream API详解:流式数据处理

📂 java ⏱ 5 min 927 words

Java Stream API详解:流式数据处理

概述

Stream API是Java 8引入的特性,它提供了一种高效、声明式的数据处理方式。Stream可以对集合数据进行复杂的操作,如筛选、转换、排序等。

1. 创建流

import java.util.*;
import java.util.stream.*;

public class StreamCreationExample {
    public static void main(String[] args) {
        // 1. 从集合创建流
        List<String> list = Arrays.asList("a", "b", "c", "d");
        Stream<String> stream = list.stream();
        
        // 2. 从数组创建流
        int[] array = {1, 2, 3, 4, 5};
        IntStream intStream = Arrays.stream(array);
        
        // 3. 使用Stream.of
        Stream<String> stream2 = Stream.of("x", "y", "z");
        
        // 4. 使用Stream.iterate
        Stream<Integer> iterateStream = Stream.iterate(0, n -> n + 2).limit(5);
        System.out.println("Iterate: " + iterateStream.collect(Collectors.toList()));
        
        // 5. 使用Stream.generate
        Stream<Double> generateStream = Stream.generate(Math::random).limit(3);
        System.out.println("Generate: " + generateStream.collect(Collectors.toList()));
        
        // 6. 使用IntStream.range
        IntStream rangeStream = IntStream.range(1, 6);
        System.out.println("Range: " + rangeStream.boxed().collect(Collectors.toList()));
        
        // 7. 使用字符串创建流
        IntStream charStream = "Hello".chars();
        charStream.forEach(c -> System.out.print((char) c + " "));
        System.out.println();
    }
}

2. 中间操作(转换)

import java.util.*;
import java.util.stream.*;

public class IntermediateOperationsExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        
        // filter:筛选
        List<Integer> evens = numbers.stream()
            .filter(n -> n % 2 == 0)
            .collect(Collectors.toList());
        System.out.println("偶数: " + evens);
        
        // map:映射转换
        List<Integer> doubled = numbers.stream()
            .map(n -> n * 2)
            .collect(Collectors.toList());
        System.out.println("双倍: " + doubled);
        
        // flatMap:扁平化映射
        List<List<Integer>> nested = Arrays.asList(
            Arrays.asList(1, 2),
            Arrays.asList(3, 4),
            Arrays.asList(5, 6)
        );
        List<Integer> flat = nested.stream()
            .flatMap(Collection::stream)
            .collect(Collectors.toList());
        System.out.println("扁平化: " + flat);
        
        // distinct:去重
        List<Integer> withDuplicates = Arrays.asList(1, 2, 2, 3, 3, 3);
        List<Integer> unique = withDuplicates.stream()
            .distinct()
            .collect(Collectors.toList());
        System.out.println("去重: " + unique);
        
        // sorted:排序
        List<String> names = Arrays.asList("Charlie", "Alice", "Bob", "David");
        List<String> sorted = names.stream()
            .sorted()
            .collect(Collectors.toList());
        System.out.println("排序: " + sorted);
        
        // limit:限制数量
        List<Integer> firstFive = numbers.stream()
            .limit(5)
            .collect(Collectors.toList());
        System.out.println("前5个: " + firstFive);
        
        // skip:跳过
        List<Integer> skipFirstFive = numbers.stream()
            .skip(5)
            .collect(Collectors.toList());
        System.out.println("跳过前5个: " + skipFirstFive);
        
        // peek:查看(调试用)
        List<Integer> peeked = numbers.stream()
            .filter(n -> n > 5)
            .peek(n -> System.out.println("过滤后: " + n))
            .map(n -> n * 2)
            .peek(n -> System.out.println("映射后: " + n))
            .collect(Collectors.toList());
        System.out.println("结果: " + peeked);
    }
}

3. 终止操作

import java.util.*;
import java.util.stream.*;

public class TerminalOperationsExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        
        // forEach:遍历
        System.out.print("forEach: ");
        numbers.stream().filter(n -> n > 5).forEach(n -> System.out.print(n + " "));
        System.out.println();
        
        // collect:收集
        List<Integer> evens = numbers.stream()
            .filter(n -> n % 2 == 0)
            .collect(Collectors.toList());
        System.out.println("Collect: " + evens);
        
        // reduce:归约
        int sum = numbers.stream()
            .reduce(0, Integer::sum);
        System.out.println("Sum: " + sum);
        
        int product = numbers.stream()
            .reduce(1, (a, b) -> a * b);
        System.out.println("Product: " + product);
        
        // count:计数
        long count = numbers.stream()
            .filter(n -> n > 5)
            .count();
        System.out.println("Count > 5: " + count);
        
        // min/max:最小值/最大值
        Optional<Integer> min = numbers.stream().min(Integer::compareTo);
        Optional<Integer> max = numbers.stream().max(Integer::compareTo);
        System.out.println("Min: " + min.orElse(0));
        System.out.println("Max: " + max.orElse(0));
        
        // findFirst/findAny:查找
        Optional<Integer> first = numbers.stream()
            .filter(n -> n > 5)
            .findFirst();
        System.out.println("First > 5: " + first.orElse(0));
        
        // anyMatch/allMatch/noneMatch:匹配
        boolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0);
        boolean allPositive = numbers.stream().allMatch(n -> n > 0);
        boolean noneNegative = numbers.stream().noneMatch(n -> n < 0);
        System.out.println("Any even: " + anyEven);
        System.out.println("All positive: " + allPositive);
        System.out.println("None negative: " + noneNegative);
        
        // toArray:转换为数组
        Integer[] array = numbers.stream().toArray(Integer[]::new);
        System.out.println("Array: " + Arrays.toString(array));
    }
}

4. 收集器(Collectors)

import java.util.*;
import java.util.stream.*;

public class CollectorsExample {
    static class Person {
        String name;
        int age;
        String city;
        
        Person(String name, int age, String city) {
            this.name = name;
            this.age = age;
            this.city = city;
        }
        
        @Override
        public String toString() {
            return name + "(" + age + ")";
        }
    }
    
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
            new Person("Alice", 25, "New York"),
            new Person("Bob", 30, "London"),
            new Person("Charlie", 35, "New York"),
            new Person("David", 28, "Paris"),
            new Person("Eve", 22, "London")
        );
        
        // joining:连接字符串
        String names = people.stream()
            .map(p -> p.name)
            .collect(Collectors.joining(", "));
        System.out.println("Names: " + names);
        
        // groupingBy:分组
        Map<String, List<Person>> byCity = people.stream()
            .collect(Collectors.groupingBy(p -> p.city));
        System.out.println("By city: " + byCity);
        
        // partitioningBy:分区
        Map<Boolean, List<Person>> agePartition = people.stream()
            .collect(Collectors.partitioningBy(p -> p.age >= 30));
        System.out.println("Age >= 30: " + agePartition);
        
        // counting:计数
        long count = people.stream()
            .collect(Collectors.counting());
        System.out.println("Count: " + count);
        
        // summarizingInt:汇总
        IntSummaryStatistics ageStats = people.stream()
            .collect(Collectors.summarizingInt(p -> p.age));
        System.out.println("Age stats: " + ageStats);
        
        // toMap:转换为Map
        Map<String, Integer> nameAgeMap = people.stream()
            .collect(Collectors.toMap(
                p -> p.name,
                p -> p.age
            ));
        System.out.println("Name-Age map: " + nameAgeMap);
        
        // groupingBy with downstream collector
        Map<String, Long> countByCity = people.stream()
            .collect(Collectors.groupingBy(
                p -> p.city,
                Collectors.counting()
            ));
        System.out.println("Count by city: " + countByCity);
    }
}

5. 并行流

import java.util.*;
import java.util.stream.*;

public class ParallelStreamExample {
    public static void main(String[] args) {
        // 创建并行流
        List<Integer> numbers = IntStream.rangeClosed(1, 1000).boxed().collect(Collectors.toList());
        
        // 顺序流
        long startTime = System.currentTimeMillis();
        long sum1 = numbers.stream()
            .mapToLong(Long::longValue)
            .sum();
        long endTime = System.currentTimeMillis();
        System.out.println("顺序流: " + sum1 + ", 耗时: " + (endTime - startTime) + "ms");
        
        // 并行流
        startTime = System.currentTimeMillis();
        long sum2 = numbers.parallelStream()
            .mapToLong(Long::longValue)
            .sum();
        endTime = System.currentTimeMillis();
        System.out.println("并行流: " + sum2 + ", 耗时: " + (endTime - startTime) + "ms");
        
        // 注意:并行流不适合所有场景
        // 1. 数据量小
        // 2. 操作是IO密集型
        // 3. 操作有顺序依赖
    }
}

6. 实际应用示例

数据分析

import java.util.*;
import java.util.stream.*;

public class DataAnalysisExample {
    static class Order {
        String product;
        double amount;
        String category;
        
        Order(String product, double amount, String category) {
            this.product = product;
            this.amount = amount;
            this.category = category;
        }
    }
    
    public static void main(String[] args) {
        List<Order> orders = Arrays.asList(
            new Order("iPhone", 999, "Electronics"),
            new Order("MacBook", 1999, "Electronics"),
            new Order("Book", 20, "Books"),
            new Order("T-Shirt", 30, "Clothing"),
            new Order("Headphones", 150, "Electronics"),
            new Order("Novel", 15, "Books"),
            new Order("Jeans", 50, "Clothing")
        );
        
        // 按类别统计销售额
        Map<String, Double> salesByCategory = orders.stream()
            .collect(Collectors.groupingBy(
                o -> o.category,
                Collectors.summingDouble(o -> o.amount)
            ));
        System.out.println("Sales by category: " + salesByCategory);
        
        // 找出最贵的产品
        Order mostExpensive = orders.stream()
            .max(Comparator.comparingDouble(o -> o.amount))
            .orElse(null);
        System.out.println("Most expensive: " + mostExpensive.product);
        
        // 筛选电子产品
        List<String> electronics = orders.stream()
            .filter(o -> o.category.equals("Electronics"))
            .map(o -> o.product)
            .collect(Collectors.toList());
        System.out.println("Electronics: " + electronics);
        
        // 计算平均订单金额
        double average = orders.stream()
            .mapToDouble(o -> o.amount)
            .average()
            .orElse(0);
        System.out.println("Average order: " + String.format("%.2f", average));
    }
}

7. 最佳实践

  1. 使用方法引用:当Lambda只是调用现有方法时
  2. 避免副作用:流操作应该是无副作用的
  3. 选择合适的流:顺序流还是并行流
  4. 使用收集器:利用Collectors提供的丰富功能
  5. 保持链式调用简洁:避免过长的链式调用

总结

Stream API是Java 8引入的重要特性,它提供了高效、声明式的数据处理方式。掌握Stream API的使用,包括创建流、中间操作、终止操作和收集器,是现代Java编程的重要技能。