Articles14
Tags12
Categories3
java8函数设计[1]-在filter中根据Key去重的函数

java8函数设计[1]-在filter中根据Key去重的函数

函数接口是如何写出来的?

java函数接口设计

在filter中根据Key去重的函数 StreamUtil.distinctByKey()

具体使用方法

  • 该函数用于在filter中根据传入参数的某一属性进行过滤,以保证在收集为map的情况下不会出现重复主键
List<entry<string, string="">&gt; simpleList = baseProjects.stream()
                .filter(StreamUtil.distinctByKey(BaseProject::getTypeDic))
                .map(StreamUtil.entry(BaseProject::getTypeDic, BaseProject::getTypeStr))
                .collect(Collectors.toList());

接口设计

    /**
     * <h3>distinctByKey</h3>
     * <p>可用于在filter中根据属性过滤</p>
     *
     * @param function 接受一个 接受 类型A 返回 类型B 的函数式接口
     * @return Predicate 返回一个 接受 类型A 返回 Boolean型 的函数式接口
     */
    public static <t> Predicate<t> distinctByKey(Function<!--? super T, ?--> function) &#123;
        Map filterMap = Maps.newConcurrentMap();

        return t -&gt; filterMap.putIfAbsent(function.apply(t), Boolean.TRUE) == null;
    &#125;

设计思路

  1. 观察Stream.filter()接口
  2. 对接Stream.filter()接口
  3. 实现去重功能
  4. 参数优化

开始编写

观察Stream.filter()接口 && 对接Stream.filter()接口

Stream.filter()接口:Stream<t> filter(Predicate<!--? super T--> predicate)

首先可以看到filter接口需要接收一个类型为Predicate<!--? super T-->的函数,这个函数接受一个参数返回一个boolean类型。

根据以上信息先写一个函数出来

public static <e> Predicate<e> distinctByKey2() &#123;
        return new Predicate<e>() &#123;
            @Override
            public boolean test(E e) &#123;
                return false;
            &#125;
        &#125;;
    &#125;

这个函数虽然可以被filter正常接收,但是由于没有形参,因此无法传递参数

 public static void main(String[] args) &#123;
        Lists.newArrayList()
                .stream()
                .filter(StreamUtil.distinctByKey2())
                .collect(Collectors.toList());
    &#125;

现在与预期的效果比对一下
| 对比 | 函数 |
| :– | - |
| 目前效果 | .filter(StreamUtil.distinctByKey2()) |
| 预期的效果 | .filter(StreamUtil.distinctByKey2(Xxxxx:getId)) |
有点不对?!这个函数虽然可以被filter正常接收,但是去无法传入参数。因此要给distinctByKey2()方法加上传入的参数。
通过观察预期效果,是需要传入的参数应该是一个函数的,这个函数接收一个T类型参数,返回一个不知道什么类型的参数。
Function<t, r="">函数接收一个T类型,返回一个R类型,可以满足这个需求。
继续观察预期效果,这个不知道什么类型的参数实际上就是distinctByKey2方法中new出来Predicate<e>#test(E e)中的那个e,说人话就是Function<t,r>中的R在此处就是Predicate<e>中的E。
那么补上我们的形参

public static <e,r> Predicate<e> distinctByKey2(Function<e,r> function) &#123;
        return new Predicate<e>() &#123;
            @Override
            public boolean test(E t) &#123;

                return false;
            &#125;
        &#125;;
    &#125;

实现去重功能

现在与预期效果一致了,需要实现去重功能 去重功能可以用Set或者ConcurrentMap实现
使用ConcurrentMap存储function返回值的状态
根据ConcurrentMap.putIfAbsent(xxx)的特性 如果map中已经有同样的key和value就返回null,根据返回值是否为null来判断是否需要被过滤

   public static <e,r> Predicate<e> distinctByKey2(Function<e,r> function) &#123;

        Map filterMap = Maps.newConcurrentMap();

        return new Predicate<e>() &#123;
            @Override
            public boolean test(E t) &#123;
                // 调用方传入函数的结果
                R apply = function.apply(t);
                // putIfAbsent 在首次关联K,V时返回null 非首次的时候不执行put()方法 直接返回之前的值
                Boolean isNullIsDuplicate = filterMap.putIfAbsent(apply, Boolean.TRUE);
                // isNullIsDuplicate==null时 K就没重复 函数返回true
                return isNullIsDuplicate == null;
            &#125;
        &#125;;
    &#125;

参数优化

把匿名内部类使用lambda替换掉,在把冗余代码inline,最后调整一下泛型参数

在上面的例子中`Function<e,r>`中
R是调用者函数的返回值类型,仅仅被当做key使用,本身是什么类型不重要,因此可以直接去掉这个R泛型,由?代替
E是调用者函数的形参类型,函数调用方在函数中可能会显式声明参数类型`[注1]`,以达到强转形参类型的目的,因此将E修改为 <!--? super E-->
 public static <e> Predicate<e> distinctByKey2(Function<!--? super E, ?--> function) &#123;
        Map filterMap = Maps.newConcurrentMap();

        return e -&gt; filterMap.putIfAbsent(function.apply(e), Boolean.TRUE) == null;
    &#125;

 //[注1] 
 public static void main(String[] args) &#123;
        List collect = Lists.newArrayList()
                .stream()
                // 显式强转形参类型
                .filter(StreamUtil.distinctByKey2(baseEntity -&gt; baseEntity))
                .collect(Collectors.toList());
    &#125;
Author:Daizc
Link:http://yoursite.com/2019/12/19/java8%E5%87%BD%E6%95%B0%E8%AE%BE%E8%AE%A1[1]-%E5%9C%A8filter%E4%B8%AD%E6%A0%B9%E6%8D%AEKey%E5%8E%BB%E9%87%8D%E7%9A%84%E5%87%BD%E6%95%B0/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可