• 请不要在回答技术问题时复制粘贴 AI 生成的内容
wleexi
V2EX  ›  程序员

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

  •  
  •   wleexi · Feb 19, 2019 · 12035 views
    This topic created in 2814 days ago, the information mentioned may be changed or developed.

    场景 保存信息时,发现手机号重复返回 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 replies  •  2019-02-20 10:04:07 +08:00
    si
    si
    Feb 19, 2019❤️5
    1
    不知道大佬怎么写的,要是我一般会写成连续的。
    if() return;
    if() return;
    if() return;
    whx20202
    whx20202
    Feb 19, 2019❤️4
    2
    代码整洁之道原则:提前 return

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

    如果你的多层 if else 都有代码块,那会复杂一点,但是也可以优化
    yesterdaysun
    yesterdaysun
    Feb 19, 2019❤️1
    3
    试试 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());
    }
    ```
    LxExExl
    LxExExl
    Feb 19, 2019 via iPhone
    4
    返回 true 要么为空 要么成员唯一且和输入相等

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

    else return false
    danliuwo
    danliuwo
    Feb 19, 2019
    5
    switch
    wutiantong
    wutiantong
    Feb 19, 2019❤️3
    6
    return CollectionUtils.isEmpty(supplierList) || supplierList.size() == BaseConstants.INT_ONE && Objects.equals(supplierList.get(BaseConstants.INT_ZERO).getId(), param.getId());

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

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

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

    0 和 1 本身就有自带语议了,不属于魔数,没必要搞个这么长的常量吧
    fuxiuyin
    fuxiuyin
    Feb 19, 2019
    21
    之前在哪看到一个感觉挺不错的,记得是 windows SDK 里面的风格?
    // 初始化资源
    int result = 0;
    while(1)
    {
    if(xxxx)
    break;
    if(xxxx)
    break;
    // logical
    result = 1;
    break;
    }
    // 释放资源
    return result;
    确保一个函数一个 return,将来该起来比较容易看,也不会到处都是 return 导致忘记释放某些资源。
    wutiantong
    wutiantong
    Feb 19, 2019
    22
    @wleexi 这个写法完全符合语法而且也充分表达了逻辑含义,根本算不上什么奇技淫巧,为什么可读性就不高了呢?
    6diyipi
    6diyipi
    Feb 19, 2019
    23
    ```
    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;
    }
    ```
    这样?
    6diyipi
    6diyipi
    Feb 19, 2019❤️1
    24
    写错一个条件了, 发出去的居然不能编辑了。。

    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;
    }
    wleexi
    wleexi
    OP
    Feb 19, 2019
    25
    @wutiantong 表达式太长了?
    wutiantong
    wutiantong
    Feb 19, 2019
    26
    @wleexi 那就分行呗。
    lhx2008
    lhx2008
    Feb 19, 2019
    27
    #3 @yesterdaysun 是我喜欢的风格。
    hugedeffing
    hugedeffing
    Feb 19, 2019
    28
    用工厂模式,或者继承来做啊,if 不就是多个条件嘛
    Sapp
    Sapp
    Feb 19, 2019
    29
    你这个反向 return 就行了,有啥优化难度
    Kylinsun
    Kylinsun
    Feb 19, 2019 via iPhone
    30
    用断言。
    zzzzzzZ
    zzzzzzZ
    Feb 19, 2019❤️1
    31
    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,也能增加可读性
    Enivel
    Enivel
    PRO
    Feb 19, 2019
    32
    do while + break 方案比较舒服, return 太多很混乱 一个函数一个出口一个入口最好
    zzzzzzZ
    zzzzzzZ
    Feb 19, 2019
    33
    总感觉你的逻辑哪里有点不对劲,可能跟参数和变量太奇葩有关,说不上来
    我算了下按照你的描述漏了一个分支在最后,但是脑袋有点晕,最后少一个 if-else 你自己看看吧
    JRay
    JRay
    Feb 19, 2019
    34
    卫语句?
    ttvast
    ttvast
    Feb 19, 2019
    35
    抛异常
    yetone
    yetone
    Feb 19, 2019
    36
    防御式编程
    nekoneko
    nekoneko
    Feb 19, 2019
    37
    BaseConstants.INT_ZERO 简直是魔鬼。。。。
    vicvinc
    vicvinc
    Feb 19, 2019
    38
    最简单的
    vicvinc
    vicvinc
    Feb 19, 2019❤️1
    39
    ctl+enter 直接发送了(🤦‍♂️
    补充一下:

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

    可以改写成:

    if (条件 1&&条件 2&&...&&条件 N)
    shot
    shot
    Feb 19, 2019❤️1
    40
    像这种判断条件不算太多的情况,写成 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));
    }
    ```
    jmk92
    jmk92
    Feb 19, 2019
    41
    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;
    }
    biossun
    biossun
    Feb 19, 2019
    42
    只是展开嵌套的话,可以写成:

    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;
    }
    codingKingKong
    codingKingKong
    Feb 19, 2019
    43
    是不是大概这样?
    ```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();
    }
    ```
    hv3s1
    hv3s1
    Feb 19, 2019
    44
    if 里面疯狂套三元。 会不会被接手的人打
    ArcherD
    ArcherD
    Feb 19, 2019 via Android
    45
    用 java 12 的 switch expression, pattern match 还要再过几个版本才能支持
    ysc3839
    ysc3839
    Feb 19, 2019 via Android❤️1
    46
    @fuxiuyin 可以改成 do {} while (0);
    这种写法在 C 语言里面挺常见的吧?算是把 while 当 goto 用。
    kaneg
    kaneg
    Feb 19, 2019 via iPhone
    47
    把比较饶人的判断语句写成方法,比如那个 INTONE,不去跟设计的人确认是很难理解为什么那么判断,可以用一个有意义的方法名,比如 isFirstNumber ()
    ITACHIJAMES
    ITACHIJAMES
    Feb 19, 2019❤️1
    48
    do{
    }while(false)
    结合 break 将多级嵌套转化成同级并列
    msg7086
    msg7086
    Feb 19, 2019
    49
    我们十年前用的 Resharper 辅助重构,可以反转 if 来简化代码,只要点几下就行了。
    lxfxf
    lxfxf
    Feb 20, 2019
    50
    @ArcherD 那不就是 scala 嘛,逃
    guanhui07
    guanhui07
    Feb 20, 2019
    51
    提前 return
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2500 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 93ms · UTC 15:20 · PVG 23:20 · LAX 07:20 · JFK 10:20
    ♥ Do have faith in what you're doing.