Stream流

目录

Stream流的作用

Stream流的使用步骤:

获取Stream流: 

单列集合

双列集合

数组

一堆零散的数组

Stream流的中间方法

filter过滤

limit获取前几个元素

 skip跳过前几个元素 

distinct 元素去重,依赖(hashcode和equal法) 

concat(Stream a, Stream b)     合并a和b两个流为一个流

map转换流中的数据类型 

Stream流的终结方法

forEach遍历 

count()统计 

 toArray() 收集流中的数据,放到数组中

 collect(Collector collector)                收集流中的数据,放到集合中(list,set,map) 

练习 

一、定义一个集合,并添加一些数 1,2,3,4,5,6,7,8,9,10过滤奇数,只留下偶数。并将结果保存起来

 二、创建一个ArrayList集合,并添加以下字符串,字符串中前面是姓名,后面是年龄"zhangsan,23""lisi,24""wangwu,25”保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值

三、现在有两个ArrayList集合第一个集合中:存储6名男演员的名字和年龄。第二个集合中:存储6名女演员的名字和年龄。姓名和年龄中间用逗号隔开。比如:张三,23要求完成如下的操作:1,男演员只要名字为2个字的前两人2,女演员只要姓赵的,并且不要第一个3,把过滤后的男演员姓名和女演员姓名合并到一起4,将上一步的演员信息封装成Actor对象,5,将所有的演员对象都保存到List集合中备注:演员类Actor,属性有:name,age


在Java中,Stream流是一种用于处理数据的抽象概念。它可以用来操作集合、数组、输入/输出资源等,提供了一种统一的处理方式。

在Java 8中引入了Stream API,它可以让开发者更方便地处理数据集合,以函数式编程的方式进行操作。Stream流支持多种操作,可以分为两类:中间操作和终端操作。

中间操作是指在数据流中进行处理,可以用来过滤、映射、排序等操作。常用的中间操作有:filter、map、sorted等。

终端操作是指对数据流进行最终的处理,可以用来收集、计数、求和等操作。常用的终端操作有:collect、count、sum等。

Stream流的作用

结合了Lambda表达式,简化集合、数组的操作

Stream流的使用步骤:

 先得到一条Stream流(流水线),并把数据放上去,再利用Stream流中的API进行各种操作 

获取Stream流: 

单列集合

方法名: 

default Stream<E>stream() 

collection中的默认方法

 

完整代码在这里

public class StreamDemo {
    public static void main(String[] args) {
        ArrayList<String>list=new ArrayList<>();
        Collections.addAll(list,"a","b","c","d","e");
        //获取到一条流水线,并把集合中的数据放到流水线上
        Stream<String> stream1 = list.stream();
        //使用终结方法打印一下流水线上的所有数据
        stream1.forEach(s -> System.out.println(s));

    }
}

双列集合

无法直接使用Stream流

可以先用keyset方法获取所有的键,再获取Stream流

也可以使用entryset方法获取所有的键值对对象,在获取Stream流

数组

方法名: 

public static <T> Stream<T> stream(T[] array)  

Arrays工具类中的静态方法 

完整代码在这里 

public class StreamDemo3 {
    public static void main(String[] args) {
        int[]arr={1,2,3,4,5};
        Arrays.stream(arr).forEach(s-> System.out.println(s));
    }
}

一堆零散的数组

方法名: 

public static<T> stream<T> of(T... values) 

Stream接口中的静态方法

 

注意: 

Stream接口中静态方法of的细节:方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组但是数组必须是引用数类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到stream当中。

基本数据类型:

引用数据类型: 

Stream流的中间方法

Stream<T>filter(Predicate<? super T> predicate)         过滤

Stream<T>limit(long maxSize)                                      获取前几个元素   

Stream<T> skip(long n)                                                跳过前几个元素

Stream<T> distinct()                                                     元素去重,依赖(hashcode和equal法)

static <T>Stream<T>concat(Stream a, Stream b)       合并a和b两个流为一个流

Stream<R> map(Function<T ,R> mapper)                  转换流中的数据类型

注意: 

中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程

修改Stream流中的数据,不会影响原来集合或者数组中的数据

filter过滤

练习: 把“张”开头的留下,其余数据过滤不要

上面是拿匿名内部类写的,可以用Lambda表达式简化一下👇


 

如果我在使用Stream1的话就会报错

表示在对流进行操作时,流已经被关闭👆,这就是注意的第一点

中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程👇

注意的第二点就字面的意思 

 修改Stream流中的数据,不会影响原来集合或者数组中的数据👇

limit获取前几个元素

练习:获取前三个元素 

 skip跳过前几个元素 

