Optional的详细实战用法,优雅的消除if..else..复杂逻辑运算函数封装....

如何优雅的消除if…else…让代码看起来高大上?兄弟们搞起来啊


怎么优雅的让你的代码不再有if…else;如何优雅的躲避深恶痛绝的NPE,这也许是一个程序员一生的追求,今天给大家带来一个案例,将一个臃肿的胖子,P成一个高富帅的过程.
其中使用到了J8的Optional这个容器.当然肯定有小伙伴比我用的好,或者比我理解的更透彻,我写的有不对的地方,也请小伙伴指出来,大家共同学习,共同进步…

if(我是高富帅){
	System.out("对象排排站")
}else{
	System.out("苦逼的写代码")
}

不叨逼叨逼叨了.先给大家看段代码,你若不晕,我连吹两瓶二锅头…

public class DiscountedPriceConverter implements CustomConverter {
    @Override
    public Object convert(Object destination, Object source, Class<?> destinationClass, Class<?> sourceClass) {
        double platformDiscount = 0;
        if (ObjectUtil.isEmpty(source)) {
            return String.valueOf(platformDiscount);
        }
        if (ObjectUtil.isNotEmpty(source) && source instanceof List) {
            List<?> objectList = (List<?>) source;
            Optional<?> optional = objectList.stream().findFirst();
            if (optional.isPresent()) {
                Object object = optional.get();
                if (object instanceof CouponDetail) {
                    List<CouponDetail> couponDetails =
                            ListsUtil.castList(source, CouponDetail.class);
                    if (ObjectUtil.isNotEmpty(couponDetails)) {
                        assert couponDetails != null;
                        for (CouponDetail couponDetail : couponDetails) {
                            if (ObjectUtil.isEmpty(couponDetail)) {
                                platformDiscount = 0;
                            }
                            if (ObjectUtil.isNotEmpty(couponDetail) && ObjectUtil.isNotEmpty(couponDetail.getCouponPrice())) {
                                platformDiscount += Double.parseDouble(couponDetail.getCouponPrice());
                            }
                        }
                        return String.valueOf(platformDiscount);
                    }
                }

                if (object instanceof com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.enGet
                        .CouponDetail) {
                    List<com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.enGet
                            .CouponDetail> couponDetails =
                            ListsUtil.castList(source, com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.enGet
                                    .CouponDetail.class);
                    if (ObjectUtil.isNotEmpty(couponDetails)) {
                        assert couponDetails != null;
                        for (com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.enGet
                                .CouponDetail couponDetail : couponDetails) {
                            if (ObjectUtil.isEmpty(couponDetail)) {
                                platformDiscount = 0;
                            }
                            if (ObjectUtil.isNotEmpty(couponDetail) && ObjectUtil.isNotEmpty(couponDetail.getCouponPrice())) {
                                platformDiscount += Double.parseDouble(couponDetail.getCouponPrice());
                            }
                        }
                        return String.valueOf(platformDiscount);
                    }
                }
            }
            return String.valueOf(platformDiscount);
        }
        return String.valueOf(platformDiscount);
    }
}

看了这段代码,如果你看到这段代码,如果没有反胃的生理反应,那么恭喜你,蓝翔挖掘机专业是你改变人生的最好途径.接下来,咱们就改造这个代码,让他看起来高大上…(这段没有注释的代码)

  1. 业务梳理

①、首先我们先看这里的大框架,是由两个两个逻辑块, 判空逻辑; 如果source为空则返回默认值,如果source不为空则返回计算后的值。
②、当source不为空时,需要判断source的类型是否为List类型,若不是则直接返回默认值.(这里受业务约束,必须是list)
③、当source为list且不为空时,要确定list中的泛型(这里受业务约束,list中的泛型为同一泛型,不存在多种类型同时存在的情况)
④、当source不为空时,这里执行了两个业务逻辑判断,也就是下面两个类的判断,两个类走了不同转换逻辑.否则返回默认值

com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.enGet.CouponDetail
com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.search.CouponDetail
  1. 代码构建

通过对代码结构逻辑的梳理我们就可以着手改造这段代码了,首先我们先把大的框架写出来,在进行具体业务的逻辑处理

//这里为空则返回空对象 这里表示 如果source不为空则继续执行,若为空直接返回默认值
Optional.ofNullable(source)
		 //若source为list类型,这继续执行,若不为list类型则直接返回默认值
         .filter(fSource -> fSource instanceof List)
         //若source为list类型执行计算
         .map(mSource -> {
             //这里进行计算或者下一步逻辑
         })
         //这里返回默认值
         .orElse(String.valueOf(platformDiscount));

