Java 求解如何优化 100 个 if 判断? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
whereisgungun
V2EX    程序员

Java 求解如何优化 100 个 if 判断?

  •  
  •   whereisgungun 2022-11-07 21:04:51 +08:00 8212 次点击
    这是一个创建于 1072 天前的主题,其中的信息可能已经有所发展或是发生改变。
    需求是这样的:
    上游服务调用接口( TCP 协议,用 netty 做了服务端,上游是客户端)发来报文,这个报文里面会有 35 个属性,我们简单定义这 35 个属性为 A 、B 、C 、D....然后每个属性的值为 a 、b 、c 、d....现在有接近 100 个模板,然后我们的功能就是要根据报文来确定要用哪一个,重点是这 100 个模板是没有规律的。

    比如:
    if(a==1 && b==2) {return "模板 1";}
    if(c.length==1 && d.equals("xxx")) {return "模板 2";}
    ...
    也就是说,会有 100 个 if 判断来确定此次调用的报文对应哪个模板,而且报文是不冲突的,35 个属性的值只要命中其中一个模板,其他的就都不符合,都是互斥的。(算是 CompletableFuture 的 anyOf 方法。)

    现在暂时找不出这 100 个 if 里面有什么具体的规律,35 个属性也没有。求问各位大神有什么好的思路优化吗?线程池 or 中间件?

    PS:作为最底层的外包,也没法要求上游能做什么改动了。。他们是一个老旧的银行系统,以前也是用的一个一个判断来着,现在把项目丢给我们了。。
    82 条回复    2022-11-09 12:56:51 +08:00
    nightwitch
        1
    nightwitch  
       2022-11-07 21:09:21 +08:00 via Android
    没规律的话 100 个判断是少不了的,只是写成 if 和写成函数的区别
    hqs0417
        2
    hqs0417  
       2022-11-07 21:11:32 +08:00
    可以考虑做个规则引擎,类似查表
    secondwtq
        3
    secondwtq  
       2022-11-07 21:12:17 +08:00
    你是想要优化结构还是优化性能?
    ClericPy
        4
    ClericPy  
       2022-11-07 21:14:01 +08:00
    本来还以为路径那样前缀树, 一看还有判断长短....


    解释器模式搞个规则引擎吧
    hidemyself
        5
    hidemyself  
       2022-11-07 21:15:27 +08:00
    完全没规律如果后续也不会有什么改动,if 就可以了
    whereisgungun
        6
    whereisgungun  
    OP
       2022-11-07 21:16:35 +08:00
    @nightwitch 是的。知道得写了。。就是想问问有什么技术方法可以加快一下判断,压榨机器。。
    justNoBody
        7
    justNoBody  
       2022-11-07 21:16:57 +08:00
    无意冒犯,但如果只是作为人力外包,且领导没有明确要求重构、或者不给重构工时、或者不给充分的测试时间,千万别改这这部分的代码,在这 100 个 if-else 之上写新的业务逻辑就行,这部分你可以适当设计一下。
    whereisgungun
        8
    whereisgungun  
    OP
       2022-11-07 21:17:13 +08:00
    @secondwtq 主要还是性能
    optional
        9
    optional  
       2022-11-07 21:18:35 +08:00 via iPhone   8
    统计下各个模板的频率,把常见的模板放最上面,可以提高性能
    secondwtq
        10
    secondwtq  
       2022-11-07 21:18:52 +08:00
    @whereisgungun 有相关数据的话就简单,找出每个请求走的哪个 if ,命中频率最高的排前面就行
    whereisgungun
        11
    whereisgungun  
    OP
       2022-11-07 21:22:46 +08:00
    @optional
    @secondwtq
    感谢感谢,感觉还是得搞完之后再进行统计了
    whereisgungun
        12
    whereisgungun  
    OP
       2022-11-07 21:23:31 +08:00
    @hidemyself
    @justNoBody
    是的,时间不够性能优化的话就只能往这坨东西上面继续拉了
    whereisgungun
        13
    whereisgungun  
    OP
       2022-11-07 21:24:04 +08:00
    @hqs0417
    @ClericPy
    感谢,我去研究研究咋用
    xyjincan
        14
    xyjincan  
       2022-11-07 21:29:03 +08:00 via Android
    map 对象
    PendingOni
        15
    PendingOni  
       2022-11-07 21:30:13 +08:00
    #9 说的对,先把频率出现最高的放到最前面,之后用 swich 分组试试
    sparky
        16
    sparky  
       2022-11-07 21:59:13 +08:00 via Android
    可以试试决策树,有 java 开源实现,还可以可视化编辑,最终会生成一个 json 配置,可以实现规则和业务的分离
    ih8es9OIzne0959p
        17
    ih8es9OIzne0959p  
       2022-11-07 22:00:42 +08:00
    能不能多起几个线程
    546L5LiK6ZOt
        18
    546L5LiK6ZOt  
       2022-11-07 22:06:01 +08:00
    如果完全没有规律,那上游是怎么发报文的,也是 100 个 if ?我猜应该是有规律的,不然这一整条链路维护起来都很吐血。。。
    pannanxu
        19
    pannanxu  
       2022-11-07 22:09:17 +08:00
    直接枚举啊,一个参数是参数校验,一个参数是模板
    seers
        20
    seers  
       2022-11-07 22:26:16 +08:00
    试试图那些算法,DFS 和 BFS ,感觉会有效果
    CEBBCAT
        21
    CEBBCAT  
       2022-11-07 22:38:15 +08:00
    无非是些 if-else ,怎么会有性能问题呢?
    楼主的文字我都读了,但是总是不敢相信事实就是我理解的那样。假如这 35 个 field 之间几乎没有关系(除了文中提到的 c 、d )

    我认为现在楼主的诉求还是不明确,对问题的理解,或者说抽象还是不到位。为避免 XY 问题,楼主可否再多透露些细节?

    如果不方便的话,我认为有两个要点,一个是提高可维护性,上百个 if-else 会把人搞得头晕脑胀,不沐浴焚香在脑袋里装图灵机是 hold 不住这样的代码的。另一个是防止业务人员提错需求,维护人员照做之下产生逻辑覆盖错误
    billlee
        22
    billlee  
       2022-11-07 22:43:57 +08:00
    没有什么好有优化的,我做过规则引擎,100 个 if 编译出来的结果是运行速度最快的。
    jeesk
        23
    jeesk  
       2022-11-07 22:48:34 +08:00
    @seers 请教一下,dfs, bfs 如何应用到这种判断上去?

    说说我的看法, 要么用有优先级的过滤器判断, 要么就 if else.
    wangritian
        24
    wangritian  
       2022-11-07 23:01:39 +08:00   1
    别动,别动,别动
    Hurriance
        25
    Hurriance  
       2022-11-07 23:41:19 +08:00
    不用优化吧。优化后有回归测试的成本和发布风险,每个 if 写好注释,我觉得就可以了
    graptioute
        26
    graptioute  
       2022-11-07 23:45:19 +08:00
    表驱动编程
    JohnBull
        27
    JohnBull  
       2022-11-07 23:49:11 +08:00
    Erlang 的 pattern matching 最善于处理这种逻辑
    shyangs
        28
    shyangs  
       2022-11-08 00:02:29 +08:00
    方是「老」的行系,

    如果需求已「固定」,些件性本都不再更,

    那直接 if-else 性能是最高的,比你用函跳高。
    fkdog
        29
    fkdog  
       2022-11-08 00:10:21 +08:00
    这 100 个 if ,我就想单测能不能覆盖到所有的 case 。。。
    itechify
        30
    itechify  
    PRO
       2022-11-08 00:10:28 +08:00 via Android
    JAVA 的话,可以把条件+模板组合封装成 Predicate ,用 stream.filter 出匹配到的,但这对性能没有优化
    allenzhangSB
        31
    allenzhangSB  
       2022-11-08 00:17:32 +08:00   2
    你一百多个 if else 能有什么性能问题?
    night98
        32
    night98  
       2022-11-08 00:20:20 +08:00
    你要搞清楚你调整代码的目的是啥,是更好的性能还是更好的可读性,还是更好的可修改性。更好的性能就是拆成三五个 func ,并发去调。可读性就是拆成枚举直接遍历,枚举里放判断的 func ,可修改性同上,加个 unit test 完事,要是没这些需求就别动,慢慢往上加 if 吧
    aguesuka
        33
    aguesuka  
       2022-11-08 00:36:30 +08:00   1
    @optional 按照楼主说的报文不冲突, 命中其中一个模板, 其他都不符合, 改顺序会影响结果.
    c0xt30a
        34
    c0xt30a  
       2022-11-08 07:10:57 +08:00
    1. 别动
    2. 表驱动
    3. 代码自动生成
    sorcerer
        35
    sorcerer  
       2022-11-08 07:46:45 +08:00 via iPhone   12
    if else 优化口诀
    互斥条件表驱动
    嵌套条件校验链
    短路条件早 return
    零散条件可组合
    opengps
        36
    opengps  
       2022-11-08 09:15:15 +08:00
    才 100 个,及即使按照高频率靠前优化了,效率也不会明显提升的,仅仅是少 100 个 if (假设条件里不带消耗性能的转换),测试不出来明显的感受。楼主跑个 1000 万次看看总时间,就知道效率优化有多小了
    allenzhangSB
        37
    allenzhangSB  
       2022-11-08 09:29:50 +08:00
    @night98 就 100 多个 if 判断, 多线程只会变慢
    312ybj22
        38
    312ybj22  
       2022-11-08 09:32:07 +08:00
    你先把规则进行统计,用规则树的形式进行统计(条件桩,条件项等),然后把规则写到规则引擎中(drools), 可以用数据脚本的形式,或者 excel 的形式。 这对于条件判断来讲就够了,当然我说的都是纸上谈兵,关键是能不能落地到你的业务体系中,你可以试试看,弄好的话还可以出去吹吹牛
    summerLast
        39
    summerLast  
       2022-11-08 09:37:52 +08:00
    责任链
    debuggerx
        40
    debuggerx  
       2022-11-08 09:46:45 +08:00
    有些人真是设计模式学傻了吧,问题的关键在于“优化 if 提升性能”这个错误认知吧
    NeroKamin
        41
    NeroKamin  
       2022-11-08 10:06:20 +08:00
    可以优化代码,但是对于性能上优化可能不太会有帮助
    mingsz
        42
    mingsz  
       2022-11-08 10:43:02 +08:00
    不动,继续加 if
    万一重构后,部分逻辑与之前不一样就 gg
    6david9
        43
    6david9  
       2022-11-08 10:47:41 +08:00 via iPhone
    看下响应链模式是否满足你的需求
    fgwmlhdkkkw
        44
    fgwmlhdkkkw  
       2022-11-08 10:52:14 +08:00
    每个模板需要的参数和值是确定的,那就可以查表呀。

    "a:a1,b:b1..." : tpl1
    "a:a2,b:b1..." : tpl2
    leonshaw
        45
    leonshaw  
       2022-11-08 10:55:05 +08:00
    判断这块需要优化的依据是什么?
    daminge
        46
    daminge  
       2022-11-08 10:57:11 +08:00
    放 map 里面最简单
    fgwmlhdkkkw
        47
    fgwmlhdkkkw  
       2022-11-08 10:57:25 +08:00
    @fgwmlhdkkkw #44
    如果值不是确定的,那可以 `({fn: (params: Params) => bool, hits: number})[]`依次执行,找到 hits 加一,一段时间后按照 hits 降序,理论上也会提高性能。
    fgwmlhdkkkw
        48
    fgwmlhdkkkw  
       2022-11-08 10:58:20 +08:00
    但是你要让我改,我肯定不想改……
    kingbill
        49
    kingbill  
       2022-11-08 11:10:55 +08:00
    提升性能的话,是打算并发判断吗?好像也不是不行,但总感觉没有必要
    jsjjdzg
        50
    jsjjdzg  
       2022-11-08 11:13:23 +08:00
    各种规则引擎下来还是 if 最快,把常用的 if 条件放前面就是最好的
    HugoChao
        51
    HugoChao  
       2022-11-08 11:20:33 +08:00
    才一百个,没有性能问题吧。保持这个结构,方便以后继续改逻辑
    7911364440
        52
    7911364440  
       2022-11-08 11:36:19 +08:00
    txy3000
        53
    txy3000  
       2022-11-08 11:39:06 +08:00
    做个 profile 再来谈性能 你确定瓶颈是 if 太多?
    shanghai1943
        54
    shanghai1943  
       2022-11-08 11:57:45 +08:00   1
    假如你为了所谓的命中率高的放前面,移动了 if 的逻辑判断顺序,会不会导致某些业务逻辑的执行顺序发生变化了。

    假设存在两种传参 a=1,b=2 和 a=1,b=2,c=3 ,以及两种 if 判断 a=1&&b=2 和 a=1&&c=3 ,如果调整了 if 的判断顺序,可能执行的业务就变得不一样了。

    建议慎重。。
    HanMeiM
        55
    HanMeiM  
       2022-11-08 12:24:13 +08:00
    用 map 做 key -> function 的驱动注册
    hhjswf
        56
    hhjswf  
       2022-11-08 12:27:04 +08:00
    if else 能有什么性能问题无非是丑了点
    cyrbuzz
        57
    cyrbuzz  
       2022-11-08 12:53:26 +08:00
    每个判断写成一个函数?对应的返回值可以写成枚举,1,2,3,4 这样,然后枚举和模板对应起来。

    js 代码:

    ```
    const enmu = {
    1: '模板 1',
    ....
    }

    const judgeFunc = [() => { return false }, () => { return true }]


    const finded = judgeFunc.findIndex((func) => { return func() })

    // 加判断
    enmu[finded]()
    ```

    随便扩展 enmu 和 judgeFunc 就可以了。
    bk201
        58
    bk201  
       2022-11-08 13:05:17 +08:00
    优化的目的是啥?增强可读性还是要做扩展?老系统能用就不要优化。你要优化,那还是那句话,首先优化的目标是啥?
    Ashore
        59
    Ashore  
       2022-11-08 13:12:25 +08:00
    改出问题你负责?不要想着去优化这个优化那个,业务能跑才是最重要的。
    vacuitym
        60
    vacuitym  
       2022-11-08 13:16:11 +08:00
    如果是为了程序可读性,而且每个变量对应的判断只有一种,可以对每个变量做一次真假的判断,然后存到一个 100 位的二进制中,然后对 100 个模版进行二进制的对应
    yolee599
        61
    yolee599  
       2022-11-08 13:20:42 +08:00 via Android
    建表,把所有需要判断的条件做成列,所有的处理函数作为行。一行一行遍历,每一行遍历所有列,如果有空列,则不做这列的判断,有符合条件的行就执行该行的处理函数。这样看起来比较好看,就是会损失一点点性能
    ipwx
        62
    ipwx  
       2022-11-08 13:40:26 +08:00
    楼上已经提到过了,用统计重新排列 if 的顺序可以提速。更近一步,可以通过命中概率构建一个二叉树,类似于霍夫曼树。然后自动生成嵌套的 if 代码。这样速度是最快的。

    https://zhuanlan.zhihu.com/p/54714101
    xlzyxxn
        63
    xlzyxxn  
       2022-11-08 13:52:35 +08:00
    无非丑了点,不要嘲笑别人,也不要怕被别人嘲笑,switch 表结构和 if 条件分支预测是能快,但优雅的代码是建立在解决业务问题之上的,不那么优雅的代码往往是因为复杂的业务问题。
    weixiangzhe
        64
    weixiangzhe  
       2022-11-08 13:59:21 +08:00
    我也觉得拆成 责任链 比较好
    forbreak
        65
    forbreak  
       2022-11-08 14:18:00 +08:00
    如果是为了性能那么就不用优化了。 提升性能觉对不会需要你再去优化这个 if 的性能。 因为肯定有比这个地方更慢的东西值得你去优化。要是为了优化代码结构还值得去折腾折腾。
    PythonYXY
        66
    PythonYXY  
       2022-11-08 14:21:02 +08:00
    别重构了,到时候屎山崩了你要负责的
    GLee9507
        67
    GLee9507  
       2022-11-08 14:22:54 +08:00
    责任链模式+1
    @weixiangzhe
    BQsummer
        68
    BQsummer  
       2022-11-08 14:25:52 +08:00
    这种场景 if 是最快的了
    TArysiyehua
        69
    TArysiyehua  
       2022-11-08 14:26:41 +08:00
    100 个 if 完全没必要优化,效率贼高,上面说的提高命中率和加设计模式能提高你写代码的技术,这个倒是真的。但是对性能是几乎没有帮助的。
    WhiteDragon96
        70
    WhiteDragon96  
       2022-11-08 14:28:10 +08:00
    把所有对应关系放 map 里面
    xuelu520
        71
    xuelu520  
       2022-11-08 14:38:05 +08:00
    这种真没办法,必须这么多 if 每个来处理,顶多按#9 楼的说法,高频放上面。
    kaf
        72
    kaf  
       2022-11-08 15:14:03 +08:00
    写一百个枚举或者 key-value 放 map 里
    XXWHCA
        73
    XXWHCA  
       2022-11-08 16:21:24 +08:00
    判断规则都不一样,这个是没办法改,上面说用 map ,枚举的都没有好好审题,#9 才是最实际的,高频放上面
    ScepterZ
        74
    ScepterZ  
       2022-11-08 16:27:28 +08:00
    你这个是有优先级的,不能直接改顺序,才 100 个 if 没啥好优化的,不差这点性能
    你要是优化代码结构还可以搞一下
    lazyfighter
        75
    lazyfighter  
       2022-11-08 16:28:40 +08:00
    所有的优化都是由繁化简,楼主首要前提是理解这 30 多个参数的含义,以及他们是怎么组合的,if 能有什么性能问题?
    newmlp
        76
    newmlp  
       2022-11-08 16:48:08 +08:00
    为啥要优化,100 个 if 构不成性能问题吧
    v2eb
        77
    v2eb  
       2022-11-08 18:48:03 +08:00 via Android
    性能应该不成问题。
    主要代码长, 逻辑难梳理, 所以问题应该是:
    如何以可读性更高的方式优化 100 个 if 嵌套?
    winglight2016
        78
    winglight2016  
       2022-11-08 18:54:53 +08:00
    用 switch 吧,onehotencode 编码一下就可以了
    yinft
        79
    yinft  
       2022-11-08 19:31:35 +08:00
    第一反应是放 map 做映射
    xuanbg
        80
    xuanbg  
       2022-11-09 08:07:05 +08:00
    这么多条件,唯有查表解君愁。
    mg52033
        81
    mg52033  
       2022-11-09 09:01:36 +08:00
    100 个 if else 性能最高
    keepfun
        82
    keepfun  
       2022-11-09 12:56:51 +08:00 via iPhone
    Drools
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1032 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 31ms UTC 22:55 PVG 06:55 LAX 15:55 JFK 18:55
    Do have faith in what you're doing.
    ubao 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