Stream流的使用


前言

java8的新特性,允许开发人员以声明式方式处理集合,Stream并不是同集合数组这样的一种数据结构,可以将其理解成某种数据源的一个视图,这种数据源可是集合、数组、I/O和channel等。

一、Stream流的创建

集合数组等都可以转换成Stream流,例如:

    @Test
    public void createTest(){
        //集合的Stream方法--------------------------------------------------------------------
        List<String> list = Arrays.asList("a", "b");
        Stream<String> stream = list.stream();
        //并行流:list.parallelStream();

        //map集合可以获取Entry, key 及 value的stream流
        Map<String,String> map = new HashMap<>();
        map.entrySet().stream();
        map.keySet().stream();
        map.values().stream();

        //数组工具类的Stream方法----------------------------------------------------------------
        String[] arr = {"c", "d"};
        Stream<String> stream1 = Arrays.stream(arr);
        //并行流:Arrays.stream(arr).parallel();

        //Stream的静态方法---------------------------------------------------------------------
        Stream<String> stream2 = Stream.of("e", "f");
        Stream<Object> empty = Stream.empty();
        //生成一个无限流,接收一个种子值和一个迭代函数(增长)
        Stream.iterate(0, s -> s + 1).limit(10);//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
        //generate(Supplier<T> s) 生成一个无限流,元素由供给者Supplier产生,
        Stream.generate(Math::random).limit(5);

		//连接两个流 concat
        Stream<String> concat = Stream.concat(stream, stream1);
    }

二、Stream流中常用方法

Stream类中的每一个方法都对应集合上的一种操作,通过Lamada表达式将函数式编程引入java中,使代码更简洁,极大的简化了集合的处理操作。

  • 中间操作:每次操作返回一个流,可以进行多次中间操作
           无状态操作:可以直接对单个元素进行的操作,不受之前操作元素的影响;
           有状态操作:只有获取到所有元素后才能执行的操作。
  • 终端操作:每个流只能进行一个终端操作,执行后流无法再次使用,返回一个新的集合或者对象。
           非短路操作:必须处理所有元素才能得到最终结果;
           短路操作:遇到某些符合条件的元素就可以得到最终结果。

1、中间操作 - 无状态操作

可以直接对单个元素进行的操作,不受之前操作元素的影响
  • 筛选
            filterfilter(Predicate<? super T> predicate); 入参为断言型接口,根据给定的条件过滤流中的某些元素。
            distinctStream<T> distinct(); 通过流中元素的 hashCode()equals() 方法去除重复元素。
