monster1priest
V2EX  ›  Java

Java 库为什么要这么写?

  •  
  •   monster1priest · Oct 25, 2021 via iPhone · 8615 views
    This topic created in 1834 days ago, the information mentioned may be changed or developed.
    我一般都是
    int a = getNumber(); if(a >0)…….
    但是我看到源码写法很多是
    int a; if((a=getNumber()) >0)…….
    为什么会这么写?是有什么好处吗
    50 replies  •  2021-10-27 20:03:38 +08:00
    bololobo
    bololobo
    Oct 25, 2021
    1
    能显得比较厉害。别人问我为什么要这样写,我就会说 你看源码也这样写
    monster1priest
    monster1priest
    OP
    Oct 25, 2021 via iPhone
    2
    @bololobo hashmap 就是这么写的。人家应该不是为了炫耀吧
    BBCCBB
    BBCCBB
    Oct 25, 2021
    3
    一般是
    int a;
    if (xxx && (a=getNumber() > 0)) 这样吧,
    不能只有一个条件也 f((a=getNumber()) >0)/
    QingXuJiaZhi
    QingXuJiaZhi
    Oct 25, 2021❤️6
    4
    有 C 语言背景可能会习惯这样写
    rannnn
    rannnn
    Oct 25, 2021
    5
    这么写一般是在 while 里吧
    zardmyLove
    zardmyLove
    Oct 25, 2021
    6
    我的想法是显得紧凑
    zjsxwc
    zjsxwc
    Oct 25, 2021 via Android❤️3
    7
    因为这个变量 a 只是单纯想在 if 条件中使用?
    而 if 的 condition 里不能 declare 变量 a 类型,不得不挪到外面。

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

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

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


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

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

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

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

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

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

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

    对比如果不这么写:

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

    显然前者更简洁。
    skinny
    skinny
    Oct 26, 2021
    25
    可能没什么特殊用意,可能就是写这部分代码的人有一些在 C/C++的不良习惯而已,这写法不是特殊需要在 C/C++也不是推荐写法啊。后面更新维护的人也不会在没有明显问题时去动它,于是就保留了下来。JVM 优化不会这么挫的。说起库源代码违反最佳写法官方推荐写法的多了去了,比如 Python ,就很多问题,但是没人愿意去更新源代码。
    clf
    clf
    Oct 26, 2021
    26
    有没有可能第二种的 a 作用域只在 if 的括号里,所以这样写。
    b0644170fc
    b0644170fc
    Oct 26, 2021
    27
    我觉得 4 楼说的有理.
    cubecube
    cubecube
    Oct 26, 2021❤️1
    28
    @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
    MineDog
    Oct 26, 2021
    29
    @546L5LiK6ZOt #9 还有是访问成员变量需要的指令比局部变量多,在保证语义一致的情况下,指令更少,性能更好一点
    tobepro
    tobepro
    Oct 26, 2021
    30
    记得以前学嵌入式的时候,听韦东山老师说过,有部分大型开源项目的看着感觉很高大上的代码,其实没什么卵用,单纯就是写代码的人想炫技
    streamrx
    streamrx
    Oct 26, 2021 via iPhone
    31
    1
    yuchting
    yuchting
    Oct 26, 2021
    32
    其实更吊的写法应该是 if((var a = getNumber()) > 0) ...
    可惜没语言支持。
    oldshensheep
    oldshensheep
    Oct 26, 2021
    33
    @yuchting
    python 可以
    xiang0818
    xiang0818
    Oct 26, 2021
    34
    因为是上了年代的程序员写的~
    ColinZeb
    ColinZeb
    Oct 26, 2021
    35
    @yuchting c# 可以 ,还可以顺便判断类型或者是否为空。

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

    if(obj is {})//判断是否非空
    ipwx
    ipwx
    Oct 26, 2021
    36
    @yuchting python 3.9


    if (a := getNumber()) > 0:
    ....
    newmlp
    newmlp
    Oct 26, 2021❤️1
    37
    代码行数少,有限的空间内可以看到更多的逻辑,没其他原因
    zhgg0
    zhgg0
    Oct 26, 2021
    38
    @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
    penguinWWY
    Oct 26, 2021
    39
    @cubecube 优化是后面 Hotspot 干的事情,javac 几乎不做优化
    geligaoli
    geligaoli
    Oct 26, 2021
    40
    @546L5LiK6ZOt 多线程中,有时这么写是为了避免锁,局部变量之后的操作,不用担心其他线程的影响。
    littlewing
    littlewing
    Oct 26, 2021
    41
    羡慕 Java ,能看懂 标准库的代码,最新学 C++,STL 不是人看的
    rrfeng
    rrfeng
    Oct 26, 2021 via Android
    42
    @yuchting
    你们最讨厌的 go 也支持
    iceheart
    iceheart
    Oct 26, 2021 via Android
    43
    C 代码转过来的吧,直接用了,省事
    eason1874
    eason1874
    Oct 26, 2021
    44
    @yuchting #32 PHP 很多就这么写的,不用提前声明变量 $a ,直接在条件判断里赋值运算,某些场景能省不少 if 嵌套

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

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

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

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

    为了兼容所有的编译器所以使用第二种写法,还有的编译器定义变量的时候不能在函数中间定义,必须在函数最前面定义。
    yolee599
    yolee599
    Oct 27, 2021
    49
    @yolee599 #48 第一种写法是 C99 的语法,很多编译器是不支持 C99 语法的。有时候编译器支持 C99 也不会特意去开启 C99 ,都是为了兼容😂
    skinny
    skinny
    Oct 27, 2021
    50
    @yolee599 你没明白我的意思
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   3302 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 123ms · UTC 10:40 · PVG 18:40 · LAX 02:40 · JFK 05:40
    ♥ Do have faith in what you're doing.