【JAVA入门】Day34 - Stream流

【JAVA入门】Day34 - Stream流


文章目录

  • [【JAVA入门】Day34 - Stream流](#【JAVA入门】Day34 - Stream流)
    • [一、Stream 流的作用和使用步骤](#一、Stream 流的作用和使用步骤)
    • 1.Stream流的创建,数据的添加
    • [2. Stream流的中间方法](#2. Stream流的中间方法)
    • [3. Stream流的终结方法](#3. Stream流的终结方法)

Stream 流有什么作用?我们看一个例子:

【练习】需求:按照下面的要求完成集合的创建和遍历。

①把所有以"张"开头的元素存储到新集合中。

②把"张"开头的,长度为3的元素再存储到新集合中。

③遍历打印最终结果。

以往我们是这样写的。

java 复制代码
package Stream;

import java.util.ArrayList;

public class StreamDemo {
    public static void main(String[] args) {
        /*①把所有以"张"开头的元素存储到新集合中。
②把"张"开头的,长度为3的元素再存储到新集合中。
③遍历打印最终结果。*/
        ArrayList<String> list1 = new ArrayList<>();
        list1.add("张无忌");
        list1.add("周芷若");
        list1.add("赵敏");
        list1.add("张强");
        list1.add("张三丰");

        //①把所有以"张"开头的元素存储到新集合中。
        ArrayList<String> list2 = new ArrayList<>();
        for (String name : list1) {
            if(name.startsWith("张")){
                list2.add(name);
            }
        }

        System.out.println(list2);

        //②把"张"开头的,长度为3的元素再存储到新集合中。
        ArrayList<String> list3 = new ArrayList<>();
        for (String name : list2) {
            if(name.length() == 3){
                list3.add(name);
            }
        }

        System.out.println(list3);

        //③遍历打印最终结果。
        for (String s : list3) {
            System.out.println(s);
        }
    }
}

使用 Stream 流我们可以这样写。

java 复制代码
package Stream;

import java.util.ArrayList;

public class StreamDemo1 {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();
        list1.add("张无忌");
        list1.add("周芷若");
        list1.add("赵敏");
        list1.add("张强");
        list1.add("张三丰");

        list1.stream().filter(name->name.startsWith("张")).filter(name -> name.length() == 3).forEach(name -> System.out.println(name));
    }
}

一行代码就完成了所有任务。可以说是大大简化了代码。

一、Stream 流的作用和使用步骤

Stream 本身是结合了 Lambda 表达式,简化了集合、数组的各种操作。

Stream的使用理论步骤是:

①先得到一条 Stream 流(流水线),并把数据放上去。

②利用 Stream 流中的 API 进行各种操作,包括:过滤、转换、统计、打印 等等。

Stream 流中的方法分为两种:中间方法(过滤、转换)、终结方法(统计、打印)。中间方法就是调用完毕之后还可以调用其他方法;终结方法就是流的最后一步,调用完毕之后,不能再调用其他方法。

下面我们根据步骤分别介绍相关方法。

1.Stream流的创建,数据的添加

1.单列集合创建流水线:

java 复制代码
package Stream;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.stream.Stream;

public class StreamDemo2 {
    public static void main(String[] args) {
        //1.单列集合获取Stream流
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a","b","c","d","e");

        /*//获取一条流水线,把集合中的数据放到流水线上
        Stream<String> stream1 = list.stream();
        //使用终结方法打印流水线上所有数据
        stream1.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });*/

        //利用Lambda表达式简化
        list.stream().forEach(s -> System.out.println(s));
    }
}

2.双列集合间接使用流水线:

java 复制代码
package Stream;

import java.util.HashMap;

public class StreamDemo3 {
    public static void main(String[] args) {
        //1.创建一个双列集合
        HashMap<String,Integer> hm = new HashMap<>();

        //2.添加数据
        hm.put("aaa",111);
        hm.put("bbb",222);
        hm.put("ccc",333);
        hm.put("ddd",444);

        //3.获取stream流,放入键
        hm.keySet().stream().forEach(s -> System.out.println(s));

        //4.第二种获取stream流的办法,放入键值对
        hm.entrySet().stream().forEach(s -> System.out.println(s));
    }
}

3.数组使用流水线:

java 复制代码
package Stream;

import java.util.Arrays;

public class StreamDemo4 {
    public static void main(String[] args) {
        //1.创建数组
        int[] arr = {1,2,3,4,5,6,7,8,9,10};
        String[] arr2 = {"a","b","c","d","e"};
        //2.创建stream流
        Arrays.stream(arr).forEach(s -> System.out.println(s));
        Arrays.stream(arr2).forEach(s -> System.out.println(s));
    }
}

4.大量零散数据使用流水线:

java 复制代码
package Stream;

import java.util.stream.Stream;

public class StreamDemo5 {
    public static void main(String[] args) {
        //public static<T> Stream<T> of(T...values)     Stream接口中的静态方法
        Stream.of(1,2,3,4,5).forEach(s -> System.out.println(s));

        Stream.of("a","b","c","d","e").forEach(s -> System.out.println(s));
    }
}

要注意:

java 复制代码
//数组可以作为Stream.of()的参数,但必须是引用类型的,如果传递基本数据类型的数组,会把整个数组当成一个元素放入Stream
Stream.of(arr2).forEach(s -> System.out.println(s));

2. Stream流的中间方法

Stream 流的中间方法如下。

其中要注意 distinct() 方法去重,依赖于那两个常用方法,如果要去重的是自定义数据类型,务必重写这两个方法。

还要注意:中间方法会返回新的 Stream 流,而原来的 Stream 流只能用一次(调一次方法就关闭了),所以建议使用链式编程节省代码量。

还要注意:修改 Stream 流中的数据是不会影响原来集合或者数组中的数据的。

部分方法使用例代码如下。

java 复制代码
package Stream;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;

public class StreamDemo6 {
    public static void main(String[] args) {
        /*
            filter  过滤
            limit   获取前几个元素
            skip    跳过前几个元素
         */

        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张无忌","周芷若","赵敏","张三丰","张翠山","张良","王二麻子","谢广坤");

        //filter 过滤 把"张"开头的留下,其他不要
        /*list.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                //如果返回值为true,表示当前数据留下
                //如果返回值为false,表示当前数据舍弃不要
                return s.startsWith("张");
            }
        }).forEach(s -> System.out.println(s));*/

        list.stream().filter(s -> s.startsWith("张")).forEach(s -> System.out.println(s));
        //原集合没有发生变化
        System.out.println(list);   //[张无忌, 周芷若, 赵敏, 张三丰, 张翠山, 张良, 王二麻子, 谢广坤]
		
    }
}
java 复制代码
package Stream;

import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Stream;

public class StreamDemo7 {
    public static void main(String[] args) {
        /*
            distinct 元素去重,依赖hashCode和equals方法
            concat   合并a和b两个流为一个流
         */

        ArrayList<String> list1 = new ArrayList<>();
        Collections.addAll(list1, "张无忌","张无忌","张无忌","张强","张三丰","张翠山","张良","王二麻子","谢广坤");

        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"周芷若","赵敏");

        //元素去重
        list1.stream().distinct().forEach(s -> System.out.println(s));

        //流的合并
        Stream.concat(list1.stream(),list2.stream()).forEach(s -> System.out.println(s));
    }
}
java 复制代码
package Stream;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;

public class StreamDemo8 {
    public static void main(String[] args) {
        /*
            map     转换流中的数据类型
         */

        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-100","张翠山-40","张良-35","王二麻子-37","谢广坤-41");

        //获取里面的年龄并进行打印
        //第一个类型:表示流中原本的数据类型
        //第二个类型:表示要转换之后的数据类型
        //apply的形参s:表示流里面的每一个数据
        //返回值:表示转换之后的数据类型
        list.stream().map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                String[] arr = s.split("-");
                String ageString = arr[1];                  //arr[0]是名字,arr[1]是年龄
                int age = Integer.parseInt(ageString);
                return age;
            }
        }).forEach(s -> System.out.println(s));

        //简写为Lambda表达式
        list.stream().map(s -> Integer.parseInt(s.split("-")[1])).forEach(s -> System.out.println(s));
    }
}

