前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >命令式到函数式编程

命令式到函数式编程

作者头像
lambeta
发布2018-08-17 11:41:16
3530
发布2018-08-17 11:41:16
举报
文章被收录于专栏:编舟记编舟记

逻辑判断和返回 vs. Optional

应用场景:当我们用到 if-elseif-else 的时候,可以考虑使用 Optional 语义。 举例说明:

代码语言:javascript
复制
if(id != null) {
    return find1(id);
} 

if(name != null) {
    return find2(name);
}

if(type != null) {
    return find3(type);
}

语义化

代码语言:javascript
复制
Supplier<?> chain = find(() -> find1(id), id)
                     .orElseGet(() -> find(() -> find2(name), name)
                       .orElse(() -> find3(type), type)));

Optional<Supplier<?>> find(Supplier s, Condtion... conditions) {
    return Stream.of(conditions).anyMatch(c -> c == null) ? Optional.empty() : Optinal.of(s);
}

去掉了不必要的Supplier,让代码清晰化

代码语言:javascript
复制
static Optional<Supplier<?>> or(Optional<Supplier<?>> hl, Optional<Supplier<?>> hr) {
    return hl.isPresent() ? hl : hr;
}

Supplier<?> chain =
                    or(
                        or(find(() -> find1(id), id),
                           find(() -> find2(name), name)),
                        find(() -> find3(type), type));     

进一步思考,上述的场景可以简化为: 如果值存在,那么拿来映射成另一个可能的存在;否则,返回不可能的存在。

代码语言:javascript
复制
ofNullalbe(id)
    .map(id -> find1(id))
    .map(r -> nonNull(r) ? r : find2(name)))
    .map(r -> nonNull(r) ? r : find3(type)))
    .orElse(T t);

假如我们有Optional.orGet函数,那就也可以这样实现

代码语言:javascript
复制
static <U> Optional<U> orGet(Supplier<? extends U> other) {
    return isPresent() ? this : Optional.ofNullable(other.get());
}

ofNullalbe(id)
    .map(id -> find1(id))
    .orGet(() -> find2(name))
    .orGet(() -> find3(type))
    .orElse(T t);

不过,上面的实现方式缺失了 if not null then else 的表达,进一步改进:

代码语言:javascript
复制
ofNullalbe(id)
    .map(id -> find1(id))
    .orGet(() -> ofNullable(name).map(name -> find2(name)))
    .orGet(() -> ofNullable(type).map(type -> find3(type)))
    .orElse(T t);
    
static <U> Optional<U> orGet(Supplier<? extends Optional<U>> other) {
    return isPresent() ? this : Optional.ofNullable(other.get());
}    

完毕。

语句重构到表达式

if-else -> Optional

代码语言:javascript
复制
Optional<Rule> rule = ruleOf(id);
if(rule.isPresent()) {
    return transform(rule.get());
} else {
    throw new RuntimeException();
}

public Rule transform(Rule rule) {
    return Rule.builder()
                .withName("No." + rule.getId())
                .build();
}

这是典型的语句可以重构到表达式的场景,关键是怎么重构呢? 第一步,调转if

代码语言:javascript
复制
Optional rule = ruleOf(id);

if(!rule.isPresent()) {
    throw new RuntimeException();
} 
   
return transform(rule.get());

第二步,Optional.map函数

代码语言:javascript
复制
...
return rule.map(r -> transform(r)).get();

第三步,inline transform函数

代码语言:javascript
复制
...
rule.map(r -> Rule.builder()
                    .withName("No." + r.getId())
                    .build()).get();

第四步,Optional.orElseThrow函数

代码语言:javascript
复制
...
rule.map(r -> Rule.builder()
                    .withName("No." + r.getId())
                    .build())
    .orElseThrow(() -> new RuntimeException());

第五步,注if释语句中的throw new RuntimeException()

代码语言:javascript
复制
if(!rule.isPresent()) {
   // throw new RuntimeException();
} 

这时候发现语句中为空,即可将整个语句删除。可以考虑inline rule

代码语言:javascript
复制
ruleOf(id).map(r -> Rule.builder()
                    .withName("No." + r.getId())
                    .build())
    .orElseThrow(() -> new RuntimeException());

完毕。

重复try...catch->Closure

代码语言:javascript
复制
// 结构性重复
if(meta.hasURI()) {
    try {
        return deciderOfURI.decide(attr);
    } catch (CustomizedException e) {
        //...
        LOGGER.error(e);
    } catch (Exception e) {
        //...
        LOGGER.error(e);
    }
}

if(meta.hasAction()) {
    try {
        return deciderOfAction.decide(attr);
    } catch (CustomizedException e) {
        //...
        LOGGER.error(e);
    } catch (Exception e) {
        //...
        LOGGER.error(e);
    }
}

这个结构性重复,一般想到的就是把表达式提成参数,但是由于表达式是预先求值的顺序,直接抽成参数意味着表达式求值时抛出的异常不能被捕获。所以使用functional parameter重构手法。 第一步,extract method

代码语言:javascript
复制
pubic Decision tryDecide() {
    if(meta.hasURI()) {
        try {
            return deciderOfURI.decide(attr);
        } catch (CustomizedException e) {
            //...
            LOGGER.error(e);
        } catch (Exception e) {
            //...
            LOGGER.error(e);
        }
    }
}

第二步,functional parameter

代码语言:javascript
复制
pubic Decision tryDecide(Supplier<Decision> decider) {
    if(meta.hasURI()) {
        try {
            return decider.get();
        } catch (CustomizedException e) {
            //...
            LOGGER.error(e);
        } catch (Exception e) {
            //...
            LOGGER.error(e);
        }
    }
}

第三步,替换重复

代码语言:javascript
复制
// 结构性重复
if(meta.hasURI()) {
    return tryDecide(() -> deciderOfAction.decide(attr));
}

if(meta.hasAction()) {
    return tryDecide(() -> deciderOfURI.decide(attr));
}

完毕。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.11.22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 逻辑判断和返回 vs. Optional
  • 语句重构到表达式
    • if-else -> Optional
      • 重复try...catch->Closure
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档