public static List<Integer> TEST_LIST = Arrays.asList(10,20,14,15,20,30,10,8,25,20,30);

    @Test
    public void test(){

        //20, 20, 30, 25, 20, 30, 
        TEST_LIST.stream().filter(s -> s > 15).forEach(str -> System.out.print(str + ", "));

		//10, 20, 14, 15, 30, 8, 25, 
        TEST_LIST.stream().distinct().forEach(str -> System.out.print(str + ", "));
    }
  • 切片
            limit(n)limit(long maxSize); 获取 n 个元素。
            skip(n)skip(long n); 跳过 n 个元素,可以与 limit 配合实现分页。
    @Test
    public void test1(){
        //10, 20, 14, 15, 20,
        TEST_LIST.stream().limit(5).forEach(str -> System.out.print(str + ", "));

		//30, 10, 8, 25, 20, 30,
        TEST_LIST.stream().skip(5).forEach(str -> System.out.print(str + ", "));
    }
  • 映射:将一个流的元素按照给定的规则映射到另一个流中。
            mapmap(Function<? super T, ? extends R> mapper); 接收一个函数型接口作为参数,该接口实现方法会应用到每个元素上,将其映射成一个新的元素。
            flatMapflatMap(Function<? super T, ? extends Stream<? extends R>> mapper); 接收一个函数型接口作为参数,参数T转换成R(Stream流),将流中的每个元素都转换成另一流,然后把所有的流连接成一个新的流返回。
            mapToIntmapToInt(ToIntFunction<? super T> mapper); 接收一个函数型接口参数,返回一个Int元素的Stream流
            flatMapToIntflatMapToInt(Function<? super T, ? extends IntStream> mapper); 函数型接口参数,R为IntStream,返回一个操作Int的IntStream流。
    @Test
    public void test2(){
        //10F, 20F, 14F, 15F, 20F, 30F, 10F, 8F, 25F, 20F, 30F,
        TEST_LIST.stream().map(str -> str + "F").forEach(s -> System.out.print(s + ", "));

		//1, 0, 2, 0, 1, 4, 1, 5, 2, 0, 3, 0, 1, 0, 8, 2, 5, 2, 0, 3, 0,
        TEST_LIST.stream()
                .map(String::valueOf)
                //如元素10 拆成1 和 0 组成的流
                .flatMap(str -> {
                    String[] split = str.split("");
                    return Arrays.stream(split);
                }).forEach(s -> System.out.print(s + ", "));

	    //2, 1, 3,
        Arrays.asList("aa","b","ccc").stream()
                .mapToInt(String::length)
                .forEach(s -> System.out.print(s + ", "));

        //3, 2, 4,
        Arrays.asList("aa","b","ccc").stream()
                .flatMapToInt(str->IntStream.of(str.length()+1))
                .forEach(s-> System.out.print(s + ", "));
    }
  • 消费
            peekpeek(Consumer<? super T> action);对流中的每个元素进行操作。与 map 类似,但 map 接收一个 Function 表达式,有返回值;而 peek 接收的是一个 Consumer 表达式,没有返回值,可能会修改流中元素的初始数据值。
    @Test
    public void test3(){
        StringBuilder[] sbs = {new StringBuilder("a"),new StringBuilder("B")};
        //[a, B]
        System.out.println(Arrays.toString(sbs));
        //a11, B11, 
        Arrays.stream(sbs).peek(sb -> sb.append("11")).forEach(s -> System.out.print(s + ", "));
        //[a11, B11]      peek作为消费者,可能会改变原来对象值
        System.out.println(Arrays.toString(sbs));
    }

2、中间操作 - 有状态操作

只有获取到所有元素后才能执行的操作
  • 排序
            sortedsorted(); 自然排序,流中的元素需要实现Comparable接口。
            sortedsorted(Comparator<? super T> comparator);自定义排序,自定义Comparator比较器。
    @Test
    public void test4(){
        //aaa, aba, ba, bc, c,
        Arrays.asList("aba","aaa","bc","ba","c").stream()
                .sorted()
                .forEach(s-> System.out.print(s + ", "));

        //c,bc,ba,aba,aaa,
        Arrays.asList("aba","aaa","bc","ba","c").stream()
                .sorted(Comparator.comparingInt(String::length))
                .forEach(s-> System.out.print(s + ","));
    }

3、终端操作 - 短路操作

遇到某些符合条件的元素就可以得到最终结果
  • 判断
            allMatchallMatch(Predicate<? super T> predicate);接收一个Predicate参数,当流中每个元素都满足表达式的条件时返回 true,否则返回 false。相当于 =all
           noneMatchnoneMatch(Predicate<? super T> predicate);接收一个Predicate参数,当流中的每个元素都不满足表达式的条件时返回 true,否则返回 false。相当于 not in
            anyMatchanyMatch(Predicate<? super T> predicate);接收一个Predicate参数,当流中出现某一个元素满足表达式的条件时返回 true,否则返回 false。相当于 =any ( in )
    @Test
    public void test5(){
        List<String> list = Arrays.asList("aa", "b", "ccc");

		//都满足  长度大于2
        boolean allMatch = list.stream().allMatch(str -> str.length() > 2); //false

		//都不满足  为null
        boolean noneMatch = list.stream().noneMatch(String::isEmpty); //true

		//任意一个满足  包含c
        boolean anyMatch = list.stream().anyMatch(str -> str.contains("c")); //true
    }
  • 获取
            findFirstOptional<T> findFirst();返回流中的第一个元素。
            findAnyOptional<T> findAny();返回流中的任意一个元素。
    @Test
    public void test6(){
        List<String> list = Arrays.asList("aa", "c", "d","a","b");

        Optional<String> first = list.stream().findFirst();
        System.out.println(first.get()); //aa

        Optional<String> any = list.stream().findAny();
        System.out.println(any.get()); //aa
    }