例子: 跳过前三个元素

distinct 元素去重,依赖(hashcode和equal法) 

例子:

 

重复的张三被去除了,我们来看看底层

hashset存储自定义元素的时候要重写hashcode和equals方法 

concat(Stream a, Stream b)     合并a和b两个流为一个流

map转换流中的数据类型 

例子:获取里面的年龄

 

第一个类型:流中原本的数据类型
第二个类型:要转成之后的类型

apply的形参s:依次表示流里面的每一个数据
返回值:表示转换之后的数据

 用Lambda表达式表示👇

Stream流的终结方法

void forEach(Consumer action)                  遍历
long count()                                                 统计
toArray()                                                      收集流中的数据,放到数组中
collect(Collector collector)                           收集流中的数据,放到集合中 

forEach遍历 

Consumer的泛型:表示流中数据的类型

accept方法的形参s:依次表示流里面的每一个数据

方法体:对每一个数据的处理操作(打印) 

用lambda表达式写

 

count()统计 

 

 toArray() 收集流中的数据,放到数组中

如果要收集指定类型的👇

 IntFunction的泛型:具体类型的数组

apply的形参:流中数据的个数,要跟数组的长度保持一致

apply的返回值:具体类型的数组

方法体:就是创建数组

toArray方法的参数的作用:负贵创建一个指定类型的数组

toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中

toArray方法的返回值:是一个装着流里面所有数据的数组

 

用lambda表达式👇

 

 collect(Collector collector)                收集流中的数据,放到集合中(list,set,map) 

例子:收集到list集合中,把所有男性收集起来 

 

 例子:收集到set集合中,把所有男性收集起来 

拿收集到list集合跟set集合中与什么区别呢?

 

set集合会去除重复元素

 例子:收集Map集合当中。把所有的男性收集起来。键:姓名, 值:年龄。

 toMap :参数一表示键的生成规则

             参数二表示值的生成规则

参数一:

        Function   泛型一:表示流中每一个数据的类型
                         泛型二:表示Map集合中键的数据类型
        方法apply形参:依次表示流里面的每一个数据

        方法体;生成键的代码

        返回值:已经生成的键

参数二:

        Function   泛型一:表示流中每一个数据的类型
                         泛型二:表示Map集合中值的数据类型
        方法apply形参:依次表示流里面的每一个数据

        方法体;生成值的代码

        返回值:已经生成的值

 注意:如果我们要收集到Map集合当中。健不能重复。否则会报错

用lambda表达式写就是👇这样子

 

练习 

一、定义一个集合,并添加一些数 1,2,3,4,5,6,7,8,9,10过滤奇数,只留下偶数。并将结果保存起来

 

完整代码在这里👇 

public class StreamTest1 {
    public static void main(String[] args) {
        //定义集合
        ArrayList<Integer>list=new ArrayList<>();
        //添加一些整数
        Collections.addAll(list,1,2,3,4,5,6,7,8,9,10);
        //过滤奇数,只留下偶数
        List<Integer> list1 = list.stream()
                .filter(s -> s % 2 == 0)
                .collect(Collectors.toList());
        System.out.println(list1);
    }
}

 二、创建一个ArrayList集合,并添加以下字符串,字符串中前面是姓名,后面是年龄
"zhangsan,23"
"lisi,24"
"wangwu,25”
保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值

 

完整代码在这里👇 

public class StreamTest2 {
    public static void main(String[] args) {
        ArrayList<String>list=new ArrayList<>();
        Collections.addAll(list,"zhangsan,23","lisi,24","wangwu,25");
        Map<String, Integer> map = list.stream()
                .filter(s -> Integer.parseInt(s.split(",")[1]) >= 24)
                .collect(Collectors.toMap(
                        s -> s.split(",")[0],
                        s -> Integer.parseInt(s.split(",")[1])));
        System.out.println(map);
    }
}

三、现在有两个ArrayList集合
第一个集合中:存储6名男演员的名字和年龄。第二个集合中:存储6名女演员的名字和年龄。姓名和年龄中间用逗号隔开。比如:张三,23要求完成如下的操作:
1,男演员只要名字为2个字的前两人
2,女演员只要姓赵的,并且不要第一个
3,把过滤后的男演员姓名和女演员姓名合并到一起
4,将上一步的演员信息封装成Actor对象,
5,将所有的演员对象都保存到List集合中
备注:演员类Actor,属性有:name,age

Actor类

public class Actor {
    private String name;
    private int age;

    public Actor() {
    }

