Java—Stream流

目录

初识Stream流

Stream流的使用步骤

获取Stream流

单列集合获取Stream流

双列集合获取Stream流

数组获取Stream流

零散数据获取Stream流

Stream流的中间方法

filter

limit、skip

distinct

concat

map

Stream流的终结方法

toArray

collect


初识Stream流

        在Java中,Stream流是一种用于处理集合类(如List、Set和Map)中元素的工具。Stream API 引入于 Java 8,它允许我们以声明式的方式进行数据操作。使用 Stream API 可以使代码更简洁、更易读,同时利用并行处理来提升性能。

Stream流的使用步骤

Stream流的使用步骤如下
1. 先获取一条Stream流(流水线),并把数据放上去;
2. 使用中间方法对流水线上的数据进行操作;
3. 使用终结方法对流水线上的数据进行操作。


获取Stream流

如下表所示不同数据类型获取Stream流的方式各不相同。 


单列集合获取Stream流

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c", "d", "e");
// 获取流水线,并打印元素
list.stream().forEach(e -> System.out.printf(e));//abcde

双列集合获取Stream流

双列集合可以通过两种方式获取Stream流
1. 通过hm.keySet().stream()获取集合中所有的键的stream流;
2. 通过hm.entrySet().stream()获取集合中所有键值对的stream流。、

代码示例

HashMap<String, Integer> hm = new HashMap<>();
hm.put("aaa", 111);
hm.put("bbb", 222);
hm.put("ccc", 333);
hm.put("ddd", 444);

//第1种获取stream流的方法:获取集合中的所有键
hm.keySet().stream().forEach(e-> System.out.println(e));
/*
aaa
ccc
bbb
ddd
*/

//第2种获取stream的流方法:获取集合中的所有键值对
hm.entrySet().stream().forEach(e-> System.out.println(e));
/*
aaa=111
ccc=333
bbb=222
ddd=444
*/

数组获取Stream流

数组可以通过两种方式获取Stream流
1. 通过Arrays.stream(arr)方法获取Stream流;
2. 通过Stream.of(arr)方法获取Stream流,因为该方法的形参是不可变参数,因此可以传入数组类型。但弊端在于,传入数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream流当中,因此并不建议使用该方法获取数组的Stream流。

示例代码

int[] arr = {1, 2, 3};
String[] strings = {"a", "b", "c"};

// 1.通过Arrays.stream()获取stream流
Arrays.stream(arr).forEach(e -> System.out.println(e));
/*
1
2
3
*/

// 2.通过Stream.of()获取stream流(不建议使用)
Stream.of(arr).forEach(e-> System.out.println(e)); //[I@3b9a45b3
Stream.of(strings).forEach(e -> System.out.println(e));
/*
a
b
c
*/

零散数据获取Stream流

零散数据可以通过Stream.of()的方式获取stream流,但是需要保证传入的数据类型都是相同的

Stream.of("a", "b", "c").forEach(e -> System.out.println(e));
/*
a
b
c
*/

Stream.of(1,2,3).forEach(e-> System.out.println(e));
/*
1
2
3
*/

Stream流的中间方法

Stream<T> filter(Predicate<? super T> predicate)        // 过滤
Stream<T> limit(long maxSize)                           // 获取前几个元素
Stream<T> skip(long n)                                  // 跳过前几个元素
Stream<T> distinct()                                    // 元素去重,依赖(hashCode和equals方法)
static<T>Stream<T>concat(Stream a,Stream b)             // 合并a和b两个流为一个流
Stream<R> map(Function<T ,R> mapper)                    // 转换流中的数据类型

注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据


filter

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(e -> System.out.println(e));



//链式编程:留下以张开头且长度为3的字符串
list.stream().filter(s -> s.startsWith("张"))
        .filter(s -> s.length() == 3)
        .forEach(e -> System.out.println(e));



Stream<String> stream1 = list.stream();
Stream<String> stream2 = stream1.filter(s -> s.startsWith("张"));
Stream<String> stream3 = stream1.filter(s -> s.length() == 3);//报错:stream1已经被使用过一次,不可再次被使用

