Stream流

初识Stream作用:

创建集合添加元素,完成以下需求:
1.把所有以“张”开头的元素存储到新集合中
2.把“张"开头的,长度为3的元素再存储到新集合中
3.遍历打印最终结果
以前的做法:

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三", "赵六", "张四", "李四", "张老五");


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


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

[张老五]

Stream的写法:

//初识Stream流
list.stream()
.filter(name -> name.startsWith("张"))
.filter(name -> name.length() == 3)
.forEach(s -> System.out.println(s));

张老五

明显更加简便
Snipaste_2024-02-01_15-18-05.png


Stream流的作用:
结合了Lambda表达式,简化集合、数组的操作。


Stream流的使用步骤:

  1. 先得到一条Stream流(流水线),并把数据放上去
  2. 利用Stream流中的API进行各种操作
    1. 如中间方法:过滤、转换。 方法调用完毕之后,还可以调用其他方法
    2. 如终结方法:统计、打印 最后一步,调用完毕之后,不能调用其他方法

1.获取Stream流

image.png
注意:
其中双列集合不能直接获取Stream流,必须先利用keySet或EntrySet变成Set集合


单列集合 -获取方式演示:

//创建单列集合
ArrayList<Integer>list=new ArrayList<>();
//添加元素
Collections.addAll(list,1,2,3,4);
//获取stream流(流水线),并把数据放在了流水线上,使用终结方法遍历流水线上的数据
list.stream().forEach(new Consumer<Integer>() {
    @Override
    public void accept(Integer i) {
        System.out.println(i);
    }
});

//当然也可以用Lambda表达式简化(forEach是函数式接口)
//list.stream().forEach(i -> System.out.println(i));

控制台:
1
2
3
4


双列集合获取stream流:

HashMap<String,Integer>hm=new HashMap<>();
hm.put("a",1);
hm.put("b",2);
hm.put("c",3);
//方式一:先转成keySet
Set<String> set1 = hm.keySet();
set1.stream().forEach(s -> System.out.println(s));//遍历键

//方式二:先转成entrySet
Set<Map.Entry<String, Integer>> entries = hm.entrySet();
entries.stream().forEach(new Consumer<Map.Entry<String, Integer>>() {
    @Override
    public void accept(Map.Entry<String, Integer> s) {
        System.out.println(s);//直接打印可以,调用getKey和getValue方法可以用
    }
});
//也可以用Lambda表达式简化,Consumer是函数式接口
//entries.stream().forEach( s-> System.out.println(s));

控制台:
a
b
c
a=1
b=2
c=3


数组获取stream流:

//定义集合
int []arr1={1,2,3};
String []arr2={"a","b","c"};
//获取
Arrays.stream(arr1).forEach(i-> System.out.println(i));
System.out.println("----------------------------------");
Arrays.stream(arr2).forEach(s -> System.out.println(s));

控制台:
1
2
3

a
b
c


一堆零散数据获取stream流:

image.png
Stream接口中静态方法of的细节:
形参不仅仅可以传一堆零散数据,还可以传递数组,但仅限引用数据类型
如果传递基本数据类型,是会把整个数组当做一个元素,放到stream当中,如下:
image.png

Stream.of(1,2,3).forEach(s-> System.out.println(s));
System.out.println("----------------");
Stream.of("a","b").forEach(s-> System.out.println(s));

1
2
3

a
b


Stream流的中间方法:

中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作
image.png
Snipaste_2024-02-01_15-35-46.png
注意concat方法是静态的
注意第一点:不能重复使用,否则报错:
image.png


filter过滤方法演示:

filter的形参:
image.png
Predicate是函数式接口:可以用Lambda简化
image.png

ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("张翠山");
list.add("王二麻子");
list.add("张良");
list.add("谢广坤");

//要求:把"张"开头的名字留下,其他不要
list.stream().filter(new Predicate<String>() {
    @Override
    public boolean test(String s) {
        //s,就依次表示流中的每一个数据.
        //返回值:false表示当前数据不留下
        //      true表示留下
        boolean results = s.startsWith("张");
        return results;
    }
}).forEach(s -> System.out.println(s));

注意test方法的返回值是boolean


limit和skip方法:

ArrayList<String>list=new ArrayList<>();
list.add("林青霞");
list.add("张曼玉");
list.add("张三");
list.add("王祖贤");
list.add("柳岩");
list.add("张敏");
list.add("张无忌");

//1.skip跳过前几个元素
//list.stream().skip(3).forEach(s -> System.out.println(s));//跳过前三个

//2.limit获取前几个元素
//list.stream().limit(3).forEach(s-> System.out.println(s));//只获取前三个

//要求:要求截取 "王祖贤"
//方式一:先跳过前三个,再获取第一个
list.stream().skip(3).limit(1).forEach(s -> System.out.println(s));//王祖贤

//方式二:先获取前四个,再跳过前三个
list.stream().limit(4).skip(3).forEach(s -> System.out.println(s));//王祖贤


distinct:去重和concat(静态):合流 方法

distinct底层是HashSet,元素不重复,且要重写hashCode和equals方法,
若要给自定义对象去重一定要重写hashCode和equals方法

concat方法,要传递两个stream流对象
image.png
image.png

//distinct 元素去重,依赖(hashCode和equals方法)
ArrayList<String>list=new ArrayList<>();
Collections.addAll(list,"王祖贤","王祖贤","李四");
list.stream().distinct().forEach(s -> System.out.println(s));


System.out.println("-----------------");
//concat    合并a和b两个流为一个流
ArrayList<String>list1=new ArrayList<>();
ArrayList<String>list2=new ArrayList<>();
Collections.addAll(list1,"zhangsan");
Collections.addAll(list2,"lisi");
//合流并遍历
Stream.concat(list1.stream(),list2.stream()).forEach(s-> System.out.println(s));

