Java 8 Stream流API解析

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分类

API类型返回类型使用的类型/函数式接口函数描述符
filter中间操作(Intermediate)Stream < T >Predicate < T >T - > boolean
distinct中间操作(Intermediate,有状态 - 无界)Stream < T >
skip中间操作(Intermediate,有状态 - 有界)Stream < T >long
map中间操作(Intermediate)Stream < T >Function < T,R >T - > R
flatMap中间操作(Intermediate)Stream < T >Function < T,Stream < R > >T - > Stream < R >
sorted中间操作(Intermediate,有状态 - 无界)Stream < T >Compartor < T >(T,T) - > int
anyMatch终端操作(Terminal)booleanPredicate < T >T - > boolean
noneMatch终端操作(Terminal)booleanPredicate < T >T - > boolean
allMatch终端操作(Terminal)booleanPredicate < T >T - > boolean
findAny终端操作(Terminal)Optional < T >
findFirst终端操作(Terminal)Optional < T >
forEach终端操作(Terminal)voidConsumer < T >T - > void
collect终端操作(Terminal)RCollector <T,A,R>
reduce终端操作(Terminal,有状态 - 有界)Optional < T >BinaryOperator < T >(T,T) - > T
count终端操作(Terminal)long
  • 有状态:指该操作只有拿到所有元素之后才能继续下去
  • 无状态:指元素的处理不受之前元素的影响

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]
  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值