Java 库为什么要这么写? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
monster1priest
V2EX    Java

Java 库为什么要这么写?

  •  
  •   monster1priest 2021-10-25 21:37:22 +08:00 via iPhone 7813 次点击
    这是一个创建于 1446 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我一般都是
    int a = getNumber(); if(a >0)…….
    但是我看到源码写法很多是
    int a; if((a=getNumber()) >0)…….
    为什么会这么写?是有什么好处吗
    50 条回复    2021-10-27 20:03:38 +08:00
    bololobo
        1
    bololobo  
       2021-10-25 21:50:50 +08:00
    能显得比较厉害。别人问我为什么要这样写,我就会说 你看源码也这样写
    monster1priest
        2
    monster1priest  
    OP
       2021-10-25 21:51:44 +08:00 via iPhone
    @bololobo hashmap 就是这么写的。人家应该不是为了炫耀吧
    BBCCBB
        3
    BBCCBB  
       2021-10-25 21:53:41 +08:00
    一般是
    int a;
    if (xxx && (a=getNumber() > 0)) 这样吧,
    不能只有一个条件也 f((a=getNumber()) >0)/
    cmdOptionKana
        4
    cmdOptionKana  
       2021-10-25 22:31:04 +08:00   6
    有 C 语言背景可能会习惯这样写
    rannnn
        5
    rannnn  
       2021-10-25 22:36:23 +08:00
    这么写一般是在 while 里吧
    zardmyLove
        6
    zardmyLove  
       2021-10-25 22:51:57 +08:00
    我的想法是显得紧凑
    zjsxwc
        7
    zjsxwc  
       2021-10-25 22:52:32 +08:00 via Android   3
    因为这个变量 a 只是单纯想在 if 条件中使用?
    而 if 的 condition 里不能 declare 变量 a 类型,不得不挪到面。

    https://stackoverflow.com/questions/16148580/assign-variable-value-inside-if-statement
    zjsxwc
        8
    zjsxwc  
       2021-10-25 22:53:51 +08:00 via Android
    感觉,莫名好笑
    546L5LiK6ZOt
        9
    546L5LiK6ZOt  
       2021-10-25 23:56:42 +08:00   4
    我记得很多类库还有一个常见的写法,就是在一个方法里,把类的成员变量赋值给局部变量,方法里都使用这个局部变量,而不直接用成员变量。例如:
    class A {
    int a;

    void func() {
    int a = this.a;
    // ……
    }
    }

    后来看到一种解释,说访问方法里成员变量不利于运行时优化(至少局部变量肯定是线程安全的)。


    我记得 jdk 的类库里还经常看到这么种情况,明明这两个循环可以写在一起,合并成一个循环,但是却特地分开写。一种解释说,小的循环容易让 cpu 命中 cache ,执行更快。。。

    总之,类库总有些特殊的写法,跟写业务代码不一样
    mritd
        10
    mritd  
       2021-10-26 01:28:45 +08:00 via iPhone
    @546L5LiK6ZOt #9 这种好像是为了满足那些 get set 规范
    Jooooooooo
        11
    Jooooooooo  
       2021-10-26 01:39:44 +08:00
    这是习惯问题

    两种写法还能用性能差异那是 jvm 有毛病
    chendy
        12
    chendy  
       2021-10-26 08:25:08 +08:00
    没啥好处,甚至不太好读
    是源码还是反编译?反编译的话经常看到一些奇怪的写法,但是都是编译器优化导致的
    rpish
        13
    rpish  
       2021-10-26 08:27:36 +08:00
    @546L5LiK6ZOt
    @zjsxwc
    感谢两位老哥,涨姿势了
    yidinghe
        14
    yidinghe  
       2021-10-26 08:37:10 +08:00 via Android
    不看上下文的话,每次都这么写是脱裤子放屁,但确实有合理使用的场景,一般都是在 IO 流读取时出现
    Cbdy
        15
    Cbdy  
       2021-10-26 08:40:33 +08:00
    IO 时会这样写,C 语言延续下来的传统,我记得 Unix 高程称赞过这种写法
    Leviathann
        16
    Leviathann  
       2021-10-26 09:16:41 +08:00 via iPhone
    这就是 c 味
    反正我挺不喜欢的
    micean
        17
    micean  
       2021-10-26 09:18:38 +08:00 via Android
    @zjsxwc 那不需要声明 a 变量
    aguesuka
        18
    aguesuka  
       2021-10-26 09:24:28 +08:00
    就是 4 楼的说法, 请相信这种简单的优化, 编译器比人更聪明.
    bk201
        19
    bk201  
       2021-10-26 09:37:59 +08:00
    语意应该浅显易懂,我觉得源码这处不行
    cubecube
        20
    cubecube  
       2021-10-26 09:38:23 +08:00
    @aguesuka 然而有时候编译器并不会更聪明。
    javac 近些年几乎保持不变。很多 jdk 的代码的确有部分优化,至于这种方式是否有神秘性能加成,回头可以分析下。
    wolfie
        21
    wolfie  
       2021-10-26 09:43:11 +08:00
    简洁啊。

    举例不对,这个例子没有任何必要。
    cpstar
        22
    cpstar  
       2021-10-26 09:50:33 +08:00
    从编译出的 bytecode 上,这两个没差别,也无所谓性能调优。
    都是先 invoke 再 ifgt 。

    如果说性能调优,那就是 9#说的问题,局部变量,不需要每次都 invoke当然编译器也可能自动识别并且加上一个局部变量压栈
    yinzhili
        23
    yinzhili  
       2021-10-26 09:56:19 +08:00
    一些人原先习惯了其它的编程语言,写 Java 代码的时候就会带上之前的习惯,比如:喜欢用下划线开头的变量名
    ipwx
        24
    ipwx  
       2021-10-26 09:59:37 +08:00
    if 这么写就是魔怔了。。。

    但是如果换成 while ,这么写就爽了。比如:

    int bytesRead;
    while ((bytesRead = read(fd)) > 0) {
    ...
    }

    对比如果不这么写:

    while (true) {
    int bytesRead = read(fd);
    if (bytesRead <= 0) {
    break;
    }
    ...
    }

    显然前者更简洁。
    skinny
        25
    skinny  
       2021-10-26 10:02:40 +08:00
    可能没什么特殊用意,可能就是写这部分代码的人有一些在 C/C++的不良习惯而已,这写法不是特殊需要在 C/C++也不是推荐写法啊。后面更新维护的人也不会在没有明显问题时去动它,于是就保留了下来。JVM 优化不会这么挫的。说起库源代码违反最佳写法官方推荐写法的多了去了,比如 Python ,就很多问题,但是没人愿意去更新源代码。
    clf
        26
    clf  
       2021-10-26 10:08:02 +08:00
    有没有可能第二种的 a 作用域只在 if 的括号里,所以这样写。
    b0644170fc
        27
    b0644170fc  
       2021-10-26 10:13:25 +08:00
    我觉得 4 楼说的有理.
    cubecube
        28
    cubecube  
       2021-10-26 10:17:57 +08:00   1
    @aguesuka 的确没有神秘加成, 可能就是程序员的个人习惯了

    JMHPerfCondition.conditionInvokeFirst avgt 3 13.930 ± 3.733 ns/op
    JMHPerfCondition.conditionInvokeLater avgt 3 13.742 ± 1.632 ns/op

    ```java
    @Benchmark
    public int conditionInvokeFirst() {
    int a = SpecialCaseTest.getNumber();
    if (a > 0) {
    return 1;
    } else {
    return 0;
    }

    }

    @Benchmark
    public int conditionInvokeLater() {
    int a;
    if ((a = SpecialCaseTest.getNumber()) > 0) {
    return 1;
    } else {
    return 0;
    }
    }
    ```
    MineDog
        29
    MineDog  
       2021-10-26 10:19:39 +08:00
    @546L5LiK6ZOt #9 还有是访问成员变量需要的指令比局部变量多,在保证语义一致的情况下,指令更少,性能更好一点
    tobepro
        30
    tobepro  
       2021-10-26 11:03:42 +08:00
    记得以前学嵌入式的时候,听韦东山老师说过,有部分大型开源项目的看着感觉很高大上的代码,其实没什么卵用,单纯就是写代码的人想炫技
    streamrx
        31
    streamrx  
       2021-10-26 11:11:03 +08:00 via iPhone
    1
    yuchting
        32
    yuchting  
       2021-10-26 11:44:04 +08:00
    其实更吊的写法应该是 if((var a = getNumber()) > 0) ...
    可惜没语言支持。
    oldshensheep
        33
    oldshensheep  
       2021-10-26 11:53:56 +08:00
    @yuchting
    python 可以
    xiang0818
        34
    xiang0818  
       2021-10-26 13:44:11 +08:00
    因为是上了年代的程序员写的~
    ColinZeb
        35
    ColinZeb  
       2021-10-26 15:43:23 +08:00
    @yuchting c# 可以 ,还可以顺便判断类型或者是否为空。

    if( obj is int a )//判断是否 int 类型 如果是 int 赋值给 int a

    if(obj is {})//判断是否非空
    ipwx
        36
    ipwx  
       2021-10-26 15:54:21 +08:00
    @yuchting python 3.9


    if (a := getNumber()) > 0:
    ....
    newmlp
        37
    newmlp  
       2021-10-26 15:56:10 +08:00   1
    代码行数少,有限的空间内可以看到更多的逻辑,没其他原因
    zhgg0
        38
    zhgg0  
       2021-10-26 16:48:11 +08:00
    @newmlp 就是 37 楼说的原因,纯粹就是因为代码行数少。仔细翻下 HashMap 的源码就能验证,我刚验证过。
    在 HashMap 源码里面,就拿楼主写的代码来作比方 int a = getNumber(); if(a >0);
    1 、如果 a 变量在别的地方早就定义过,那就会被写成 if((a=getNumber()) >0);
    2 、如果 a 变量在别的地方没定义过,需要定义,那就会被写成 int a = getNumber(); if(a >0);

    1 的情况放 if 里能节省一行,所以放 if 里了; 2 的情况不管是否放 if 里都不能节省一行,所以没放 if 里;仔细翻下源码就发现了。
    penguinWWY
        39
    penguinWWY  
       2021-10-26 16:50:37 +08:00
    @cubecube 优化是后面 Hotspot 干的事情,javac 几乎不做优化
    geligaoli
        40
    geligaoli  
       2021-10-26 16:53:19 +08:00
    @546L5LiK6ZOt 多线程中,有时这么写是为了避免锁,局部变量之后的操作,不用担心其他线程的影响。
    littlewing
        41
    littlewing  
       2021-10-26 19:44:56 +08:00
    羡慕 Java ,能看懂 标准库的代码,最新学 C++,STL 不是人看的
    rrfeng
        42
    rrfeng  
       2021-10-26 19:52:38 +08:00 via Android
    @yuchting
    你们最讨厌的 go 也支持
    iceheart
        43
    iceheart  
       2021-10-26 20:21:55 +08:00 via Android
    C 代码转过来的吧,直接用了,省事
    eason1874
        44
    eason1874  
       2021-10-26 20:39:45 +08:00
    @yuchting #32 PHP 很多就这么写的,不用提前声明变量 $a ,直接在条件判断里赋值运算,某些场景能省不少 if 嵌套

    if (isOk() && ($a = getNumber()) > 0 && $a < 10) echo $a;
    someonedeng
        45
    someonedeng  
       2021-10-27 00:45:55 +08:00
    c 语言留下的习惯,个人感觉不好看
    fuchaofather
        46
    fuchaofather  
       2021-10-27 10:07:18 +08:00
    c 味儿
    GiftedJarvis
        47
    GiftedJarvis  
       2021-10-27 14:25:16 +08:00
    我也有这疑问, 不光 HashMap, 还有一堆 BlockQueue, AQS 里都这么写
    yolee599
        48
    yolee599  
       2021-10-27 17:49:00 +08:00
    @skinny #25 对于 C 语言,这样写不是不良习惯,反而是好习惯,因为有的编译器不支持以下语法:

    for (int i = 0; i < 10; i++)
    {
    ...
    }

    要改成下面的写法才能编译通过:

    int i;
    for (i = 0; i < 10; i++)
    {
    ...
    }

    为了兼容所有的编译器所以使用第二种写法,还有的编译器定义变量的时候不能在函数中间定义,必须在函数最前面定义。
    yolee599
        49
    yolee599  
       2021-10-27 17:52:25 +08:00
    @yolee599 #48 第一种写法是 C99 的语法,很多编译器是不支持 C99 语法的。有时候编译器支持 C99 也不会特意去开启 C99 ,都是为了兼容
    skinny
        50
    skinny  
       2021-10-27 20:03:38 +08:00
    @yolee599 你没明白我的意思
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1211 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 17:25 PVG 01:25 LAX 10:25 JFK 13:25
    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