王祖贤
李四

zhangsan
lisi


map:转换流中的数据类型

image.png
函数式接口:
image.png

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三-23", "李四-24", "王五-25");

//需求:只获取里面的年龄并进行打印
//先获取年龄字符串 ,再String->int
//第一个类型:流中原本的数据类型
//第二个类型:要转成之后的类型
//apply的形参s:依次表示流里面的每一个数据
//返回值:表示转换之后的数据
list.stream().map(new Function<String, Integer>() {
    @Override
    public Integer apply(String s) {
        String[] str = s.split("-");//张三 23
        String s1 = str[1];
        int i = Integer.parseInt(s1);
        return i;
    }
}).forEach(s-> System.out.println(s));



//也可用Lambda简化
// list.stream()
//         .map( s -> Integer.parseInt(s.split("-")[1]))
//         .forEach(s-> System.out.println(s));

23
24
25


Stream流终结操作方法:
image.png

forEach遍历:

形参:
image.png
是函数式接口,可用Lambda简化
image.png

//创建集合:
ArrayList<String>list=new ArrayList<>();
Collections.addAll(list,"zhangsan","lisi","wangwu");

//获取stream流,并打印
list.stream().forEach(new Consumer<String>() {
    /**
     * <String>表示流上的数据类型
     * accept的形参s表示当前操作的数据
     * accept方法体:打印
     */
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});

//当然可以用Lambda表达式简化:
//list.stream().forEach( s-> System.out.println(s));

zhangsan
lisi
wangwu


Count统计个数:

返回值是long:
image.png

//创建集合:
ArrayList<String>list=new ArrayList<>();
Collections.addAll(list,"zhangsan","lisi","wangwu");
//获取stream流:
long count = list.stream().count();
System.out.println(count);

3


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

有重载方法:

  1. 将数据放入 Object类型的数组中
  2. 将数据放入 指定类型的数组中

image.png

  1. 可以指定数组类型的toArray方法的形参:

image.png

  1. 函数式接口,可用Lambda简化

image.png

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

//1.toArray---放入Object集合
Object[] arr = list.stream().toArray();
System.out.println(Arrays.toString(arr));//直接打印arr会打印地址值



//2.toArray--放入指定类型
/*
注意点:
IntFunction的泛型:具体类型数组
apply形参:流中数据的个数,要跟数组的长度保持一致
apply的返回值:具体类型的数组
方法体:创建数组并返回
*/
String[] arr2 = list.stream().toArray(new IntFunction<String[]>() {
    @Override
    public String[] apply(int value) {
        return new String[value];
    }
});
System.out.println(Arrays.toString(arr2));

//Lambda简化后:
// String[] arr2 = list.stream().toArray(value-> new String[value]);
//System.out.println(Arrays.toString(arr2));

[zhangsan, lisi, wangwu]

注意点:
toArray方法的参数的作用:负责创建一个指定类型的数组
toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组中
toArray方法的返回值:是一个装着流里面所有数据的数组


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

形参:
image.png
1.收集到list:底层使用ArrayList收集

//创建集合
ArrayList<String>list=new ArrayList<>();
Collections.addAll(list,"zhangsan-男-23","zhangsan-男-23","lisi-女-24","wangwu-男-25");

//要求:将男生收集到list集合中
//先过滤,再收集
List<String> list1 = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))//过滤最后要返回Boolean类型
.collect(Collectors.toList());
System.out.println(list1);

[zhangsan-男-23, zhangsan-男-23, wangwu-男-25]

2.收集到Set:底层使用HashSet’收集


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



//要求:将男生收集到list集合中
        Set<String> set = list.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toSet());
        System.out.println(set);

[wangwu-男-25, zhangsan-男-23]

注意点:
ArrayList不去重复,HashSet会去重


3.收集到Map集合:使用HashMap收集
to Map:

  • 参数一表示键的生成规则:
    • Function泛型一:表示流中每一个数据的类型
    • 泛型二:表示Map集合中键的数据类型
    • apply方法形参依次表示每个数据
    • 方法体:生产键的代码
    • 返回值:已经生成的键
  • 参数二表示值的生成规则
    • Function泛型—:表示流中每一个数据的类型
    • 泛型二:表示Map集合中值的数据类型
    • apply方法形参依次表示每个数据
    • 方法体:生产值的代码
    • 返回值:已经生成的值
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "zhangsan-男-23", "lisi-女-24", "wangwu-男-25" ;
//要求:将男生收集到Map集合中,建放姓名,值放年龄
//先过滤出男生,再去设置键和值生成规则
Map<String, Integer> map = list.stream()
            .filter(s -> "男".equals(s.split("-")[1]))
            .collect(Collectors.toMap(new Function<String, String>() {
                                          @Override
                                          public String apply(String s) {
                                              return s.split("-")[0];//zhangsan
                                          }
                                      }
                        ,
                        new Function<String, Integer>() {
                            @Override
                            public Integer apply(String s) {
                                return Integer.parseInt(s.split("-")[2]);//23
                            }
                        }
                ));
        System.out.println(map);


//Lambda可简化
// Map<String, Integer> map = list.stream()
//                 .filter(s -> "男".equals(s.split("-")[1]))
//                 .collect(Collectors.toMap(
//                         s -> s.split("-")[0], 
//                         s -> Integer.parseInt(s.split("-")[2])
//                 ));


//         System.out.println(map);

{zhangsan=23, wangwu=25}

注意点
如果我们要收集到Map集合当中,键不能重复,否则会报错

总结

在这里插入图片描述

  • 44
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

成果、

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

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

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

打赏作者

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

抵扣说明:

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

余额充值