3. Stream流的终结方法

Stream 的终结方法使用完毕后,Stream 流就关闭了,所以要写在最后。

以下演示了如何遍历、统计一个流中的数据,并将流中的数据收集到一个数组当中,使用的方法是 toArray(),其中的代码都可以用 Lambda 表达式来改写。

java 复制代码
package Stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.IntFunction;

public class StreamDemo9 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌","张无忌","张无忌","张强","张三丰","张翠山","张良","王二麻子","谢广坤");

        //void forEach(Consumer action) 遍历
        //重写的方法体是对每一个数据的操作
/*
        list.stream().forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
*/

        list.stream().forEach(s -> System.out.println(s));

        //long count() 统计
        System.out.println(list.stream().count());

        //toArray() 收集流中数据,放入数组中
        Object[] arr1 = list.stream().toArray();                //空参是转化为Object类型,放入Object数组中
        System.out.println(Arrays.toString(arr1));              //调用Arrays.toString方法转化为字符串打印

        //IntFunction的泛型是:具体类型的数组 <? extends Object[]>
        //apply方法的形参:流中数据的个数,要和数组长度保持一致
        //apply的返回值:返回具体的类型的数组
        //apply的方法体:创建数组,流中有多少数据,数组长度就填多少
        //toArray方法整体这个实现类参数的作用是:创建一个指定类型的数组
        //toArray方法的底层会依次得到流中每一个数据,并把数据放入数组中
        //toArray方法的返回值是一个装着流里所有数据的数组