4、终端操作 - 非短路操作

必须处理所有元素才能得到最终结果

主要进行一些对结果进行聚合、规约或者收集等操作

  • 聚合
            countlong count(); 返回流中元素的总数。
            maxOptional<T> max(Comparator<? super T> comparator); 返回流中元素的最大值。
            minOptional<T> min(Comparator<? super T> comparator); 返回流中元素的最小值。
    @Test
    public void test7(){
        List<String> list = Arrays.asList("7", "3", "4","1","2");

        long count = list.stream().filter(s->Integer.parseInt(s) > 3).count();
        System.out.println(count);//2

        Optional<String> max = list.stream().max(String::compareTo);
        System.out.println(max.get());//7


        Optional<String> min = list.stream().min(String::compareTo);
        System.out.println(min.get());//1
    }
  • 收集:收集一个 Collector 实例,将流中返回的元素收集成另外一个数据结构。

        通过Collectors工具对像中的方法:
              toList()
              toSet()
              toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper)
              toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction) (BinaryOperator extends BiFunction<T,T,T>)
              joining(CharSequence delimiter)

    @Test
    public void test8(){
        String[] arr = new String[]{"a","bb","ccc","d"};

        //转换成List
        List<String> list = Arrays.stream(arr).collect(Collectors.toList());
        System.out.println(list); //[a, bb, ccc, d]

        //转换成Set
        Set<Integer> set = Arrays.stream(arr).map(String::length).collect(Collectors.toSet());
        System.out.println(set); //[1, 2, 3]

        //转换成Map,保证key唯一,否则报错
        Map<String, Integer> map = Arrays.stream(arr).collect(Collectors.toMap(Function.identity(), String::length));
        System.out.println(map); //{bb=2, a=1, ccc=3, d=1}

        //转换成Map,key重复,自定义策略,(o,o1)->o1:原来值为o,现在值为o1,取o1,即新值覆盖
        Map<Integer, String> map1 = Arrays.stream(arr)
                .collect(Collectors.toMap(String::length, Function.identity(),(o,o1)->o1));
        System.out.println(map1); //{1=d, 2=bb, 3=ccc}

        //转String,joining加入分隔符
        String collect = Arrays.stream(arr).collect(Collectors.joining(","));
        System.out.println(collect); //a,bb,ccc,d
    }
  • 归约:reduce 将流中的元素缩减成一个值进行返回,通常用于求和、求积等操作。
    public void test11(){
        List<Integer> list = Arrays.asList(1, 2, 3);
        Optional<Integer> reduce = list.stream().reduce(Integer::sum);
        System.out.println(reduce.get()); //6

        //两个参数的    第一个参数其实就是累加对象参数的初始值(必须是流元素类型)
        Integer sum = list.stream().reduce(10, Integer::sum);
        System.out.println(sum); //16

        //三个参数的
        Integer reduce1 = list.stream().reduce(10, (x, y) -> x + y, (x, y) -> x + y);
        System.out.println(reduce1);  //16
        //(10+1) +2 + 3

        Integer reduce2 = list.parallelStream().reduce(10, (x, y) -> x + y, (x, y) -> x + y);
        //10 + 1 + 10+ 2 + 10+3
        System.out.println(reduce2); //36
    }

对于规约方法reduce的三个参数的详解见:https://blog.csdn.net/qq_43621307/article/details/128407863


文章参考:

https://blog.csdn.net/ss810540895/article/details/126172285
https://blog.csdn.net/sinat_36645384/article/details/121494363

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值