由上面代码可以看出这段逻辑代码的框架逻辑我们就已经搭建好了,下面对代码进行技术分析:(看黑板)

2.1、由于不知道source是否为空,这里使用ofNullable(),进行Optional的创建。Optional有三种实例化的方式:

①创建空Optional对象 empty();
②创建非空Optional对象,of();这里的容器中的对象一定不能为空,否者会抛出异常;
③创建非空或空Optional对象,ofNullable();

2.2、使用filter()进行source对象是否是List集合; filter()条件判断,返回optional容器,若结果为true则返回带有对象的Optional容器,否则返回空容器;

2.3、使用map()对内部细节业务逻辑进行计算;这里不对map()方法进行详细分析了,网上有很多资料,大家可以自己去看;这里给大家总结几点重要的点:(看黑板)

①map()接收的是上一层逻辑返回的容器中的对象值(类型),都必须一致;否则无法使用map()方法
②map()方法是主动为传递过来的对象创建Optional容器的,这跟flatMap()方法又却别;
③map()方法首先对容器内的对象进行判断,若对象为空,则直接返回空的Optional容器对象,若不为空,则直接将计算后的值重新创建新的Optional容器进行返回

2.4、orElse()方法返回默认值,Optional中的这个方法,就可以认为这个方法就是返回默认值的,可以理解为,如果为空,则直接返回默认值,不为空,则返回计算值;(这里需要强调,orElse()方法,在执行逻辑中,始终都是执行的,不管你当前Optional容器中的对象是不是空的,都会执行orElse()方法中的逻辑;如果为空执行,不为空不执行,需要使用orElseGet()方法);


接下来我们填充细节逻辑:

//这里为空则返回空对象 这里表示 如果source不为空则继续执行,若为空直接返回默认值
Optional.ofNullable(source)
		 //若source为list类型,这继续执行,若不为list类型则直接返回默认值
         .filter(fSource -> fSource instanceof List)
         //若source为list类型执行计算
         .map(mSource -> {
         	//这里确定source为list类型,则直接强转list,因为不确定泛型,所以用?来表示
             List<?> objectList = (List<?>) source;
			//取出list的第一个元素,这里无法得知,list中的元素是否为空,
			//或者其元素的中的属性值是否为空,所以还需要使用Optional容器进行规避NPE,
			//findFirst()方法返回的就是一个Optional容器 所以我们直接使用Map进行计算
			return objectList
                    .stream()
                    .findFirst()
                    //此时map中的firstSource为list中的第一条元素对象;
                    .map(firstSource ->
                    //这里需要强调,由于Optional中的对象不能同级进行传递,上面技术分析中有说到这一点;                            
                    	FunctionBuilder
                                    //创建IF函数实例
                                    .returnIf(new HashMap<Object, FunctionReturn<String>>())
                                    //添加函数条件以及执行函数
                                    .addReturn(CouponDetail.class, () -> ifSearchCouponDetail(source))
                                    //添加函数条件以及执行函数
                                    .addReturn(com.jd.open.api.sdk.domain.order
                                            .OrderQueryJsfService.response.enGet
                                            .CouponDetail.class, () -> ifEnGetCouPonDetail(source))
                                    //实际入参对象
                                    .doIfInstance(firstSource)
                                    //默认值
                                    .defaultValue(null)
                    ).orElse(null);
         })
         //这里返回默认值
         .orElse(String.valueOf(platformDiscount));

将具体的业务代码抽离成方法.

ifEnGetCouPonDetail(),如果是EnGetCouPonDetail类型走此方法执行业务
ifSearchCouponDetail(),如果是SearchCouponDetail类型的走此方法执行业务

   @NotNull
    private String ifEnGetCouPonDetail(Object source) {
        List<com.jd.open.api.sdk.domain.order.OrderQueryJsfService.response.
                enGet.CouponDetail> couponDetails =
                ListsUtil.castList(source, com.jd.open.api.sdk.domain.order.
                        OrderQueryJsfService.response.enGet.CouponDetail.class);
        double optionalDiscount = 0.0;
        for (com.jd.open.api.sdk.domain.order
                .OrderQueryJsfService.response.enGet
                .CouponDetail couponDetail : couponDetails) {
            optionalDiscount += Optional.ofNullable(couponDetail)
                    .map(com.jd.open.api.sdk.domain.order.OrderQueryJsfService.
                            response.enGet.CouponDetail::getCouponPrice)
                    .map(Double::parseDouble)
                    .orElse(optionalDiscount);
        }
        return String.valueOf(optionalDiscount);
    }
 @NotNull
    private String ifSearchCouponDetail(Object source) {
        List<CouponDetail> couponDetails =
                ListsUtil.castList(source, CouponDetail.class);
        double optionalDiscount = 0.0;
        for (CouponDetail couponDetail : couponDetails) {
            optionalDiscount += Optional.ofNullable(couponDetail)
                    .map(CouponDetail::getCouponPrice)
                    .map(Double::parseDouble)
                    .orElse(optionalDiscount);
        }
        return String.valueOf(optionalDiscount);
    }

