为什么Java API在if语句中有看似奇怪的赋值?

Iva*_*van 10 java java-8

我是编程和Java的新手.我注意到,在Java API中,if语句中有一些奇怪的赋值方法.

以下是Map界面的示例:

default V replace(K key, V value) {
    V curValue;
    if (((curValue = get(key)) != null) || containsKey(key)) {
        curValue = put(key, value);
    }
    return curValue;
}
Run Code Online (Sandbox Code Playgroud)

以这种方式嵌套赋值是否有某种好处?这纯粹是一种风格选择吗?为什么不在curValue第一次声明时进行赋值?

// why not do it like this?
default V replace(K key, V value) {
    V curValue = get(key); // not nested
    if (curValue != null || containsKey(key)) {
        curValue = put(key, value);
    }
    return curValue;
}
Run Code Online (Sandbox Code Playgroud)

我在Map界面和其他地方的许多新添加的Java 8方法中都注意到了这一点.这种嵌套分配的形式似乎是不必要的.

编辑:Map界面中的另一个示例:

default V computeIfAbsent(K key,
        Function<? super K, ? extends V> mappingFunction) {
    Objects.requireNonNull(mappingFunction);
    V v;
    if ((v = get(key)) == null) {
        V newValue;
        if ((newValue = mappingFunction.apply(key)) != null) {
            put(key, newValue);
            return newValue;
        }
    }

    return v;
}
Run Code Online (Sandbox Code Playgroud)

Eug*_*ene 3

它所做的实际上是复制到局部变量,这会产生更小的字节代码,并且它被视为绝对极端的优化方式,您将在 jdk 代码中的许多其他地方看到这一点。

另一件事是,多次读取局部变量意味着仅读取共享变量一次,例如,如果该变量是 avolatile并且您只需读取它一次并在方法中使用它。

编辑

据我所知,这两种方法之间的区别在于一次读取

假设我们有这两个方法:

V replace(K key, V value) {
    V curValue;
    if ((curValue = map.get(key)) != null || map.containsKey(key)) {
        curValue = map.put(key, value);
    }
    return curValue;
} 

V replaceSecond(K key, V value) {
    V curValue = map.get(key); // write
    if (curValue != null || map.containsKey(key)) { // read
        curValue = map.put(key, value); // write
    }
    return curValue;
}
Run Code Online (Sandbox Code Playgroud)

其字节码几乎相同,除了:replaceSecond将具有:

 astore_3 // V curValue = map.get(key); store to curValue
 aload_3  // curValue != null; read the value from curValue
Run Code Online (Sandbox Code Playgroud)

虽然该replace方法将是:

 dup      // duplicate whatever value came from map.get(key)
 astore_3 // store the value, thus "consuming" it form the stack
Run Code Online (Sandbox Code Playgroud)

根据我的理解,dup这不算是另一次阅读,所以我想这就是所谓的极限优化