MyBatisPlus 泛型方法使用default <V> List<V> listObjs(Function<? super Object, V> mapper)

2022-05-10 0 By admin

一、泛型限制和函数式接口说明

1.1、带限制的泛型

default List listObjs(Function<? super Object, V> mapper)

首先 我们先看到的这个方法入参是:Function<? super Object , V> mapper ,这是jdk1.8为了统一简化书写格式引进的函数式接口 。简单 解释一下对Function函数的理解,就以上面的写法为例,可以看到Function函数要传入两个类型:

  1. ? super Object 这个类型限制了下限,即传入的类型必须是Object的超类,或者是Object ,所以函数的第一个类型必然是 Object类型 ,后面会说为什么会是Object类型
  2. V 没有限制泛型的上下边界,所以可以为任何类型

1.2、函数式接口

每个函数式接口的典型特点就是有且仅有一个可以实现的接口,Function也不例外;看下接口部分源码:

@FunctionalInterface
public interface Function<T, R> {
 R apply(T t); 
 ...
}

这个接口做的就是类型之间T和R的转换传入T类型 ,返回R类型。那么上面的Function<? super Object, V>写法就是说【传入Object类型,返回 V 类型】。

知识补充:

函数式(Functional)接口

泛型在继承上的体现【通配符】

二、MyBatisPlus listObjs 接口介绍

2.1、官网接口说明

// 查询全部记录
1. <V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
2. <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

接口源码

1. default List<Object> listObjs() {
       return this.listObjs(Function.identity());
   }
2.  default <V> List<V> listObjs(Function<? super Object, V> mapper) {
       return this.listObjs(Wrappers.emptyWrapper(), mapper);
   }
3.  default List<Object> listObjs(Wrapper<T> queryWrapper) {
       return this.listObjs(queryWrapper, Function.identity());
   }
4. default <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
       return (List)this.getBaseMapper().selectObjs(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
   }

可以看到接口源码中方法2调用了方法4。

2.2、方法4的意义

  1. this.getBaseMapper().selectObjs(queryWrapper):拿到BaseMapper;再调用它的selectObjs方法传入queryWrapper条件,查出数据list。
  2. stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList()):再利用流处理,过滤掉空值,筛选出mapper类型的数据,重新组成一个集合。
  3. 就得到了我们所需要的List数据。这个V类型就是我们上面所说的Function中所传的泛型V,就是我们想要转换的类型。

三、listObjs 使用示例

接下来看一下我们在Service业务方法中对Function的方法实现以及对listObjs()方法的调用。

3.1、实例化出Function接口

先实例化出Function接口,实现apply接口,进行类型转换,其中Object类型的参数是我们实体类中使用Mp的@TableId注解标注的属性。
##由于主键属性的类型不定,所以mp只能定为Object类型来限制传参。
##如果没有标注注解,则根据属性名对应数据库表的字段进行匹配查找(参数一般都是主键id,除非你使用@TableId注解标注了其他字段)。

Function<Object,Long> function = new Function<Object, Long>() {
    @Override
    public Long apply(Object id) {
    //进行一系列转换操作 ,最终返回我们所需要的类型V , 这里只做简单演示。
        return Long.valueOf(id.toString());
    }
};

3.2、listObjs 调用

调用listObjs(queryWarpper,function)方法,这里queryWrapper就不做介绍。

List<Long> longs1 = listObjs(null, function);

经过Function的处理我们会得到表中数据的所有主键做组成的list集合。

3.3、方式使用另外两种写法

推荐最后一种。

//匿名类写法
List<Long> longs = listObjs(null,  new Function<Object, Long>() {
    @Override
    public Long apply(Object id) {
    //进行一系列转换操作 ,最终返回我们所需要的类型V , 这里只做简单演示。
        return Long.valueOf(id.toString());
    }
});
//简写
List<Long> longs = listObjs(null, a ->{
    return Long.valueOf(a.toString());
});

3.4、返回其他对象类型示例

@Test
void mpTest() {
    List<User> list = userService.list();
    list.stream().forEach(System.out::println);
    System.out.println("--------------------------------");
    List<UserVo> longs = userService.listObjs(null,  new Function<Object, UserVo>() {
        @Override
        public UserVo apply(Object id) {
            System.out.println("apply的参数"+id.toString());
            UserVo userVo = new UserVo();
            User user = userService.getById(Integer.valueOf(id.toString()));
            copyProperties(user,userVo);
            return userVo;
        }
    });
    longs.stream().forEach(System.out::println);
}