对以上代码技术点进行分析:

在以上代码看来.逻辑清晰,结构简单,可阅读性强;这里重点说一下FunctionBuilder这个函数逻辑运算,这里是我自己封装的复杂逻辑运算的执行器,这里不能完全使用Optional来消除if,原因有两点如下:

①、Optional只能对容器中的对象是否为空,做为条件进行逻辑计算,但不能对其他条件逻辑进行判断
②、Optional对同级逻辑是不能使用同一个对象的, 比如你使用了两个map()方法,第一个map中是User对象,第二个map()方法中的Optional容器中的对象是第一个map(),计算后返回的对象,不可能是同一个User对象了,很明显不符合这里的业务逻辑;


这里我也贴出封装的部分源码

FunctionBuilder类

/**
 * @Author: yangjiahui
 * @Description: TODO  构建if函数的创建工具类
 * @Date: 2021/03/22 14:15
 */
public class FunctionBuilder {
    /**
     * 创建无返回值if函数
     *
     * @param map Map<条件,执行函数>
     * @param  条件参数类型
     * @return if函数实例
     * @see Map
     */
    public static <K> IfVoidFunction<K> voidIf(Map<K, Function> map) {
        return IfVoidFunction.<K>builder().buildVoidIf(map).build();
    }

    public static <K, T> IfFunctionReturn<K, T> returnIf(Map<K, FunctionReturn<T>> returnMap) {
        return IfFunctionReturn.<K, T>builder().buildReturnIf(returnMap).build();
    }
}

IfFunctionReturn类

这里是带有返回值的if函数

/**
 * @Author: yangjiahui
 * @Description: TODO 带有返回值的if函数实例
 * @Date: 2021/03/05 5:43 下午
 */
public class IfFunctionReturn<K, T> {

    private Map<K, FunctionReturn<T>> mapReturn;

    /**
     * 如果不为null,则为该值;
     * 否则为false。如果为null,则表示不存在任何值
     */
    private T result;


    public void setMap(Map<K, FunctionReturn<T>> mapReturn) {
        this.mapReturn = mapReturn;
    }

    public IfFunctionReturn() {
    }

    /**
     * 添加条件 有返回值函数
     *
     * @param key            需要验证的条件(key)
     * @param functionReturn 要执行的方法
     * @return this.
     */
    public IfFunctionReturn<K, T> addReturn(K key, FunctionReturn<T> functionReturn) {
        this.mapReturn.put(key, functionReturn);
        return this;
    }

    /**
     * 批量添加条件 有返回值函数
     *
     * @param key            需要验证的条件(key)
     * @param functionReturn 要执行的方法
     * @return this.
     */
    @SafeVarargs
    public final IfFunctionReturn<K, T> addReturnAll(FunctionReturn<T> functionReturn, K... key) {
        for (K element : key) {
            if (ObjectUtil.isNotEmpty(element)) {
                this.mapReturn.put(element, functionReturn);
            }
        }
        return this;
    }

