一.Stream流与传统方法的对比
Stream是Java 8引入的一套函数式编程风格的API,用于对集合数据进行声明式处理。
// 传统方式 vs Stream方式
public class StreamVsTraditional {public static void main(String[] args) {List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Anna");// 🟡 传统方式:如何做(Imperative)List<String> result1 = new ArrayList<>();for (String name : names) {if (name.startsWith("A")) {result1.add(name.toUpperCase());}}Collections.sort(result1);System.out.println("传统方式: " + result1);// 🟢 Stream方式:做什么(Declarative)List<String> result2 = names.stream().filter(name -> name.startsWith("A")).map(String::toUpperCase).sorted().collect(Collectors.toList());System.out.println("Stream方式: " + result2);}
}
二.各种集合创建Stream流
| 获取方式 | 方法名 | 说明 | 示例 |
|---|
| 单列集合 | default Stream<E> stream() | Collection接口中的默认方法 | list.stream() |
| 单列集合 | default Stream<E> parallelStream() | Collection接口中的默认方法(并行流) | list.parallelStream() |
| 双列集合 | 无直接方法 | 无法直接使用stream流 | 需通过keySet()、entrySet()、values()转换 |
| 数组 | public static <T> Stream<T> stream(T[] array) | Arrays工具类中的静态方法 | Arrays.stream(arr) |
| 基本类型数组 | public static IntStream stream(int[] array) | Arrays工具类中的静态方法 | Arrays.stream(intArr) |
| 一堆零散数据 | public static<T> Stream<T> of(T... values) | Stream接口中的静态方法 | Stream.of(1, 2, 3) |
| 无限流 | public static<T> Stream<T> generate(Supplier<T> s) | 生成无限流 | Stream.generate(Math::random) |
| 无限流 | public static<T> Stream<T> iterate(T seed, UnaryOperator<T> f) | 迭代无限流 | Stream.iterate(1, n -> n * 2) |
| 范围流 | public static IntStream range(int start, int end) | 生成整数范围流 | IntStream.range(1, 10) |
import java.util.*;
import java.util.stream.*;public class StreamCreation {public static void main(String[] args) {// 1. 单列集合List<String> list = Arrays.asList("A", "B", "C");Stream<String> listStream = list.stream();Stream<String> parallelListStream = list.parallelStream(); // 并行流// 2. 双列集合Map<String, Integer> map = new HashMap<>();map.put("A", 1); map.put("B", 2); map.put("C", 3);Stream<String> keyStream = map.keySet().stream();Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();Stream<Integer> valueStream = map.values().stream();// 3. 数组int[] intArray = {1, 2, 3, 4, 5};IntStream arrayStream = Arrays.stream(intArray); // 推荐Stream<int[]> arrayObjectStream = Stream.of(intArray); // 注意:这是Stream<int[]>// 4. 零散数据Stream<Integer> scatteredStream = Stream.of(1, 2, 3, 4, 5);// 5. 使用Stream.BuilderStream.Builder<String> builder = Stream.builder();builder.add("A").add("B").add("C");Stream<String> builtStream = builder.build();// 6. 使用Stream.generate() - 无限流Stream<Double> randomStream = Stream.generate(Math::random).limit(5);// 7. 使用Stream.iterate() - 无限流Stream<Integer> iterateStream = Stream.iterate(0, n -> n + 2).limit(5);// 8. 基本类型流IntStream intStream = IntStream.range(1, 6); // 1,2,3,4,5IntStream closedIntStream = IntStream.rangeClosed(1, 5); // 1,2,3,4,5LongStream longStream = LongStream.range(1, 6);DoubleStream doubleStream = DoubleStream.of(1.1, 2.2, 3.3);}
}
三.Stream流的中间方法
- 中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
- 修改Stream流中的数据,不会影响原来集合或者数组中的数据
因为Stream流中的参数是可变参数,所以可以用来存储数组中的引用数据类型
| 名称 | 语法 | 说明 | 参数说明 | 返回值 | 示例 |
|---|
| filter | Stream<T> filter(Predicate<? super T> predicate) | 过滤元素 | Predicate: 过滤条件 | 过滤后的Stream | stream.filter(s -> s.length() > 3) |
| limit | Stream<T> limit(long maxSize) | 获取前几个元素 | maxSize: 最大数量 | 截取后的Stream | stream.limit(5) |
| skip | Stream<T> skip(long n) | 跳过前几个元素 | n: 跳过数量 | 跳过后的Stream | stream.skip(2) |
| distinct | Stream<T> distinct() | 元素去重 | 无参数 | 去重后的Stream | stream.distinct() |
| concat | static <T> Stream<T> concat(Stream a, Stream b) | 合并两个流 | a, b: 要合并的流 | 合并后的Stream | Stream.concat(stream1, stream2) |
| map | Stream<R> map(Function<T, R> mapper) | 转换流中的数据类型 | Function: 转换函数 | 转换后的Stream | stream.map(String::toUpperCase) |
package Stream流;import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;public class 中间方法 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();ArrayList<String> list1 = new ArrayList<>();Collections.addAll(list, "张三", "张三四", "李四", "王二");Collections.addAll(list1, "王二-1", "王三-2", "王四-3");list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {
// 返回true,表示当前表示的数据留下
// 返回false,表示当前表示的数据不要return s.startsWith("张");}}).forEach(s -> System.out.println(s));
// limit:截取流中的前n个数据list.stream().limit(2).forEach(System.out::println);
// skip:跳过流中的前n个数据list.stream().skip(2).forEach(System.out::println);
// distinct:去除流中的重复数据list.stream().distinct().forEach(System.out::println);
// concat:合并流Stream.concat(list.stream(), list1.stream()).forEach(System.out::println);
// map:映射流中的数据list1.stream().map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s.split("-")[1]);}}).forEach(System.out::println);}
}
四.Stream流的终端方法
| 名称 | 语法 | 说明 | 参数说明 | 返回值 | 示例 |
|---|
| forEach | void forEach(Consumer action) | 遍历流中的每个元素 | Consumer: 消费操作 | void | stream.forEach(System.out::println) |
| count | long count() | 统计流中元素个数 | 无参数 | long | stream.count() |
| toArray | Object[] toArray() | 收集流中的数据到数组 | 无参数 | Object[] | stream.toArray() |
| toArray | A[] toArray(IntFunction<A[]> generator) | 收集流中的数据到指定类型数组 | generator: 数组生成器 | A[] | stream.toArray(String[]::new) |
| collect | R collect(Collector collector) | 收集流中的数据到集合 | Collector: 收集器 | R | stream.collect(Collectors.toList()) |
import java.util.*;
import java.util.stream.*;
import java.util.function.*;public class CollectExample {public static void main(String[] args) {List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Anna", "Alex");// 示例1: 收集到ListSystem.out.println("=== 收集到List ===");List<String> nameList = names.stream().filter(name -> name.startsWith("A")).collect(Collectors.toList());System.out.println("List结果: " + nameList);// 输出: List结果: [Alice, Anna, Alex]// 示例2: 收集到Set(自动去重)System.out.println("\n=== 收集到Set ===");List<String> withDuplicates = Arrays.asList("A", "B", "A", "C", "B");Set<String> nameSet = withDuplicates.stream().collect(Collectors.toSet());System.out.println("Set结果: " + nameSet);// 输出: Set结果: [A, B, C] (顺序可能不同)// 示例3: 收集到指定类型的集合System.out.println("\n=== 收集到指定类型集合 ===");TreeSet<String> treeSet = names.stream().collect(Collectors.toCollection(TreeSet::new));System.out.println("TreeSet结果: " + treeSet);// 输出: TreeSet结果: [Alex, Alice, Anna, Bob, Charlie, David] (排序后)// 示例4: 收集到MapSystem.out.println("\n=== 收集到Map ===");Map<String, Integer> nameLengthMap = names.stream().collect(Collectors.toMap(name -> name, // key映射器String::length // value映射器));System.out.println("Map结果: " + nameLengthMap);// 输出: Map结果: {Charlie=7, Bob=3, David=5, Alex=4, Alice=5, Anna=4}// 示例5: 处理重复键的Map收集System.out.println("\n=== 处理重复键的Map ===");List<Person> people = Arrays.asList(new Person("Alice", 25),new Person("Bob", 30),new Person("Alice", 28) // 重复的键);Map<String, Integer> personMap = people.stream().collect(Collectors.toMap(Person::getName,Person::getAge,(oldAge, newAge) -> newAge // 重复键处理:保留新的));System.out.println("Person Map: " + personMap);// 输出: Person Map: {Bob=30, Alice=28}// 示例6: 分组收集System.out.println("\n=== 分组收集 ===");Map<Integer, List<String>> groupByLength = names.stream().collect(Collectors.groupingBy(String::length));System.out.println("按长度分组: " + groupByLength);// 输出: 按长度分组: {3=[Bob], 4=[Anna, Alex], 5=[Alice, David], 7=[Charlie]}// 示例7: 分区收集System.out.println("\n=== 分区收集 ===");Map<Boolean, List<String>> partition = names.stream().collect(Collectors.partitioningBy(name -> name.startsWith("A")));System.out.println("按A开头分区: " + partition);// 输出: 按A开头分区: {false=[Bob, Charlie, David], true=[Alice, Anna, Alex]}// 示例8: 字符串连接System.out.println("\n=== 字符串连接 ===");String joined = names.stream().filter(name -> name.startsWith("A")).collect(Collectors.joining(", ", "[", "]"));System.out.println("连接结果: " + joined);// 输出: 连接结果: [Alice, Anna, Alex]// 示例9: 统计信息System.out.println("\n=== 统计信息 ===");IntSummaryStatistics stats = names.stream().collect(Collectors.summarizingInt(String::length));System.out.println("长度统计: " + stats);// 输出: 长度统计: IntSummaryStatistics{count=6, sum=28, min=3, average=4.666667, max=7}}
}class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() { return name; }public int getAge() { return age; }
}
五.练习
package Stream流;import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;public class 练习 {public static void main(String[] args) {/** 创建一个集合,保留年龄大于24的,以姓名,年龄为键和值进行存储到Map中* */ArrayList<String> list2 = new ArrayList<>();Collections.addAll(list2, "张三-25", "李四-23", "王二-24");Map<String, Integer> map = list2.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return Integer.parseInt(s.split("-")[1]) >= 24;}}).collect(Collectors.toMap(new Function<String, String>() {@Overridepublic String apply(String s) {return s.split("-")[0];}}, new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s.split("-")[1]);}}));System.out.println(map);/** 现有两个集合,分别存储6个男生和女生的姓名和年龄* 合并这两个集合,并以姓名为键,年龄为值进行存储到Map中*人的类包含name与age属性* */ArrayList<String> list3 = new ArrayList<>();Collections.addAll(list3, "张三1-25", "李四2-23", "王二-24", "王三3-26", "王四-28", "王五-30");Map<String, Integer> map1 = list3.stream().collect(Collectors.toMap(new Function<String, String>() {@Overridepublic String apply(String s) {return s.split("-")[0];}}, new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s.split("-")[1]);}}));System.out.println(map1);}
}
{张三=25, 王二=24}
{张三1=25, 王五=30, 李四2=23, 王三3=26, 王四=28, 王二=24}
import A学生管理系统.Student;import java.util.ArrayList;
import java.util.Collections;public class test {public static void main(String[] args){ArrayList<String> list = new ArrayList<String>();Collections.addAll(list, "a,1", "b,2", "c,3");
// Student[] arr = list.stream().map(s -> {
// String[] arr1 = s.split(",");
// return new Student(arr1[0], arr1[1], Integer.parseInt(arr1[2]), arr1[3]);
// }).toArray(Student[]::new);Student[] arr1 = list.stream().map(Student::new).toArray(Student[]::new);}
}