代码 if 嵌套过多,怎么优化比较好 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
请不要在回答技术问题时复制粘贴 AI 生成的内容
wleexi

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

  •  
  •   wleexi Feb 19, 2019 11540 views
    This topic created in 2626 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
        1
    si  
       Feb 19, 2019   5
    不知道大佬怎么写的,要是我一般会写成连续的。
    if() return;
    if() return;
    if() return;
    whx20202
        2
    whx20202  
       Feb 19, 2019   4
    代码整洁之道原则:提前 return

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

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

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

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

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

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

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

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

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

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

    可以改写成:

    if (条件 1&&条件 2&&...&&条件 N)
    shot
        40
    shot  
       Feb 19, 2019   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));
    }
    ```
    jmk92
        41
    jmk92  
       Feb 19, 2019
    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
        42
    biossun  
       Feb 19, 2019
    只是展开嵌套的话,可以写成:

    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
        43
    codingKingKong  
       Feb 19, 2019
    是不是大概这样?
    ```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
        44
    hv3s1  
       Feb 19, 2019
    if 里面疯狂套三元。 会不会被接手的人打
    ArcherD
        45
    ArcherD  
       Feb 19, 2019 via Android
    用 java 12 的 switch expression, pattern match 还要再过几个版本才能支持
    ysc3839
        46
    ysc3839  
       Feb 19, 2019 via Android   1
    @fuxiuyin 可以改成 do {} while (0);
    这种写法在 C 语言里面挺常见的吧?算是把 while 当 goto 用。
    kaneg
        47
    kaneg  
       Feb 19, 2019 via iPhone
    把比较饶人的判断语句写成方法,比如那个 INTONE,不去跟设计的人确认是很难理解为什么那么判断,可以用一个有意义的方法名,比如 isFirstNumber ()
    ITACHIJAMES
        48
    ITACHIJAMES  
       Feb 19, 2019   1
    do{
    }while(false)
    结合 break 将多级嵌套转化成同级并列
    msg7086
        49
    msg7086  
       Feb 19, 2019
    我们十年前用的 Resharper 辅助重构,可以反转 if 来简化代码,只要点几下就行了。
    lxfxf
        50
    lxfxf  
       Feb 20, 2019
    @ArcherD 那不就是 scala 嘛,逃
    guanhui07
        51
    guanhui07  
       Feb 20, 2019
    提前 return
    About     Help     Advertise     Blog     API     FAQ     Solana     2660 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 107ms UTC 15:52 PVG 23:52 LAX 08:52 JFK 11:52
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86