Java流式编程初体验--Stream流基础

Stream流

在JDK8引入了流的概念。本质上是为了对集合的功能进行进一步的完善。使代码更加简洁优雅,还可以并行处理。

什么是流

流,是一系列数据项,它不是一种数据结构。
流可以进行相关的算法和计算,只是它并没有显式地表现,而是在内部进行隐式地操作。
我们可以把流认为就是一条流水线,在流水线上可以进行各种筛选操作。

流的优势

流,解决了两个问题,1.直接实现你”想要什么”,2.可以进行并行处理。
流,的本质,集合Lambda表达式,对传统Java集合的功能强化。
Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。

Stream流的获取

stream流的获取方式只有四种:

  1. 单列集合 使用collection接口的stream默认方法生成流
  2. 双列集合 间接获取流 可以先通过keySet或者entrySet方法获取到set集合,在获取stream流
  3. 数组 Arrays工具类中的静态方法stream生成流
  4. 同种数据类型的多个数据
    1 2 3 4 5
    a b c d e
    这种形式的数据可以通过 Stream.of(T… values) 用以生成流。
单列集合
private static void method1() {
        // 单列集合
        ArrayList<String> list = new ArrayList<>();
        list.add("111");
        list.add("222");
        list.add("333");
        list.add("444");
        // 获取流
        Stream<String> stream = list.stream();
        stream.forEach(str -> System.out.println(str));
    }
双列集合(Map)
private static void method2() {
        // 双列集合(map)
        HashMap<String, String> map = new HashMap<>();
        map.put("1", "a");
        map.put("2", "b");
        map.put("3", "c");
        // 先获取到所有的键key,然后把这个set结合中所有的键放到stream中
        map.keySet().stream().forEach(s -> System.out.println(s + "--->" + map.get(s)));
        System.out.println("============");
        // 直接获取所有的键值对对象,然后把这个集合中所有的键值对放到stream流中
        map.entrySet().stream().forEach(entry -> System.out.println(entry.getKey() + "--->" + entry.getValue()));
    }
数组
private static void method3() {
        // 数组
        int[] arr = {1, 2, 3, 4, 5};
        Arrays.stream(arr).forEach(a -> System.out.println(a));
    }
同种数据类型的多个数据
private static void method4() {
        // 同种数据类型的多个数据
        Stream.of(1, 2, 3, 4, 5).forEach(a -> System.out.println(a));
    }

stream流的中间方法

1. filter
  1. Stream filter(Predicate predicate) 用于对流中的数据进行过滤
    Predicate接口中的方法
    boolean test(T t) 对给定的参数进行判断,返回一个布尔值
private static void method5() {
        // 1. Stream filter(Predicate predicate) 用于对流中的数据进行过滤
        //         *       Predicate接口中的方法
        //         *           (1)boolean test(T t) 对给定的参数进行判断,返回一个布尔值
        ArrayList<String> arrayList = new ArrayList();
        arrayList.add("张三丰");
        arrayList.add("张无忌");
        arrayList.add("张翠山");
        arrayList.add("赵六");
        arrayList.add("张亮");
        arrayList.add("刘备");
        arrayList.add("关于");

        // filter方法会获取流中的每个数据
        // test方法中的s就是流中的每个数据,
        // 方法返回值为true,表示这个数据留着,
        // 为false,着会剔除流中的该数据
        // 对数据进行判断,张开头的数据留下,
        arrayList.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                if (s.startsWith("张")) return true;
                return false;
            }
        }).forEach(str -> System.out.println(str));
        System.out.println("------------");
        // 接口只有一个抽象方法,所以可以使用lambda表达式替换,简化书写
        arrayList.stream().filter(s -> {
            // if (s.startsWith("张")) return true;
            // return false;
            return s.startsWith("张");
        }).forEach(str -> System.out.println(str));
    }
2. limit

Stream limit(long maxSize) 截取指定参数个数的数据.
打个比方,用户往流中传入了10个数据,我只要前五个,那么就可以使用该方法

private static void method6() {
       // Stream limit(long maxSize) 截取指定参数个数的数据
       ArrayList<String> arrayList = new ArrayList();
       arrayList.add("张三丰");
       arrayList.add("张无忌");
       arrayList.add("张翠山");
       arrayList.add("赵六");
       arrayList.add("张亮");
       arrayList.add("刘备");
       arrayList.add("关于");

       arrayList.stream().limit(3).forEach(str-> System.out.println(str));
   }
3. skip

Stream skip(long n): 跳过指定参数个数的数据
打个比方,用户往流中传入了10个数据,我不要前五个,那个就可以使用该方法,直接跳过前五个数据