limit、skip

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "张三", "张三丰", "赵敏", "张良", "李四");

//获取前3个数据
list.stream().limit(3).forEach(e-> System.out.printf(e+" "));//张无忌 周芷若 张三
//跳过前4个数据
list.stream().skip(4).forEach(e-> System.out.printf(e+" "));//赵敏 张良 李四 

distinct

注意:distinct底层依赖hashCode和equals两个方法对集合中的元素进行去重,如果集合中的元素类型是自定义类,则需要重写这两个方法。

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

list.stream().distinct().forEach(e-> System.out.printf(e+" "));//张三 赵敏 张良 李四

concat

ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1, "张三", "张三");
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2, "李四", "李四");

Stream.concat(list1.stream(),list2.stream()).forEach(e-> System.out.printf(e+" ")); //张三 张三 李四 李四

map

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌-12", "赵敏-22", "张良-8", "李四-26");


//需求:获取字符串的数字部分
//Function<E, T>,E代表元素原来的类型,T代表元素转换后的类型
//需要保证apply返回值类型与T相同
list.stream().map(new Function<String, Integer>() {
    @Override
    public Integer apply(String s) {
        //将字符串进行分割
        String[] arr = s.split("-");
        //取出字符串的年龄部分
        String ageString = arr[1];
        int age = Integer.parseInt(ageString);
        return age;
    }
}).forEach(e-> System.out.println(e));


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

Stream流的终结方法

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

toArray

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "赵敏", "张良", "周芷若");

//转换成Object类型的数组
Object[] objects = list.stream().toArray();

//转换成指定类型的数组
String[] strings1 = list.stream().toArray(new IntFunction<String[]>() {
    @Override
    //value表示的是stream流中元素的个数
    public String[] apply(int value) {
        return new String[value];
    }
});

//Lambda简化
String[] strings2 = list.stream().toArray(value -> new String[value]);

collect

通过collect方法将Stream流转换为List、Set集合,代码如下

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌-男-12", "张无忌-男-12", "赵敏-女-19", "张三丰-男-25", "周芷若-女-22", "张良-男-28", "谢广坤-男-30");

//将性别为"男"的元素搜集到List集合中,元素不去重
List<String> newList = list.stream()
        .filter(s -> "男".equals(s.split("-")[1]))
        .collect(Collectors.toList());

//将性别为"男"的元素搜集到Set集合中,元素去重
Set<String> newSet = list.stream()
        .filter(s -> "男".equals(s.split("-")[1]))
        .collect(Collectors.toSet());

通过collect方法将Stream流转换为Map集合,注意需要保证键的唯一性,代码如下

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌-男-12", "赵敏-女-19", "张三丰-男-25", "周芷若-女-22", "张良-男-28", "谢广坤-男-30");

//将性别为"男"的元素搜集到Set集合中,规定键为姓名,值为年龄
Map<String, Integer> collect = list.stream()
        .filter(s -> "男".equals(s.split("-")[1]))
        /*
         *
         * toMap: 参数1表示键的生成规则
         *        参数2表示值的生成规则
         *
         * 参数1:
         *       Function<流中每一个数据的类型,Map集合中键的数据类型>(){
         *           public Map集合中键的数据类型 apply(流中每一个数据的类型 s){
         *               生成键的代码
         *               返回键;
         *           }
         *       }
         *
         *
         *参数2:
         *       Function<流中每一个数据的类型,Map集合中值的数据类型>(){
         *           public Map集合中值的数据类型 apply(流中每一个数据的类型 s){
         *               生成值的代码
         *               返回值;
         *           }
         *       }
         *
         * */
        .collect(Collectors.toMap(
                new Function<String, String>() {
                    @Override
                    public String apply(String s) {
                        return s.split("-")[0];
                    }
                },
                new Function<String, Integer>() {
                    @Override
                    public Integer apply(String s) {
                        return Integer.valueOf(s.split("-")[2]);
                    }
                }));


//Lambda表达式简化
Map<String, Integer> collect1 = list.stream()
        .collect(Collectors.toMap(s -> s.split("-")[0], s -> Integer.valueOf(s.split("-")[2])));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值