Java 8 Stream流API解析 拼搏现实的明天。 2022-10-07 12:54 147阅读 0赞 ## 1. Stream流简介 ## Java 8 API添加了一个新的抽象称为流Stream,可以以一种声明的方式处理数据。 Stream流使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。 **Stream流特点:** * 不是数据结构,不会保存数据,只是在原数据集上定义了一组操作 * 惰性求值,流在中间处理过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算 * Stream不保存数据,它会将操作后的数据保存到另外一个对象中 **一般使用步骤:** 1. 获取数据源,创建流 2. 中间操作(Intermediate):可以有多个,每次返回一个新的流,可进行链式操作 3. 终端操作(Terminal):只能有一个,每次执行完,这个流也就用光光了,无法执行下一个操作 ## 2. Stream流的创建方式 ## package com.jbp.controller; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.util.Arrays; import java.util.List; import java.util.Random; import java.util.regex.Pattern; import java.util.stream.Stream; /** * @ClassName: StreamAPI * @description: * @author: JiangBeiPing * @create: 2021-06-18 11:07 * @Version: 1.0 **/ public class StreamAPI { public static void main(String[] args) throws FileNotFoundException { // 1.Stream创建 // 数组 ----------------------------------------- // 数组:Arrays.stream(T array) Integer[] array = { 1, 2, 3}; Stream<Integer> integerStream1 = Arrays.stream(array); // 集合 Collection ------------------------------ List<Integer> list = Arrays.asList(array); // 集合: Collection.stream() Stream<Integer> listStream1 = list.stream(); // 集合: Collection.parallelStream() 默认使用的是 ForkJoinPool.commonPool()线程池 Stream<Integer> listStream2 = list.parallelStream(); // BufferedReader ------------------------------- BufferedReader reader = new BufferedReader(new FileReader("xxx")); Stream<String> linesStream = reader.lines(); // 字符串处理 String ------------------------------ String str = "1,2,3"; Pattern pattern = Pattern.compile(","); Stream<String> stringStream = pattern.splitAsStream(str); // Stream自带的静态方法 ---------------------------- // Stream.of() Stream<Integer> integerStream = Stream.of(1, 2, 3); // Stream.iterate() Stream<Integer> integerStream2 = Stream.iterate(1, s -> (s + 2)); // Stream.generate() Stream<Double> generate = Stream.generate(Math::random); } } ## 3. Stream流API分类 ## <table> <thead> <tr> <th>API</th> <th>类型</th> <th>返回类型</th> <th>使用的类型/函数式接口</th> <th>函数描述符</th> </tr> </thead> <tbody> <tr> <td>filter</td> <td>中间操作(Intermediate)</td> <td>Stream < T ></td> <td>Predicate < T ></td> <td>T - > boolean</td> </tr> <tr> <td>distinct</td> <td>中间操作(Intermediate,有状态 - 无界)</td> <td>Stream < T ></td> <td>—</td> <td>—</td> </tr> <tr> <td>skip</td> <td>中间操作(Intermediate,有状态 - 有界)</td> <td>Stream < T ></td> <td>long</td> <td>—</td> </tr> <tr> <td>map</td> <td>中间操作(Intermediate)</td> <td>Stream < T ></td> <td>Function < T,R ></td> <td>T - > R</td> </tr> <tr> <td>flatMap</td> <td>中间操作(Intermediate)</td> <td>Stream < T ></td> <td>Function < T,Stream < R > ></td> <td>T - > Stream < R ></td> </tr> <tr> <td>sorted</td> <td>中间操作(Intermediate,有状态 - 无界)</td> <td>Stream < T ></td> <td>Compartor < T ></td> <td>(T,T) - > int</td> </tr> <tr> <td>anyMatch</td> <td>终端操作(Terminal)</td> <td>boolean</td> <td>Predicate < T ></td> <td>T - > boolean</td> </tr> <tr> <td>noneMatch</td> <td>终端操作(Terminal)</td> <td>boolean</td> <td>Predicate < T ></td> <td>T - > boolean</td> </tr> <tr> <td>allMatch</td> <td>终端操作(Terminal)</td> <td>boolean</td> <td>Predicate < T ></td> <td>T - > boolean</td> </tr> <tr> <td>findAny</td> <td>终端操作(Terminal)</td> <td>Optional < T ></td> <td>—</td> <td>—</td> </tr> <tr> <td>findFirst</td> <td>终端操作(Terminal)</td> <td>Optional < T ></td> <td>—</td> <td>—</td> </tr> <tr> <td>forEach</td> <td>终端操作(Terminal)</td> <td>void</td> <td>Consumer < T ></td> <td>T - > void</td> </tr> <tr> <td>collect</td> <td>终端操作(Terminal)</td> <td>R</td> <td>Collector <T,A,R></td> <td>—</td> </tr> <tr> <td>reduce</td> <td>终端操作(Terminal,有状态 - 有界)</td> <td>Optional < T ></td> <td>BinaryOperator < T ></td> <td>(T,T) - > T</td> </tr> <tr> <td>count</td> <td>终端操作(Terminal)</td> <td>long</td> <td>—</td> <td>—</td> </tr> </tbody> </table> * **有状态**:指该操作只有拿到所有元素之后才能继续下去 * **无状态**:指元素的处理不受之前元素的影响 ## 4. Stream流中间操作API ## #### 4.1 filter 过滤 #### 将结果为false的元素过滤掉,为true会把当前元素会保留下来。 数值型过滤: Integer[] array = { 1, 2, 3}; Stream<Integer> integerStream1 = Arrays.stream(array); Stream<Integer> filterStream = integerStream1.filter(i -> i == 2); System.out.println(Arrays.toString(filterStream.toArray())); // [2] 对象型过滤: User user1 = new User(1,"张三"); User user2 = new User(2,"李四"); User user3 = new User(3,"王五"); ArrayList<User> users = new ArrayList<>(); users.add(user1); users.add(user2); users.add(user3); Stream<User> userStream = users.stream().filter(user -> "王五".equals(user.getName())); System.out.println(Arrays.toString(userStream.toArray())); // [StreamAPI.User(id=3, name=王五)] #### 4.2 map 映射 #### 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素 数组类型映射: Integer[] array = { 1, 2, 3}; Stream<Integer> integerStream1 = Arrays.stream(array); Stream<Integer> mapStream = integerStream1.map(i -> { i++; return i; }); System.out.println(Arrays.toString(mapStream.toArray())); // [2, 3, 4] 对象类型映射: User user1 = new User(1,"张三"); User user2 = new User(2,"李四"); User user3 = new User(3,"王五"); ArrayList<User> users = new ArrayList<>(); users.add(user1); users.add(user2); users.add(user3); Stream<User> mapStream2 = users.stream().map(user -> { String name = user.getName(); user.setName(name + "xx"); return user; }); System.out.println(Arrays.toString(mapStream2.toArray())); // [StreamAPI.User(id=1, name=张三xx), StreamAPI.User(id=2, name=李四xx), StreamAPI.User(id=3, name=王五xx)] #### 4.3 flatMap 映射 #### 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 数组类型映射: Integer[] array = { 1, 2, 3}; Integer[] array2 = { 8, 9, 10}; Stream<Integer> integerStream1 = Arrays.stream(array); // 每个元素 i 转换为一次新的stream流 并返回 Stream<Integer> mapStream = integerStream1.flatMap(i -> { Stream<Integer> stream = Arrays.stream(array2); return stream; }); System.out.println(Arrays.toString(mapStream.toArray())); // [8, 9, 10, 8, 9, 10, 8, 9, 10] 对象类型映射: User user1 = new User(1,"张三"); User user2 = new User(2,"李四"); User user3 = new User(3,"王五"); ArrayList<User> users = new ArrayList<>(); users.add(user1); users.add(user2); users.add(user3); Stream<String> stringStream = users.stream().flatMap(user -> { String name = user.getName(); String[] split = name.split(""); Stream<String> stream = Arrays.stream(split); return stream; }); System.out.println(Arrays.toString(stringStream.toArray())); // [张, 三, 李, 四, 王, 五] #### 4.4 forEach 遍历 #### Integer[] array = { 1, 2, 3}; Stream<Integer> integerStream1 = Arrays.stream(array); // 遍历array数组 ---> 1,2,3 integerStream1.forEach(i -> { System.out.println(i); }); #### 4.5 limit 截取 #### 保留前n个元素 Integer[] array = { 1, 2, 3}; Stream<Integer> integerStream1 = Arrays.stream(array); Stream<Integer> integerStream = integerStream1.limit(2); System.out.println(Arrays.toString(integerStream.toArray())); // [1, 2] #### 4.6 skip 跳过 #### 跳过前n个元素 Integer[] array = { 1, 2, 3}; Stream<Integer> integerStream1 = Arrays.stream(array); Stream<Integer> integerStream = integerStream1.skip(2); System.out.println(Arrays.toString(integerStream.toArray())); // [3] #### 4.7 distinct 去重 #### 剔除重复元素 Integer[] array = { 1, 2, 3,3}; Stream<Integer> integerStream1 = Arrays.stream(array); Stream<Integer> integerStream = integerStream1.distinct(); System.out.println(Arrays.toString(integerStream.toArray())); // [1, 2, 3] #### 4.8 sorted 排序 #### * sorted():自然排序,流中元素需实现Comparable接口 * sorted(Comparator com):定制排序,自定义Comparator排序器 Integer[] array = { 1, 2, 3,8,5}; Stream<Integer> integerStream1 = Arrays.stream(array); Stream<Integer> integerStream = integerStream1.sorted(); System.out.println(Arrays.toString(integerStream.toArray())); // [1, 2, 3, 5, 8] Integer[] array = { 1, 2, 3,8,5}; Stream<Integer> integerStream1 = Arrays.stream(array); // 倒序排列 Stream<Integer> integerStream = integerStream1.sorted((i1,i2) -> { return i2 - i1; }); System.out.println(Arrays.toString(integerStream.toArray())); // [8, 5, 3, 2, 1] #### 4.9 peek 消费 #### 如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值 User user1 = new User(1,"张三"); User user2 = new User(2,"李四"); User user3 = new User(3,"王五"); ArrayList<User> users = new ArrayList<>(); users.add(user1); users.add(user2); users.add(user3); Stream<User> peek = users.stream().peek(user -> { String name = user.getName(); user.setName(name + "v"); }); System.out.println(Arrays.toString(peek.toArray())); // [StreamAPI.User(id=1, name=张三v), StreamAPI.User(id=2, name=李四v), StreamAPI.User(id=3, name=王五v)] ## 5. Stream流终止操作API ## #### 5.1 匹配、聚合操作 #### **匹配:** * anyMatch(),只要有一个元素匹配传入的条件,就返回 true * allMatch(),只有有一个元素不匹配传入的条件,就返回 false;如果全部匹配,则返回true * noneMatch(),只要有一个元素匹配传入的条件,就返回 false;如果全部匹配,则返回 true Integer[] array = { 1, 2, 3,8,5}; Stream<Integer> integerStream1 = Arrays.stream(array); boolean anyMatch = integerStream1.anyMatch(i -> i > 6); // true System.out.println(anyMatch); boolean allMatch = integerStream1.allMatch(i -> i > 6); // false System.out.println(allMatch); boolean noneMatch = integerStream1.noneMatch(i -> i > 6); // false System.out.println(noneMatch); **聚合:** * findFirst:返回流中第一个元素 * findAny:返回流中的任意元素 * count:返回流中元素的总个数 * max:返回流中元素最大值 * min:返回流中元素最小值 Integer[] array = { 1, 2, 3,8,5}; Stream<Integer> integerStream1 = Arrays.stream(array); Optional<Integer> first = integerStream1.findFirst();// 1 Optional<Integer> any = integerStream1.findAny(); long count = integerStream1.count(); // 5 Optional<Integer> max = integerStream1.max(Integer::compareTo);// Optional[8] Optional<Integer> min = integerStream1.min(Integer::compareTo);//Optional[1] #### 5.2 归并 #### 合并流的元素并产生单个值 * Optional reduce(BinaryOperator accumulator) * T reduce(T identity, BinaryOperator accumulator) * < U > U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator combiner) identity = 默认值或初始值 BinaryOperator = 函数式接口,取两个值并产生一个新值。(注: java Function 函数中的 BinaryOperator 接口用于执行 lambda 表达式并返回一个 T 类型的返回值) Integer[] array = { 1, 2, 3,8,5}; int sum = 0; for (Integer i : array) { sum += i; } System.out.println(sum); // 19 Stream<Integer> integerStream1 = Arrays.stream(array); Integer reduce = integerStream1.reduce(0, (a, b) -> a + b); System.out.println(reduce);// 19 ## 6. Stream流收集器collect ## **集合、聚合收集:** User user1 = new User(1,"张三"); User user2 = new User(2,"李四"); User user3 = new User(3,"王五"); ArrayList<User> users = new ArrayList<>(); users.add(user1); users.add(user2); users.add(user3); // list List<Integer> list = integerStream1.collect(Collectors.toList()); // set Set<Integer> set = integerStream1.collect(Collectors.toSet()); // map key不能相同 Map<Integer, String> map = users.stream().collect(Collectors.toMap(User::getId, User::getName)); // 获取users元素个数 Long count = users.stream().collect(Collectors.counting()); // 获取users集合id最大值 Optional<Integer> max = users.stream().map(User::getId).collect(Collectors.maxBy(Integer::compare)); // 获取users集合id最小值 Optional<Integer> min = users.stream().map(User::getId).collect(Collectors.minBy(Integer::compare)); // 获取users集合所有id的和 Integer id = users.stream().collect(Collectors.summingInt(User::getId)); // 获取users集合所有id的平均值 Double average = users.stream().collect(Collectors.averagingDouble(User::getId)); **字符串拼接:** String s = users.stream().map(User::getName).collect(Collectors.joining(",", "{", "}"));// {张三,李四,王五} **分组、分区和归并:** User user1 = new User(1,"张三"); User user2 = new User(2,"李四"); User user3 = new User(2,"王五"); ArrayList<User> users = new ArrayList<>(); users.add(user1); users.add(user2); users.add(user3); // 按照id分组 Map<Integer, List<User>> group = users.stream().collect(Collectors.groupingBy(User::getId));// {1=[StreamAPI.User(id=1, name=张三)], 2=[StreamAPI.User(id=2, name=李四), StreamAPI.User(id=2, name=王五)]} // 多重分组:先按照名字分,再按照id分 Map<String, Map<Integer, List<User>>> map = users.stream().collect(Collectors.groupingBy(User::getName, Collectors.groupingBy(User::getId)));//{李四={2=[StreamAPI.User(id=2, name=李四)]}, 张三={1=[StreamAPI.User(id=1, name=张三)]}, 王五={2=[StreamAPI.User(id=2, name=王五)]}} // 按照id分区:大于1为一部分,小于等于1为一部分 Map<Boolean, List<User>> collect = users.stream().collect(Collectors.partitioningBy(user -> user.getId() > 1));//{false=[StreamAPI.User(id=1, name=张三)], true=[StreamAPI.User(id=2, name=李四), StreamAPI.User(id=2, name=王五)]} // 归并:计算users集合的id之和 Optional<Integer> sum = users.stream().map(User::getId).collect(Collectors.reducing(Integer::sum));//Optional[5]
相关 Java 8 Stream API 实例解析 Java 8的Stream API是Java集合框架的一个重大升级,它提供了一种新的方式来处理数据流。 以下是一些Java 8 Stream API实例的解析: 1. ** ゞ 浴缸里的玫瑰/ 2024年09月13日 03:21/ 0 赞/ 16 阅读
相关 Java 8 Stream API 操作案例解析 Java 8的Stream API提供了一种新的、并行的处理集合元素的方式。以下是一些常见的Stream操作案例: 1. **过滤**:根据某种条件筛选元素。 ```java 墨蓝/ 2024年09月11日 07:51/ 0 赞/ 17 阅读
相关 Java8 Stream 流API总结 Stream API 1.集合处理数据的弊端 当我们在需要对集合中的元素进行操作的时候,除了必需的添加,删除,获取外,最典型的操作就是集合遍历, pa 我就是我/ 2023年10月10日 12:58/ 0 赞/ 24 阅读
相关 Java 8 Stream流API解析 1. Stream流简介 Java 8 API添加了一个新的抽象称为流Stream,可以以一种声明的方式处理数据。 Stream流使用一种类似用 SQL 语句从数据库查 拼搏现实的明天。/ 2022年10月07日 12:54/ 0 赞/ 148 阅读
相关 Java 8-Stream API-创建流 使用stream方法从集合生成流 由值创建流 可以使用静态方法Stream.of,通过显示值创建一个流。它可以接受任意数量的参数。 Stream<Str ╰半夏微凉°/ 2022年05月21日 06:56/ 0 赞/ 184 阅读
相关 Java 8-Stream API-数值流 int colories=menu.stream() .map(Dish::getCalories) .reduce(0 傷城~/ 2022年05月21日 06:56/ 0 赞/ 157 阅读
相关 Java 8-Stream API-流操作 java.util.stream.Stream中的Stream接口定义了许多操作。它们可以分为两大类。 filter、map和limit可以连成一条流水线 col 约定不等于承诺〃/ 2022年05月21日 06:55/ 0 赞/ 205 阅读
相关 java8流(Stream API)概述 流(Stream)是java8引入的重磅api,使用它可以替换大部分集合操作,重要的是,流相对集合来说更简洁易读、更灵活,性能也更好。 集合操作的痛点 动不动就要遍历 墨蓝/ 2022年05月12日 11:04/ 0 赞/ 186 阅读
相关 Stream流详细解析 【Stream流】 主要内容 常用函数式接口 Stream流 教学目标 能够使用Function<T, R>函数式接口 能够使用Pr ╰+攻爆jí腚メ/ 2022年02月23日 04:35/ 0 赞/ 257 阅读
还没有评论,来说两句吧...