首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  程序员

代码 if 嵌套过多,怎么优化比较好

  •  
  •   wleexi · 63 天前 · 5614 次点击
    这是一个创建于 63 天前的主题,其中的信息可能已经有所发展或是发生改变。

    场景 保存信息时,发现手机号重复返回 false 编辑时,手机号与自身之外的手机号重复,返回 false, 没有重复,或者编辑时号码不变返回 true

        private boolean checkMobileExists(Long shopId, CreateSupplierParam param) {
            List<Supplier> supplierList = this.get(shopId, param.getContactMobile());
            if (!CollectionUtils.isEmpty(supplierList)) {
                if (supplierList.size() == BaseConstants.INT_ONE) {
                    Long existId = supplierList.get(BaseConstants.INT_ZERO).getId();
                    if (Objects.equals(existId, param.getId())) {
                        return true;
                    }
                }
                return false;
            }
            return true;
        }
    
    51 回复  |  直到 2019-02-20 10:04:07 +08:00
        1
    si   63 天前   ♥ 5
    不知道大佬怎么写的,要是我一般会写成连续的。
    if() return;
    if() return;
    if() return;
        2
    whx20202   63 天前   ♥ 4
    代码整洁之道原则:提前 return

    if(不满足):
    return
    if (不满足):
    return

    如果你的多层 if else 都有代码块,那会复杂一点,但是也可以优化
        3
    yesterdaysun   63 天前   ♥ 1
    试试 guard clause

    ```java
    private boolean checkMobileExists(Long shopId, CreateSupplierParam param) {
    List<Supplier> supplierList = this.get(shopId, param.getContactMobile());
    if (CollectionUtils.isEmpty(supplierList)) {
    return true;
    }
    if (supplierList.size() != BaseConstants.INT_ONE) {
    return false;
    }
    Long existId = supplierList.get(BaseConstants.INT_ZERO).getId();
    return Objects.equals(existId, param.getId());
    }
    ```
        4
    LxExExl   63 天前 via iPhone
    返回 true 要么为空 要么成员唯一且和输入相等

    if (list is null || list.size() == 1 && list.getFirst() == input) return true

    else return false
        5
    danliuwo   63 天前
    switch
        6
    wutiantong   63 天前   ♥ 3
    return CollectionUtils.isEmpty(supplierList) || supplierList.size() == BaseConstants.INT_ONE && Objects.equals(supplierList.get(BaseConstants.INT_ZERO).getId(), param.getId());

    一条语句搞定,假如你搞不清||和&&的优先级关系,就自己加个括号吧。
        7
    taaaang   63 天前
    可以看看《重构 改善既有代码的设计》
        8
    BingoXuan   63 天前   ♥ 8
    连续 if 可读性更高,更容易理解。可读性和代码行数不是成反比的,有时候提高可读性,你需要更多的代码。虽然看起来很冗余,但实际上会让阅读代码的人理解起来更加清晰。

    如果 python 这种缩进严格的语言,而你同事喜欢这样嵌套写。淘宝买把游标卡尺来 review 会比较好。
        9
    felixlong   63 天前
    你这 code 有 bug 啊。supplierList 为空为什么返回的是 true?
        10
    yesterdaysun   63 天前
    BaseConstants.INT_ONE 和 BaseConstants.INT_ZERO 应该就是 int 0 和 1 吧, 需要定一个常数吗?

    单单为了避免魔数也不需要做到这个程度吧
        11
    MrUser   63 天前
    exists = false;
    if (!exists) {}
    if (!exists) {}
    if (!exists) {}
    return exists;
        12
    kaedea   63 天前 via Android
    scoping function 了解一下
        13
    wleexi   63 天前
    @felixlong 额 不是的。为空表示新号码,可以通过检查的
        14
    qq976739120   63 天前   ♥ 1
    典型的箭头型代码块....如何解决楼上已经说得很好了
        15
    AngryPanda   63 天前   ♥ 1
    尽早 return
        16
    Raymon111111   63 天前
    提早 return 是正确答案.
        17
    wleexi   63 天前
    @wutiantong 想过这种,但是考虑了可读性可能不是特别高
        18
    wleexi   63 天前
    @qq976739120 不太明白
        19
    billgreen1   63 天前
    表驱动,代码大全里面提到的
        20
    Mutoo   63 天前
    BaseConstants.INT_ONE
    BaseConstants.INT_ZERO

    0 和 1 本身就有自带语议了,不属于魔数,没必要搞个这么长的常量吧
        21
    fuxiuyin   63 天前
    之前在哪看到一个感觉挺不错的,记得是 windows SDK 里面的风格?
    // 初始化资源
    int result = 0;
    while(1)
    {
    if(xxxx)
    break;
    if(xxxx)
    break;
    // logical
    result = 1;
    break;
    }
    // 释放资源
    return result;
    确保一个函数一个 return,将来该起来比较容易看,也不会到处都是 return 导致忘记释放某些资源。
        22
    wutiantong   63 天前
    @wleexi 这个写法完全符合语法而且也充分表达了逻辑含义,根本算不上什么奇技淫巧,为什么可读性就不高了呢?
        23
    6diyipi   63 天前
    ```
    private boolean checkMobileExists(Long shopId, CreateSupplierParam param) {
    List<Supplier> supplierList = this.get(shopId, param.getContactMobile());

    if (!CollectionUtils.isEmpty(supplierList) && supplierList.size() == BaseConstants.INT_ONE) { return false; }

    if (supplierList.size() != BaseConstants.INT_ONE) { return false; }

    Long existId = supplierList.get(BaseConstants.INT_ZERO).getId();

    if (!Objects.equals(existId, param.getId())) { return false; }

    return true;
    }
    ```
    这样?
        24
    6diyipi   63 天前   ♥ 1
    写错一个条件了, 发出去的居然不能编辑了。。

    private boolean checkMobileExists(Long shopId, CreateSupplierParam param) {
    List<Supplier> supplierList = this.get(shopId, param.getContactMobile());

    if (!CollectionUtils.isEmpty(supplierList) && supplierList.size() != BaseConstants.INT_ONE) { return false; }

    if (supplierList.size() != BaseConstants.INT_ONE) { return false; }

    Long existId = supplierList.get(BaseConstants.INT_ZERO).getId();

    if (!Objects.equals(existId, param.getId())) { return false; }

    return true;
    }
        25
    wleexi   63 天前
    @wutiantong 表达式太长了?
        26
    wutiantong   63 天前
    @wleexi 那就分行呗。
        27
    lhx2008   63 天前
    #3 @yesterdaysun 是我喜欢的风格。
        28
    hugedeffing   63 天前
    用工厂模式,或者继承来做啊,if 不就是多个条件嘛
        29
    Sapp   63 天前
    你这个反向 return 就行了,有啥优化难度
        30
    Kylinsun   63 天前 via iPhone
    用断言。
        31
    zzzzzzZ   63 天前   ♥ 1
    private boolean checkMobileExists(Long shopId, CreateSupplierParam param) {
    List<Supplier> supplierList = this.get(shopId, param.getContactMobile());
    if(supplierList == null || supplierList.size() == BaseConstants.INT_ONE){
    return false;
    }
    Long existId = supplierList.get(BaseConstants.INT_ZERO).getId();
    if (CollectionUtils.isEmpty(supplierList) && Objects.equals(existId, param.getId())) {
    return true;
    }
    }

    分支结构直接 return,某些场合可以无视嵌套前提(像行 3 和行 4 根本不相关)
    分开写是基本功,增加可读性
    如果不想写逻辑运算符也可以分开写多个 if,也能增加可读性
        32
    LevineChen   63 天前
    do while + break 方案比较舒服, return 太多很混乱 一个函数一个出口一个入口最好
        33
    zzzzzzZ   63 天前
    总感觉你的逻辑哪里有点不对劲,可能跟参数和变量太奇葩有关,说不上来
    我算了下按照你的描述漏了一个分支在最后,但是脑袋有点晕,最后少一个 if-else 你自己看看吧
        34
    JRay   63 天前
    卫语句?
        35
    ttvast   63 天前
    抛异常
        36
    yetone   63 天前
    防御式编程
        37
    nekoneko   63 天前
    BaseConstants.INT_ZERO 简直是魔鬼。。。。
        38
    vicvinc   63 天前
    最简单的
        39
    vicvinc   63 天前   ♥ 1
    ctl+enter 直接发送了(🤦‍♂️
    补充一下:

    if (条件 1)
    if (条件 2)
    ...
    if(条件 N)

    可以改写成:

    if (条件 1&&条件 2&&...&&条件 N)
        40
    shot   63 天前   ♥ 1
    像这种判断条件不算太多的情况,写成 if-else 问题不大,可读性好且符合团队编码规范就行。

    如果判断条件比较多(我个人习惯是 5 个及以上),可以把每个判断逻辑写成一个 lambda 函数,再循环调用它们。
    ```
    private boolean checkMobileExists(Long shopId, CreateSupplierParam param) {
    List<Supplier> supplierList = this.get(shopId, param.getContactMobile());

    List<Predicate<List<Supplier>>> predicates = Arrays.asList(
    CollectionUtils::isEmpty,
    suppliers -> suppliers.size() == BaseConstants.INT_ONE &&
    suppliers.stream().anyMatch(it -> Objects.equals(it.getId(), param.getId()))
    // more predicates here
    );

    return predicates.stream().anyMatch(it -> it.test(supplierList));
    }
    ```
        41
    jmk92   63 天前
    private boolean checkMobileExists(Long shopId, CreateSupplierParam param) {
    List<Supplier> supplierList = this.get(shopId, param.getContactMobile());
    if (CollectionUtils.isEmpty(supplierList)) return false;
    if (supplierList.size() != BaseConstants.INT_ONE) return false;
    Long existId = supplierList.get(BaseConstants.INT_ZERO).getId();
    if (Objects.equals(existId, param.getId())==false) return false;
    return true;
    }
        42
    biossun   63 天前
    只是展开嵌套的话,可以写成:

    private boolean checkMobileExists(Long shopId, CreateSupplierParam param) {
    List<Supplier> supplierList = this.get(shopId, param.getContactMobile());

    if (CollectionUtils.isEmpty(supplierList)) {
    return true;
    }

    if (supplierList.size() == BaseConstants.INT_ONE &&
    Objects.equals(supplierList.get(BaseConstants.INT_ZERO).getId(), param.getId())) {
    return true;
    }

    return false;
    }
        43
    codingKingKong   63 天前
    是不是大概这样?
    ```java
    private boolean checkMobileExists(Long shopId, String mobile, Long id) {
    List<Long> supplierList = this.get(shopId, mobile);

    if (!CollectionUtils.isEmpty(supplierList))
    return true;
    if (supplierList.size() != 1)
    return false;
    Long existId = supplierList.get(0);
    return Objects.equals(existId, id);

    }

    private List<Long> get(long shopId, String mobile){
    return Collections.emptyList();
    }
    ```
        44
    hv3s1   63 天前
    if 里面疯狂套三元。 会不会被接手的人打
        45
    ArcherD   63 天前 via Android
    用 java 12 的 switch expression, pattern match 还要再过几个版本才能支持
        46
    ysc3839   63 天前 via Android   ♥ 1
    @fuxiuyin 可以改成 do {} while (0);
    这种写法在 C 语言里面挺常见的吧?算是把 while 当 goto 用。
        47
    kaneg   63 天前 via iPhone
    把比较饶人的判断语句写成方法,比如那个 INTONE,不去跟设计的人确认是很难理解为什么那么判断,可以用一个有意义的方法名,比如 isFirstNumber ()
        48
    ITACHIJAMES   63 天前   ♥ 1
    do{
    }while(false)
    结合 break 将多级嵌套转化成同级并列
        49
    msg7086   63 天前
    我们十年前用的 Resharper 辅助重构,可以反转 if 来简化代码,只要点几下就行了。
        50
    lxfxf   63 天前
    @ArcherD 那不就是 scala 嘛,逃
        51
    guanhui07   62 天前
    提前 return
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   944 人在线   最高记录 5043   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 22ms · UTC 22:14 · PVG 06:14 · LAX 15:14 · JFK 18:14
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1