/*        String[] arr = list.stream().toArray(new IntFunction<String[]>() {
            @Override
            public String[] apply(int value) {
                return new String[value];
            }
        });
*/

        String[] arr2 = list.stream().toArray(value -> new String[value]);
        System.out.println(Arrays.toString(arr2));
    }
}

以下的代码将演示如何使用 collect() 方法将流中的数据收集到各种集合(List、Set、Map)当中。

java 复制代码
package Stream;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class StreamDemo10 {
    public static void main(String[] args) {
        /*
                collect(Collector collector)        收集流中数据,放入集合中(List Set Map)
         */

        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌-男-15","周芷若-女-14","赵敏-女-13","张强-男-20","张三丰-男-100","张翠山-女-40","张良-男-35","王二麻子-男-37","谢广坤-男-41");

        //1.收集到List集合中
        //需求:收集所有男性

        List<String> newList = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toList());
        System.out.println(newList);

        //2.收集到Set集合中
        //需求:收集所有男性
        //收集到Set中时,数据会自动去重,且无序
        Set<String> newSet = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toSet());
        System.out.println(newSet);

        //3.收集到Map集合中
        //需求:收集所有男性,键:姓名,值:年龄
        //toMap:参数一:生成键的规则,参数二:生成值的规则,两个参数都是new Function实现类
        //第一个new Function<流里面每一个数据的类型,键里面数据的类型>
        //第二个new Function<流里面每一个数据的类型,值里面数据的类型>
        //apply方法形参:依次表示流中每一个数据,方法体:生成键/值,返回值:生成的键/值
        /*
          注意点:如果要把数据收集到Map当中,那么键是不能有重复的,否则代码会报错
         */
        /*Map<String, Integer> newMap = list.stream()
        	.filter(s -> "男".equals(s.split("-")[1]))
        	.collect(Collectors.toMap(new Function<String, String>() {
            @Override
            public String apply(String s) {
                //张无忌-男-15
                //键是名字,对应0索引
                return s.split("-")[0];
            }
        }, new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                //张无忌-男-15
                //值是年龄,对应2索引
                return Integer.parseInt(s.split("-")[2]);
            }
        }));*/

        //改写为Lambda表达式
        Map<String, Integer> newMap = list.stream()
        	.filter(s -> "男".equals(s.split("-")[1])).collect(Collectors
        	.toMap(s -> s.split("-")[0], s -> Integer.parseInt(s.split("-")[2])));

        System.out.println(newMap);

    }
}

【练习1】定义一个集合,并添加一些整数1, 2, 3, 4, 5, 6, 7, 8, 9, 10。

要求过滤奇数,只留下偶数,并保存结果。

java 复制代码
package Stream;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

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

【练习2】创建一个 ArrayList 集合,并添加以下字符串,字符串前面是姓名,后面是年龄:

