Java Stream API详解:流式数据处理
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. 最佳实践
- 使用方法引用:当Lambda只是调用现有方法时
- 避免副作用:流操作应该是无副作用的
- 选择合适的流:顺序流还是并行流
- 使用收集器:利用Collectors提供的丰富功能
- 保持链式调用简洁:避免过长的链式调用
总结
Stream API是Java 8引入的重要特性,它提供了高效、声明式的数据处理方式。掌握Stream API的使用,包括创建流、中间操作、终止操作和收集器,是现代Java编程的重要技能。