    /**
     * 确定key是否存在,如果存在,则执行value中的函数。
     * 

* 函数有返回值 *

* 若key为对象类型 则需重写 equal方法和hashcode方法 * key值和map中的key值必须一致 * * @param key the key need to verify */ public IfFunctionReturn<K, T> doIfEqualReturn(@NotNull K key) { if (this.mapReturn.containsKey(key)) { this.result = mapReturn.get(key).invokeReturn(); return this; } return this; } /** * 确定key是否存在,如果存在,则执行value中的函数。若不存在执行默认函数 *

* 函数无返回值 增加默认执行函数 若传入条件皆不符合 则执行默认函数 *

* 若key为对象类型 则需重写 equal方法和hashcode方法 * key值和map中的key值必须一致 * * @param key the key need to verify 条件值 */ public IfFunctionReturn<K, T> doIfEqualReturn(@NotNull K key, @NotNull FunctionReturn<T> defaultFunction) { boolean doesItContain = this.mapReturn.containsKey(key); if (doesItContain) { this.result = mapReturn.get(key).invokeReturn(); return this; } this.result = defaultFunction.invokeReturn(); return this; } /** * 比较对象类型是否一致 若一致则执行函数 *

* 注意:此方法仅支持 同一个classloader加载两个类使用 *

* 函数无返回值 * * @param key the key need to verify 条件值 */ public IfFunctionReturn<K, T> doIfInstance(@NotNull K key) { mapReturn.forEach((setKey, value) -> { if (setKey.equals(key.getClass())) { this.result = value.invokeReturn(); } }); return this; } /** * 比较对象类型是否一致 若一致则执行函数 若不一致 执行默认函数 *

* 注意:此方法仅支持 同一个classloader加载两个类使用 *

* 函数无返回值 增加默认执行函数 若传入条件皆不符合 则执行默认函数 * * @param key the key need to verify 条件值 */ public IfFunctionReturn<K, T> doIfInstance(@NotNull K key, @NotNull FunctionReturn<T> defaultFunction) { boolean execution = true; for (Map.Entry<K, FunctionReturn<T>> entry : mapReturn.entrySet()) { if (entry.getKey().equals(key.getClass())) { this.result = entry.getValue().invokeReturn(); execution = false; } } if (execution) { this.result = defaultFunction.invokeReturn(); } return this; } /** * 获取当前函数 返回值 *

* 警告: 返回值可能为 null * * @return 返回对象 */ public T get() { if (result == null) { throw new NoSuchElementException("返回值对象为空!"); } return result; } public T defaultValue(T other) { return result != null ? result : other; } /** * 执行完毕之后自动刷新 map 防止出现数据冲突 */ public IfFunctionReturn<K, T> refresh() { this.mapReturn.clear(); return this; } /** * 创建桥接实例 * * @param 条件类型泛型 * @param 返回值类型泛型 */ public static <K, T> ResIfFunctionReturn<K, T> builder() { return new ResIfFunctionReturn<>(); } public static class ResIfFunctionReturn<K, T> { private Map<K, FunctionReturn<T>> mapReturn; private ResIfFunctionReturn() { } public ResIfFunctionReturn<K, T> buildReturnIf(Map<K, FunctionReturn<T>> mapReturn) { this.mapReturn = mapReturn; return this; } public IfFunctionReturn<K, T> build() { IfFunctionReturn<K, T> functionReturn = new IfFunctionReturn<>(); functionReturn.setMap(mapReturn); return functionReturn; } } }

FunctionReturn函数接口

用于执行业务逻辑的接口封装


/**
 * @Author: yangjiahui
 * @Description: TODO 有返回值执行函数
 * @Date: 2020/12/22 4:20 下午
 */
@FunctionalInterface
public interface FunctionReturn<T> {
    /**
     * 有返回值的函数
     * @return
     */
    T invokeReturn();
}

其实这个if函数封装很简单,不过多的赘述。


三、复盘

接下来我们看下优化前的代码 和优化后的;

优化前:11个if判断逻辑(代码进行了业务删减)

public Object convert(Object destination, Object source, Class<?> destinationClass, Class<?> sourceClass) {
        if (ObjectUtil.isEmpty(source)) {}
        if (ObjectUtil.isNotEmpty(source) && source instanceof List) {
            if (optional.isPresent()) {
                if (object instanceof CouponDetail) {
                    if (ObjectUtil.isNotEmpty(couponDetails)) {
                            if (ObjectUtil.isEmpty(couponDetail)) {}
                            if (ObjectUtil.isNotEmpty(couponDetail){}
                        }
                        return String.valueOf(platformDiscount);
                    }
                }
                if (object instanceof com...enGet.CouponDetail) {
                    if (ObjectUtil.isNotEmpty(couponDetails)) {
                            if (ObjectUtil.isEmpty(couponDetail)) {}
                            if (ObjectUtil.isNotEmpty(couponDetail)
                        }
                        return String.valueOf(platformDiscount);
                    }
                }
            }
            return String.valueOf(platformDiscount);
        }
        return String.valueOf(platformDiscount);
    }

优化后:

Optional.ofNullable(source)
         .filter(fSource -> fSource instanceof List)
         .map(mSource -> {
             List<?> objectList = (List<?>) source;
			return objectList
                    .stream()
                    .findFirst()
                    .map(firstSource -> 
                    	FunctionBuilder
                                    .returnIf(new HashMap<Object, FunctionReturn<String>>())
                                    .addReturn(CouponDetail.class, () -> ifSearchCouponDetail(source))
                                    .addReturn(com...enGet.CouponDetail.class, () -> ifEnGetCouPonDetail(source))
                                    .doIfInstance(firstSource)
                                    .defaultValue(null)
                    ).orElse(null);
         })
         .orElse(String.valueOf(platformDiscount));

优点不用多讲…一幕了然呀!!!

敲代码容易,思想不易,转载请标注出处,谢谢诸神…

***江山父老能容我,不使人间造孽钱.***

你可能感兴趣的:(java,filter,编程语言)