"zhangsan,23" "lisi,24" "wangwu,25",保留年龄大于等于24岁的人,并把结果放入 Map 中,姓名为键,年龄为值。

java 复制代码
package Stream;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;

public class StreamDemo12 {
    public static void main(String[] args) {
        /*
    创建一个 ArrayList 集合,并添加以下字符串,字符串前面是姓名,后面是年龄:
    "zhangsan,23" "lisi,24" "wangwu,25",保留年龄大于等于24岁的人,并把结果放入 Map 中,姓名为键,年龄为值。
     */

        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"zhangsan,23" ,"lisi,24" ,"wangwu,25");

        //1.建立流过滤器
        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])));

        //2.打印
        System.out.println(map);
    }

}

【练习3】如下。

java 复制代码
package Stream;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamDemo13 {
    public static void main(String[] args) {
        /*
        现在有两个ArrayList集合,
第一个集合中:存储6名男演员的名字和年龄。第二个集合中:存储6名女演员的名字和年龄。姓名和年龄中间用逗号隔开。比如:张三,23
要求完成如下的操作:
1,男演员只要名字为3个字的前两人
2,女演员只要姓杨的,并且不要第一个
3,把过滤后的男演员姓名和女演员姓名合并到一起
4,将上一步的演员信息封装成Actor对象。
5,将所有的演员对象都保存到List集合中。备注:演员类Actor,属性有: name,age
男演员:"蔡坤坤,24","叶"咸,23"","刘不甜,22","吴签,24","谷嘉,30","肖梁梁,27
女演员:"赵小颖,35","杨颖,36","高元元,43","张天天,31","刘诗,35","杨小幂,33
         */

        //1.创建集合添加数据
        ArrayList<String> manList = new ArrayList<>();
        ArrayList<String> womanList = new ArrayList<>();
        Collections.addAll(manList,"蔡坤坤,24","叶齁咸,23","刘不甜,22","吴签,24","谷嘉,30","肖梁梁,27");
        Collections.addAll(womanList,"赵小颖,35","杨颖,36","高元元,43","张天天,31","刘诗,35","杨小幂,33");

        //需求1
        Stream<String> stream1 = manList.stream().filter(s -> s.split(",")[0].length() == 3).limit(2);
        //需求2
        Stream<String> stream2 = womanList.stream().filter(s -> s.split(",")[0].startsWith("杨")).skip(1);
        //需求3
        Stream<String> stream3 = Stream.concat(stream1,stream2);
        //需求4
        //String -> Actor 对象(类型转换)
        //map方法:map(new Function<流里的类型,要转成对象的类型>(){});
/*        stream3.map(new Function<String, Actor>() {
            @Override
            public Actor apply(String s) {
                Actor actor = new Actor();
                actor.setName(s.split(",")[0]);
                actor.setAge(Integer.parseInt(s.split(",")[1]));
                return actor;
            }
        });*/
        //简化Lambda写法
        List<Actor> list = stream3.map(s -> new Actor(s.split(",")[0], Integer.parseInt(s.split(",")[1]))).collect(Collectors.toList());
        System.out.println(list);

    }
}
相关推荐
AIAdvocate1 小时前
Pandas_数据结构详解
数据结构·python·pandas
小言从不摸鱼1 小时前
【AI大模型】ChatGPT模型原理介绍(下)
人工智能·python·深度学习·机器学习·自然语言处理·chatgpt
C-SDN花园GGbond1 小时前
【探索数据结构与算法】插入排序:原理、实现与分析(图文详解)
c语言·开发语言·数据结构·排序算法
迷迭所归处2 小时前
C++ —— 关于vector
开发语言·c++·算法
架构文摘JGWZ3 小时前
Java 23 的12 个新特性!!
java·开发语言·学习
FreakStudio3 小时前
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
python·嵌入式·面向对象·电子diy
leon6253 小时前
优化算法(一)—遗传算法(Genetic Algorithm)附MATLAB程序
开发语言·算法·matlab
拾光师4 小时前
spring获取当前request
java·后端·spring
aPurpleBerry4 小时前
neo4j安装启动教程+对应的jdk配置
java·neo4j
锦亦之22334 小时前
QT+OSG+OSG-earth如何在窗口显示一个地球
开发语言·qt