Java Stream流与使用操作指南
作者:不做光头强
Stream不是数据结构,而是一种高级的数据处理工具,允许你以声明式的方式处理数据集合,类似于SQL语句操作数据库,本文给大家介绍Java Stream流与使用操作指南,感兴趣的朋友一起看看吧
一、什么是stream流
Java 8引入的Stream API是处理集合数据的一种全新方式,它代表了对数据元素序列进行函数式操作的抽象。Stream不是数据结构,而是一种高级的数据处理工具,允许你以声明式的方式处理数据集合,类似于SQL语句操作数据库。
Stream的核心特点:
- 声明式编程:只需说明"做什么"而非"如何做",代码更简洁易读
- 函数式风格:与Lambda表达式完美结合,操作更灵活
- 管道操作:多个操作可以连接起来形成数据处理流水线
- 内部迭代:不同于集合的外部迭代(使用for-each),Stream在内部处理迭代过程
- 延迟执行:中间操作不会立即执行,只有遇到终结操作才会触发计算
- 不可复用:一个Stream只能被消费一次
二、创建stream流
1.单列集合创建stream流
// 1.单列集合创建stream流 List<String> list = Arrays.asList("张三", "李四", "王五", "赵六", "钱七"); list.stream().forEach(e -> System.out.println("e = " + e));
2.双列集合创建stream流
// 2.双列集合创建stream流 HashMap<String, Integer> map = new HashMap<>(); map.put("aaa", 111); map.put("bbb", 222); map.put("ccc", 333); map.put("ddd", 444); map.put("eee", 555); // 遍历所有的key map.keySet().stream().forEach(e -> System.out.println("e = " + e)); // 遍历所有的键值对 map.entrySet().stream().forEach(e -> System.out.println("e = " + e)); // 遍历所有的值 map.values().stream().forEach(e -> System.out.println("e = " + e));
3.数组创建stream流
// 3.数组创建stream流 int[] array1 = {1, 2, 3}; String[] array2 = {"a", "b", "c"}; Arrays.stream(array1).forEach(e -> System.out.println("e = " + e));
4.零散数据创建stream流
// 4.零散数据创建stream流 Stream.of(1, 2, 3, 4, 5).forEach(e -> System.out.println("e = " + e)); // stream接口中静态方法of的细节 // 方法的形参是一个可变参数,可以传递一堆零散的数据(同一类型),也可以传递数组 // 传递的数组必须是引用数据类型的,如果传递基本数据类型,会把数组当做一个元素 Stream.of(array1).forEach(e -> System.out.println("e = " + e)); // 结果[I@4dd8dc3 Stream.of(array2).forEach(e -> System.out.println("e = " + e));
5.创建并行流
// 5.创建并行流 list.parallelStream().forEach(e -> System.out.println("e = " + e)); // 顺序会打乱
6.创建无限流
// 6.创建无限流 Stream.generate(Math::random).limit(10).forEach(e -> System.out.println("e = " + e)); Stream.iterate(0, n -> n + 2).limit(10).forEach(e -> System.out.println("e = " + e));
三、流的中间操作
中间操作返回一个新的Stream,可以链式调用多个中间操作。
注意点:
一、中间方法,返回新的stream流,原来的stream流只能使用一次,建议使用链式编程
二、修改stream流中的数据,不会影响原来集合或数组中的数据
1.过滤操作
// 1.过滤操作 // filter: 过滤元素 List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 100, 100); List<Integer> list2 = Arrays.asList(100, 200, 30, 40, 50, 60, 70, 80, 90, 100, 200, 1000, 100000); list1.stream().filter(n -> n % 2 == 0).forEach(e -> System.out.println("e = " + e)); // distinct: 去重 // 依赖于hashCode和equals方法,底层使用的是hashset list1.stream().distinct().forEach(e -> System.out.println("e = " + e));
2.映射操作
// 2.映射操作 List<String> list3 = Arrays.asList("张三-13", "李四-14", "王五-15", "赵六-16", "钱七-17"); list3.stream().map(s -> Integer.valueOf(s.split("-")[1])).forEach(e -> System.out.println("map = " + e)); List<List<Integer>> numberLists = Arrays.asList( Arrays.asList(1, 2), Arrays.asList(3, 4, 5), Arrays.asList(6) ); // flatMap 可以处理嵌套集合或需要"展平"数据结构的情况,将每个元素转换为一个流(Stream),然后把所有流合并成一个流 // 当你需要处理嵌套结构或一对多转换时,使用flatMap;当只是简单的一对一转换时,使用map numberLists.stream().map(s -> s.stream()).forEach(stream -> System.out.println("stream = " + stream)); // 输出3个流对象的地址值 java.util.stream.ReferencePipeline$Head@3b9a45b3 numberLists.stream().flatMap(s -> s.stream()).forEach(s -> System.out.println("flatMap = " + s)); // 输出 1 2 3 4 5 6
3.截取/跳过操作
// 3.截取/跳过操作 // limit: 限制元素数量 list1.stream().limit(4).forEach(e -> System.out.println("e = " + e)); // skip: 跳过前N个元素 list1.stream().skip(5).forEach(e -> System.out.println("e = " + e));
4.排序操作
// 4.排序操作 // sorted: 排序 Stream.of("b", "a", "c").sorted().forEach(s -> System.out.println("sorted = " + s)); // 自定义排序 Stream.of("aaa", "bb", "c").sorted(Comparator.comparingInt(String::length)).forEach(s -> System.out.println("customSorted = " + s)); Stream.of("aaa", "bb", "c", null).sorted((a, b) -> { if (a == null && b == null) return 0; if (a == null) return 1; if (b == null) return -1; return b.compareTo(a); }).forEach(s -> System.out.println("customSorted2 = " + s));
5.合并操作
// 5.合并操作 Stream.concat(list1.stream(), list2.stream()).forEach(e -> System.out.println("e = " + e));
6.其他中间操作
此API可以很好的证明流“延迟执行”的特点,当无forEach()时,不会打印出中间元素,当有终结操作时,流才会执行。
// 6.其他中间操作 // peek: 查看流中元素,调试用 Stream.of("one", "two", "three") .peek(e -> System.out.println("Original: " + e)) .map(String::toUpperCase) .peek(e -> System.out.println("Mapped: " + e)) .forEach(e-> System.out.println("peek = " + e));
四、 流的终结操作
终结操作会触发流的处理并返回结果
1.遍历操作
// 1.遍历操作 List<String> list = Arrays.asList("张三-13", "李四-14", "王五-15", "赵六-16", "钱七-17", "张三-23"); // forEach: 遍历元素 list.stream().forEach(e -> System.out.println("e = " + e)); // forEachOrdered: 保证顺序的遍历 list.parallelStream().forEachOrdered(e -> System.out.println("e = " + e));
2.收集操作
// 2.收集操作 // 收集到list集合 List<String> nameList = list.stream().map(e -> e.split("-")[0]).collect(Collectors.toList()); System.out.println("nameList = " + nameList); // 收集到set集合,会去重 Set<String> nameSet = list.stream().map(e -> e.split("-")[0]).collect(Collectors.toSet()); System.out.println("nameSet = " + nameSet); // 收集到map集合 // 注意收集到map,键不能重复,重复会报 java.lang.IllegalStateException: Duplicate key 张三 (attempted merging values 13 and 23) // Map<String, Integer> map1 = list.stream().collect(Collectors.toMap(s -> s.split("-")[0], s -> Integer.valueOf(s.split("-")[1]))); // System.out.println("map1 = " + map1); // 解决方案,传递第三个参数,如果键重复,使用前面的那么,以下的(a, b)代表的value,a为已经存在的,b为新加的 Map<String, Integer> map2 = list.stream().collect(Collectors.toMap(s -> s.split("-")[0], s -> Integer.valueOf(s.split("-")[1]), (a, b) -> a)); System.out.println("map2 = " + map2); // 收集为字符串 String nameStr = list.stream().map(e -> e.split("-")[0]).collect(Collectors.joining("-")); System.out.println("nameStr = " + nameStr); // 张三-李四-王五-赵六-钱七-张三
3.聚合操作
// 3.聚合操作 // count: 计数 long count = Stream.of("a", "b", "c").count(); System.out.println("count = " + count); // 3 // max/min: 最大最小值 Optional<String> max = Stream.of("a", "bb", "ccc").max(Comparator.comparingInt(String::length)); System.out.println("max = " + max.get()); // reduce: 归约操作 // 无初始值,当流为空,则为Optional.empty() Optional<Integer> sum = Stream.of(1, 2, 3).reduce(Integer::sum); System.out.println("sum = " + sum.get()); // ccc // 初始值为0,流为空则返回0,执行的操作为 0+1+2+3 = 6 Integer sumWithIdentity = Stream.of(1, 2, 3).reduce(0, Integer::sum); System.out.println("sumWithIdentity = " + sumWithIdentity); // 6
4.匹配操作
// 4.匹配操作 // anyMatch: 任意元素匹配(任意一个满足条件则为true) boolean hasEven = Stream.of(1, 2, 3).anyMatch(n -> n % 2 == 0); System.out.println("hasEven = " + hasEven); // true // allMatch: 所有元素匹配(所有元素都要满足条件) boolean allEven = Stream.of(2, 4, 6).allMatch(n -> n % 2 == 0); System.out.println("allEven = " + allEven); // true // noneMatch: 没有元素匹配(所有元素都不能满足条件) boolean noneNegative = Stream.of(1, 2, 3).noneMatch(n -> n < 0); System.out.println("noneNegative = " + noneNegative); // true
5.查找操作
// 5.查找操作 // findFirst: 查找第一个元素 Optional<String> first = Stream.of("a", "b", "c").findFirst(); System.out.println("first = " + first.get()); // a // findAny: 查找任意元素(在并行流中效率更高) Optional<String> any = Stream.of("a", "b", "c").parallel().findAny(); System.out.println("any = " + any.get()); // b
6.数组转换
// 6.数组转换 // toArray: 转换为数组 String[] array = Stream.of("a", "b", "c").toArray(String[]::new); System.out.println("array = " + Arrays.toString(array)); // [a, b, c]
7.分组
// 7.分组 // 可将一个对象集合按照里面的某个字段转换为map,如key为ID,value为对象 List<String> words = Arrays.asList("apple", "banana", "orange", "pear", "grape"); Map<Integer, List<String>> groupedByLength = words.stream() .collect(Collectors.groupingBy(String::length)); System.out.println(groupedByLength);
到此这篇关于Java Stream流与使用操作指南的文章就介绍到这了,更多相关Java Stream流内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!