Stream流详解

Lambda表达式

Stream流往往结合Lambda表达式使用,学习Stream流之前先介绍下Lambda表达式。
作用:简化匿名内部类书写

细节

  • 只能简化函数式接口的匿名内部类写法
  • 函数式接口:有且只有一个抽象方法的接口,可在接口上方加@FunctionalInterface注解做标记

好处

写的代码更加简洁,让我们更加关注于方法体

省略写法

可推导可省略

  • 参数类型可以省略
  • 如果参数只有一个,括号也可以省略不写
  • 如果方法体只有一行,大括号,return,分号都可以省略不写,但还要同时省略
//匿名内部类写法
Arrays.sort(arr, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
//Lambda标准写法
Arrays.sort(arr,(Integer o1,Integer o2) ->{
    return o2 - o1;
});
//省略写法
Arrays.sort(arr,(o1,o2) -> o2 - o1);

遍历集合

default修饰符:当没有明确访问修饰符时,默认修饰符为default

默认方法,变量,类,只能在同一个包内被访问

任意集合类型通用

default void forEach(Consumer<? super T> action);
/**
 * 底层原理:
 * forEach方法底层也会遍历集合,并将遍历的结果传给实现Consumer接口的对象中的accept方法
 * 所以直接打印accept方法参数即可
 */
list.forEach(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});

Stream流

结合Lambda表达式,用来简化数组,集合的操作

关于对Stream流的理解,可以把他当成工厂中的流水线,每个stream流的操作过程遵循着创建 -->操作 -->获取结果的过程,就像流水线上的节点一样组成一条条线。

使用步骤

  1. 获取Stream流(流水线),并把数据放上去
  2. 使用中间方法对Stream流进行操作
  3. 使用终结方法对Stream流进行操作

获取Stream流

public class Demo0 {
    public static void main(String[] args) {
        //单列集合
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"aaa","bbb","ccc");
        list.stream().forEach(s -> System.out.println(s));

        //双列集合
        //双列集合不能直接获取Stream流,所以须想办法通过单列集合来获取
        HashMap<String,String> map = new HashMap<>();
        map.put("aaa","111");
        map.put("bbb","222");
        map.put("ccc","333");
        //第一种方式:获取键集合
        map.keySet().stream().forEach(s -> System.out.println(map.get(s)));
        //第二种方式:获取键值对集合
        map.entrySet().stream().forEach(entry -> System.out.println(entry));

        //数组
        //使用Arrays中的静态方法stream()
        int[]arr = {2,345,2134,121};
        Arrays.stream(arr).forEach(num -> System.out.println(num));

        //散装的数据
        //使用Stream的静态方法of
        //方法形参是个可变参数,可以传递数组也可以传递零散的数据
        //但只能传递引用数据类型数组,如果传递基本数据类型数组,会将其看做一个整体,放到Stream中
        Stream.of("sfd","sfdsfs","dop").forEach(s -> System.out.println(s));

    }
}

使用中间方法

在这里插入图片描述

细节

  • 修改Stream流中的数据不会对原来的数组或集合造成影响
  • 返回的是一个新的Stream流,原来的Stream流只能使用一次,可使用链式编程
public class Demo1 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"aaa","abcd","jfdfs","abh");
        list.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                //返回值为true留下,返回值为false过滤掉
                return s.startsWith("a");
            }
        }).forEach(s -> System.out.println(s));
        list.stream().filter(s -> s.startsWith("a"));
        System.out.println("----------");

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

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

        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"aaa","sss","aaa","fds");
        //元素去重
        //底层用的是HashSet依赖hashSet和equals方法
        list2.stream().distinct().forEach(s -> System.out.println(s));
        System.out.println("-------");

        //将两个流合并成一个
        //尽量保证两个流的数据类型相同,如果不同合并后流的数据类型为两数据类型的共同父类
        Stream.concat(list.stream(),list2.stream()).forEach(s -> System.out.println(s));
        System.out.println("-----------");

        ArrayList<String> list3 = new ArrayList<>();
        Collections.addAll(list3,"a-12","bb-23","yu-89","iu-23");
        //map:转换流中的数据类型
        //第二个泛型和方法的返回值类型是要转换的数据类型
        list3.stream().map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s.split("-")[1]);
            }
        }).forEach(num -> System.out.println(num));


        list3.stream().map(s -> Integer.parseInt(s.split("-")[1])).forEach(num -> System.out.println(num));

    }
}

