Fork me on GitHub

如何用函数式优雅的写一个增删改查@落雨

如何用函数式优雅的写一个增删改查@落雨

作为一名专业的CRUD-Boy,本篇介绍如何使用io.vavr工具包来写一个比较舒服的有则更新,无则新增CRUD小需求

一、io.vavr

1).Optional怎么玩?jdk8

// 有则更新,无则新增,不推荐
if(optional.isPresent){
    // 有则更新
    optional.get();
} else {
    // 无则新增
}

或者


optional.map(record -> {
  // 有则更新
  update(record);
})
// 无则新增
.orElse(getNewRecord());

2).如果不用Optional如何写?

// 把Java的Optional转为io.vavr的Option,然后判断空和非空
Option.ofOptional(optional).onEmpty(() -> {
    // 处理空的情况,无则新增
    insert();
}).peek(record -> {
    // 处理非空的情况,有则更新
    update(record);
});

io.vavr介绍:
https://www.vavr.io/

用到的武器:Optional -> Option

// optional *value*, no more nulls
Option<T> option = Option.of(...);

引入pom

 <dependency>
     <groupId>io.vavr</groupId>
     <artifactId>vavr</artifactId>
     <version>0.10.3</version>
</dependency>

二、写一个Repo

/**
 * @author luoyu.lzy
 * @Title: AppUserRepo.java
 * @Description:
 * @date 2021/9/1.
 */
public interface AppUserRepo {

    /**
     * 持久化,有则更新,无则新增
     * @param appUser
     * @return
     */
    AppUser save(AppUser appUser);

    /**
     * 根据id获取DTO
     * @param id
     * @return
     */
    AppUser getById(Long id);
}

三、实现这个Repo


/**
 * @author luoyu.lzy
 * @Title:AppUserRepoImpl.java
 * @Description:用户Repo实现类
 * @date 2021/9/1.
 */
@Component
public class AppUserRepoImpl implements AppUserRepo {
    
    @Autowired
    private AppUserDAO appUserDAO;
    
   /**
    * 查询DB,根据id获取Record
    */
    private Optional<AppUserDO> getRecordById(Long id) {
       return Optional.ofNullable(appUserDAO.selectByPrimaryKey(id));
    }
    
    /**
    * bean转换 DO -> DTO
    */
     @Override
    public AppUser getById(Long id) {
        Optional<AppUserDO> optional = getRecordById(id);
        // toAppUser bean转换
        return optional.map(this::toAppUser).orElse(null);
    }
    
   /**
    * 保存,有则更新部分字段,无则新增
    */
    @Override
    public AppUser save(AppUser appUser) {
        Option.ofOptional(getRecordById(appUser.getId())).onEmpty(() -> {
            AppUserDO record = toAppUserDO(appUser);
            record.setGmtCreate(Calendar.getInstance().getTime());
            record.setGmtModified(Calendar.getInstance().getTime());
            int insertResult = appUserDAO.insert(record);
            if (insertResult > 0) {
                record.setId(record.getId());
            }
        }).peek(record -> {
            record.setStatus(appUser.getStatus());
            appUserDAO.updateByPrimaryKey(record);
        });
        return appUser;
    }

}

四、Option.of 源码分析

我们回到这段代码, 分别是Option.of(Optional).onEmpty().peek() 这3个api,我们来看看核心代码。

// 把Java的Optional转为io.vavr的Option
Option.ofOptional(xxxOptinal).onEmpty(() -> {
    // 处理空的情况
}).peek(record -> {
    // 处理非空的情况
});

再来看看Option.ofOptional源码


    /**
     * 包裹Optional对象,返回Option对象     
     */
    @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
    static <T> Option<T> ofOptional(Optional<? extends T> optional) {
    // optional不能为null
        Objects.requireNonNull(optional, "optional is null");
        //通过java.util.Optional.map(Option.of)方法来包装optional每个元素
        return optional.<Option<T>>map(Option::of).orElseGet(Option::none);
    }
       
     static <T> Option<T> of(T value) {
        // none和same分别用来生产None对象和Same对象,None和Same代表无元素(None=无元素)和有元素(Same=相同类型的元素)
        return (value == null) ? none() : some(value);
    }
    
    /**
     * java.util.Optional
     * 通过Optional.map方法,返回Optional对象
    */
    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            // 执行mapper函数
            return Optional.ofNullable(mapper.apply(value));
        }
    }
    
   /**
    * 处理OnEmpty事件,如果元素为空,则执行 Runnable.run
    */
    default Option<T> onEmpty(Runnable action) {
        Objects.requireNonNull(action, "action is null");
        if (isEmpty()) {
            action.run();
        }
        return this;
    }
    
   /**
    * 处理peek事件,如果不为empty,则执行Consumer.accept
    */
    default Option<T> peek(Consumer<? super T> action) {
        Objects.requireNonNull(action, "action is null");
        if (isDefined()) {
            action.accept(get());
        }
        return this;
    }
    
    

五、整完,CRUD更简洁

六、Optional的进化

Java 9 Optional API 新增方法 or,可以实现类似Option.onEmpty的功能

Optional<T> optional = Optional.empty();
Optional<T> result = optional.or(() -> doSomeThionEmpty);

落雨 http://js-dev.cn
2021-09-13 21:13:00

posted @ 2021-09-13 21:01  _落雨  阅读(383)  评论(0编辑  收藏  举报