private static void method7() {
      // Stream limit(long maxSize) 截取指定参数个数的数据
      ArrayList<String> arrayList = new ArrayList();
      arrayList.add("张三丰");
      arrayList.add("张无忌");
      arrayList.add("张翠山");
      arrayList.add("赵六");
      arrayList.add("张亮");
      arrayList.add("刘备");
      arrayList.add("关于");

      arrayList.stream().skip(3).forEach(str-> System.out.println(str));
  }
4. distinct

Stream distinct() 去除流中重复的元素,依赖hashCode和equals方法(自定义对象需要重写这两个方法)

private static void method8() {
      // Stream limit(long maxSize) 截取指定参数个数的数据
      ArrayList<String> arrayList = new ArrayList();
      arrayList.add("张三丰");
      arrayList.add("张无忌");
      arrayList.add("张翠山");
      arrayList.add("张三丰");
	  arrayList.add("张三丰");
      arrayList.add("赵六");
      arrayList.add("张亮");
      arrayList.add("刘备");
      arrayList.add("关于");
	  arrayList.add("关于");
      arrayList.stream().distinct().forEach(str-> System.out.println(str));
  }
5. Stream流的静态方法concat

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

private static void method9() {
        // Stream limit(long maxSize) 截取指定参数个数的数据
        ArrayList<String> arrayList = new ArrayList();
        ArrayList<String> arrayList2 = new ArrayList();
        arrayList.add("张三丰");
        arrayList.add("张无忌");
        arrayList.add("张翠山");
        arrayList2.add("赵六");
        arrayList2.add("张亮");
        arrayList2.add("刘备");
        arrayList2.add("关于1");
        Stream<String> stream = arrayList.stream();
        Stream<String> stream2 = arrayList2.stream();
        Stream<String> concat = Stream.concat(stream, stream2);
        concat.forEach(str ->
                System.out.println(str)
        );
    }

终结方法

一个stream流只能有一个终结方法
是流水线上的最后一个操作
常见的终结方法:

  1. void forEach(Consumer action)
    Consumer接口中的方法 void accept(T t) 对给定的参数执行此操作
  2. long count() 返回此流中的元素个数
private static void method10() {
        // Stream limit(long maxSize) 截取指定参数个数的数据
        ArrayList<String> arrayList = new ArrayList();
        arrayList.add("张三丰");
        arrayList.add("张无忌");
        arrayList.add("张翠山");
        arrayList.add("赵六");
        arrayList.add("张亮");
        arrayList.add("刘备");
        arrayList.stream().forEach(str-> System.out.println(str));
        long count = arrayList.stream().count();
        System.out.println(count);
    }

Stream流的收集操作(终结方法)

使用Stream流的方式操作完成后,如何收集流中的数据,留着以后使用?
Stream流的收集方法:

  1. R collect(Collector collector)

工具类Collectors提供了具体的收集方式

  1. static Collector toList(): 把元素收集到List集合中
  2. static Collector toSet(): 把元素收集到set集合中
  3. static Collector toMap(Function keyMapper,Function valueMapper): 把元素收集到Map集合中
/*
         * stream流的收集方法
         *   R collect(Collector collector)
         * */
        ArrayList<Integer> arrayList = new ArrayList();
        for (int i = 1; i < 11; i++) {
            arrayList.add(i);
        }
        // 只要偶数
        List<Integer> list = arrayList.stream()
                .filter(number -> number % 2 == 0)
                // 收集流中的数据,但是不负责创建容器,也不负责把数据添加到容器中
                // Collectors.toList() 在底层会创建一个List容器,并把流中的数据添加到List容器中
                .collect(Collectors.toList());
        System.out.println(list);
        // Collectors.toSet() 在底层会创建set容器,并把流中的数据加入到容器中
        Set<Integer> set = arrayList.stream().filter(number -> number % 2 != 0)
                .collect(Collectors.toSet());
        System.out.println(set);

ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("张三,1");
        arrayList.add("李四,2");
        arrayList.add("王五,3");
        arrayList.stream().filter(str -> {
            // 获得编号,保留编号小于等于2的
            String[] split = str.split(",");
            return Integer.valueOf(split[1]) <= 2;
        }).collect(Collectors.toMap(
                // 第一个表达式,用来获取键,第二个表达式用来获取值
                str->str.split(",")[0],
                str->str.split(",")[1]
        ));

结论

**注意:**在stream流中是无法直接修改集合或数组等数据源中的数据的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

尤雨东

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

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

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

打赏作者

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

抵扣说明:

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

余额充值