使用终结方法

在这里插入图片描述

public class Demo2 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"sd","aaa","sdf","sss");
        //遍历
        list.stream().forEach(s -> System.out.println(s));
        //统计数量
        long count = list.stream().count();
        System.out.println(count);
        System.out.println("-----------");


        //收集流中的数据放到数组中
        Object[] objects = list.stream().toArray();
        System.out.println(Arrays.toString(objects));
        System.out.println("------------");
        //指定数组数据类型
        //泛型为指定类型的数组
        //apply方法参数:流中数据的个数 方法体:创建指定类型数组
        //toArray方法底层,将流中数据依次放入创建好的数组中,返回值为装着流中所有数据的数组
        String[] arr = list.stream().toArray(new IntFunction<String[]>() {
            @Override
            public String[] apply(int value) {
                return new String[value];
            }
        });
        System.out.println(Arrays.toString(arr));
    }
}
public class Demo3 {
    public static void main(String[] args) {
        String[]arr = {"aaa-111","bbb-222","ccc-333","lll-444","ddd-555"};
        //Collectors.toList():创建集合,collect方法再将流中数据放入集合中
        //Collectors:是Stream流中的工具类
        List<String> list = Arrays.stream(arr).collect(Collectors.toList());
        System.out.println(list);

        Set<String> set = Arrays.stream(arr).collect(Collectors.toSet());
        System.out.println(set);

        /**
         * toMap参数1:键的生成规则
         *           泛型1:流中数据类型
         *           泛型2:键的数据类型
         *
         *           方法形参:流中数据
         *           方法体:处理流中数据生成键的代码
         *           返回值:键
         * toMap参数2:值的生成规则
         *           同理
         *
         * 键不能重复,否则会报异常
         */
        Map<String, Integer> map = Arrays.stream(arr).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.parseInt(s.split("-")[1]);
            }
        }));

        System.out.println(map);


    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 8 引入了一种新的抽象概念 Stream),它使得对数据的处理变得更加简便和高效。Stream 是一种来自数据源的元素队列并支持聚合操作。 Stream API 借助于lambda表达式,极大的提高了Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用fork/join并行方式来拆分任务和加速处理过程。 Stream 的特性可以归纳为: - 不是数据结构 - 没有存储元素 - 支持延迟计算 - 支持并行处理 Stream 的操作分为中间操作和终止操作。中间操作会返回一个新的 Stream,我们可以对这个新的 Stream 进行下一步的操作。终止操作则会返回一个最终的结果。 Stream 操作可以分为以下几种: - Intermediate(中间)操作:一个可以后面跟随零个或多个Intermediate操作。其目的主要是打开,做出某种程度的数据映射/过滤,然后返回一个新的,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始的遍历。 - Terminal(终止)操作:一个只能有一个 Terminal 操作,当这个操作执行后,就被使用“光”了,无法再被操作。所以这必定是的最后一个操作。Terminal 操作的执行,才会真正开始的遍历,并且会生成一个结果,或者一个 side effect。 Stream API 提供了大量的方法,可以用来完成各种不同的操作,如过滤、映射、筛选、查找、归约等等。这些方法可以分为以下几类: - 转换操作:map、flatMap、filter、distinct、sorted、peek、limit、skip - 聚合操作:forEach、reduce、collect - 匹配操作:allMatch、anyMatch、noneMatch - 查找操作:findFirst、findAny - 统计操作:count、min、max、average、sum Stream API 的使用可以大大简化代码,增加可读性和可维护性。同时,由于它的并行特性,可以有效地提升程序的性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值