    public Actor(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "Actor{name = " + name + ", age = " + age + "}";
    }

测试代码👇 

public class StreamTest3 {
    public static void main(String[] args) {
        //创建两个集合并添加数据
        ArrayList<String>manlist=new ArrayList<>();
        Collections.addAll(manlist,"张三,15","李四,18","王五,20","赵六,15","张无忌,16","张三丰,28");

        ArrayList<String>womenlist=new ArrayList<>();
        Collections.addAll(womenlist,"赵敏,16","周芷若,18","小龙女,20","貂蝉,15","孙尚香,16","赵欣,28");
        //男演员只要名字为2个字的前两人
        Stream<String> stream1 = manlist.stream()
                .filter(s -> s.split(",")[0].length() == 2)
                .limit(2);
        //女演员只要姓赵的,并且不要第一个
        Stream<String> stream2 = womenlist.stream()
                .filter(s -> s.split(",")[0].startsWith("赵"))
                .skip(1);
        //合并过滤后的男演员姓名与女演员姓名,演员信息封装为Actor对象
        List<Actor> list = Stream.concat(stream1, stream2).map(s ->
                        new Actor(s.split(",")[0], Integer.parseInt(s.split(",")[1])))
                .collect(Collectors.toList());
        System.out.println(list);
    }
}


 stream流就说到这啦!!!感谢各位阅读!!继续努力努力再努力

### Stream的使用方法 #### 1. 创建Stream的方式 可以通过多种方式创建 `Stream` ,以下是常见的几种方法: - **静态工厂方法** 通过 `Stream.empty()` 可以创建一个空的[^2]。另外还可以通过 `Stream.of()` 方法传入任意数量的参数来创建包含指定元素的[^3]。 ```java // 创建空 Stream<String> emptyStream = Stream.empty(); // 创建单个元素的 Stream<String> singletonStream = Stream.of("apple"); // 创建多个元素的 Stream<String> fruitStream = Stream.of("apple", "banana", "cherry"); ``` - **从集合创建** 可以利用集合类中的 `stream()` 或者 `parallelStream()` 方法将集合转换成[^4]。 ```java List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); Stream<Integer> stream = numbers.stream(); ``` --- #### 2. 常见的操作方法 ##### (1)过滤 (`filter`) 用于筛选满足条件的元素。 ```java Stream<Integer> filteredStream = numbers.stream().filter(n -> n % 2 == 0); filteredStream.forEach(System.out::println); // 输出偶数 ``` ##### (2)映射 (`map`) 将中的每个元素按照给定函数进行转换。 ```java Stream<String> upperCaseFruits = fruitStream.map(String::toUpperCase); upperCaseFruits.forEach(System.out::println); // 转换为大写字母 ``` ##### (3)去重 (`distinct`) 移除中的重复元素,对于自定义对象需重写 `equals` 和 `hashCode` 方法[^5]。 ```java Stream<String> distinctStream = Stream.of("apple", "banana", "apple").distinct(); distinctStream.forEach(System.out::println); // 输出唯一值 ``` ##### (4)匹配 (`match`) 判断是否符合条件并返回布尔值。 ```java boolean anyMatch = numbers.stream().anyMatch(n -> n > 3); // 是否存在大于3的数 System.out.println(anyMatch); boolean allMatch = numbers.stream().allMatch(n -> n > 0); // 所有数都大于0吗? System.out.println(allMatch); ``` ##### (5)收集结果 (`collect`) 将的结果收集到某种容器中,比如列表或集合。 ```java List<Integer> resultList = numbers.stream() .filter(n -> n % 2 != 0) .collect(Collectors.toList()); System.out.println(resultList); // 收集奇数到列表 ``` --- #### 3. 注意事项 尽管 `Stream` 提供了许多强大的功能,但在实际应用中有几点需要注意: - 对于小型数据集或者简单的操作场景,传统的方法可能更加高效且易于理解[^1]。 - 复杂的业务逻辑可能导致性能下降以及内存开销增加,应谨慎评估其适用性[^1]。 - 中间操作不会立即执行,只有遇到终端操作时才会触发整个水线的实际运行。 --- ### 示例综合代码 下面是一个完整的例子展示如何组合使用各种 `Stream` API 来完成特定任务——统计字符串数组中长度超过三个字符的所有单词,并按字母顺序排列后存入新的列表。 ```java import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class StreamExample { public static void main(String[] args) { String[] words = {"hello", "world", "java", "stream", "api"}; List<String> result = Arrays.stream(words) .filter(word -> word.length() > 3) // 过滤掉短词 .sorted() // 排序 .collect(Collectors.toList()); // 收集成列表 System.out.println(result); // 输出 ["hello", "javastream"] } } ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力敲代码的小火龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值