zoukankan      html  css  js  c++  java
  • Stream补充



    最近看的项目使用Stream来操作集合,熟悉代码阶段就令人头大,来补课了


    1. 常见的接口

    我们常用Lambda来表达这些函数式接口,所以看着比较陌生,其实日常都有使用到。下面说明时会先给出源码,然后再给出使用事例


    1.1 Consumer

    传入参数,内部进行操作,没有返回值

    @FunctionalInterface
    public interface Consumer<T> {
    
        /**
         * Performs this operation on the given argument.
         *
         * @param t the input argument
         */
        void accept(T t);
    }
    
    list.stream().forEach(s -> System.out.println(s));	// forEach(Consumer<? super T> action)
    

    1.2 Function

    传入参数,内部进行转换,有返回值

    @FunctionalInterface
    public interface Function<T, R> {
    
        /**
         * Applies this function to the given argument.
         *
         * @param t the function argument
         * @return the function result
         */
        R apply(T t);
    }
    
    list.stream().map(s -> s + "-");	// Stream<R> map(Function<? super T, ? extends R> mapper);
    

    1.3 Supplier

    创建一个容器并且返回出去

    @FunctionalInterface
    public interface Supplier<T> {
    
        /**
         * Gets a result.
         *
         * @return a result
         */
        T get();
    }
    
    Collector toMap(Function keyMapper
    			   ,Function valueMapper
    			   ,BinaryOperator mergeFunction
    			   ,Supplier<M> mapSupplier)
    

    1.4 Predicate

    传入参数,进行判断,返回boolean

    @FunctionalInterface
    public interface Predicate<T> {
    
        /**
         * Evaluates this predicate on the given argument.
         *
         * @param t the input argument
         * @return {@code true} if the input argument matches the predicate,
         * otherwise {@code false}
         */
        boolean test(T t);
    }
    
    list.stream().anyMatch(s -> s >= 10);	// anyMatch(Predicate<? super T> predicate)
    




    2. 集合的操作

    后期才知道流可以转变成的神奇之处,前来学习


    先来看流的收集方法: collect(Collector<? super T, A, R> collector) ,其主要将流中元素收集成另外一个数据结构(如:集合,String,整数等),而参数是一个Collector实例(后面会说明)


    2.1 Collectors

    Collectors是一个工具类,其常用的方法有:

    • toList(),返回一个Collector实例,这就是上面所说的Collector实例
    • toSet(),返回一个Collector实例
    • toMap(),返回一个Collector实例
    • joining()
    • collectingAndThen()
    • counting()

    2.2 转成集合

    流转成集合十分的简单,往 collect() 方法里面传入Collector实例即可(Collectors工具类生成的Collector实例)

    List list = Arrays.stream(array).collect(Collectors.toList());
    Set  set  = Arrays.stream(array).collect(Collectors.toSet());
    Map  map  = Arrays.stream(array).collect(Collectors.toMap());
    

    2.2.1 toMap()规约

    阿里巴巴Java开发手册规约提到:

    【强制】在使用 java.util.stream.Collectors 类的 toMap() 方法转为 Map 集合时,一定要使用含有参数类型为BinaryOperator,参数名为 mergeFunction 的方法,否则当出现相同 key 值时会抛出 IllegalStateException 异常
    

    使用toMap()方法转换成集合时,一般会遇到两个问题:

    • Key重复问题
    • Value空指针异常

    toMap的参数:

    public static Collector toMap(Function keyMapper
    							 ,Function valueMapper
    							 ,BinaryOperator mergeFunctio
    							 ,Supplier mapSupplier) {
    							 
    	BiConsumer accumulator = 
    	(map, element) -> map.merge(keyMapper.apply(element)
    							   ,valueMapper.apply(element)
    							   ,mergeFunction);
    							   
        return new CollectorImpl (mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
    }
    
    • 前两个是Function,传参内部操作并返回的,正常都是getKey(),getValue()
    • 第三个是BiFunction实现类(类似于Function),但接收两参数返回一个值,进行合并操作的
    • 第四个是Supplier,是提供的容器,默认是HashMap

    为了避免上述的两个问题,我们可以进行如下操作:

    • Key重复一般会使用后者覆盖策略
    ArrayList<User> list = new ArrayList();
    
    list.add(new User("张三", 30));
    list.add(new User("张三", 80));
    list.add(new User("李四", 40));
    list.add(new User("王五", 50));
    
    Map map = list.stream().collect(Collectors.toMap(User::getName,User::getAge,(v1, v2) -> v2));
    
    map.forEach((k,v) -> System.out.println(k + "---" + v));
    
    ----------------------------------------------------------------------
    
    李四---40
    张三---80
    王五---50
    

    • 而Value的NPE问题是因为底层使用了 java.util.HashMap,其 merge 方法里会进行如下的判断:
    if (value == null || remappingFunction == null)	throw new NullPointerException();
    




    3. Reduce约简操作

    以前约简不会用,现在接触才发现这就是迭代的形式啊,这次的输出值作为下次的输入值


    int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    
    // 传入前两个参数累加,返回值作为下次的第一个参数,下次往后移动一格
    System.out.println(
            Arrays.stream(nums).reduce((left, right) -> left += right).getAsInt()
    );
    
    // 有个初始值,结果不为空就不用Optional类包装了,不会NPE
    System.out.println(
            Arrays.stream(nums).reduce(100,(left, right) -> left += right)
    );
    


  • 相关阅读:
    一种安全云存储方案设计(上)——基于二次加密的存储策略与加密图文混合检索
    lamda表达式导致运行时VerifyError
    编译原理:语法分析概述
    语音识别与 RNN-Transducer 概述
    通信原理基本概念
    追光捉影的自动机:2021 卓工实训小作文
    【实战】jsfinder+jsinfo-scan结合改造
    js基础记录
    qq、微信二次分享
    收藏链接
  • 原文地址:https://www.cnblogs.com/Howlet/p/14055440.html
Copyright © 2011-2022 走看看