Java 返回分配与分配然后返回。 (例如在单身人士中)

Java returning assignement vs assigning then returning. (E.g. in Singletons)

基本上,你可以有这样的代码:

发件人:Baeldung.com

public static synchronized ClassSingleton getInstance() {
    if(instance == null) {
        instance = new ClassSingleton();
    }
    
    return instance;
}

你可以有这样的代码:

我的版本:

public static synchronized ClassSingleton getInstance() {
    return instance = (instance == null) ? new ClassSingleton() : instance;
}

下面的代码在任何方面都更简洁,但是 SonarLints 规则 java:S1121 认为这是不合规的(主要,代码味道)

除了 SonarLint 所说的可读性之外,这背后还有更多内容吗?

我有一种奇怪的感觉,我的版本总是在返回之前做一个赋值,这会不会影响性能?

很高兴听到你们的意见。

是的,它可能会对性能产生影响[可能可以忽略不计]。这可以通过尝试编译它并查看结果来测试。这是来自 Javac 16.0.1 的字节码:

Compiled from "ClassSingleton.java"
public class ClassSingleton {
  public ClassSingleton();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static synchronized ClassSingleton getInstance();
    Code:
       0: getstatic     #7                  // Field instance:LClassSingleton;
       3: ifnonnull     16
       6: new           #8                  // class ClassSingleton
       9: dup
      10: invokespecial #13                 // Method "<init>":()V
      13: putstatic     #7                  // Field instance:LClassSingleton;
      16: getstatic     #7                  // Field instance:LClassSingleton;
      19: areturn

  public static synchronized ClassSingleton getInstanceShort();
    Code:
       0: getstatic     #7                  // Field instance:LClassSingleton;
       3: ifnonnull     16
       6: new           #8                  // class ClassSingleton
       9: dup
      10: invokespecial #13                 // Method "<init>":()V
      13: goto          19
      16: getstatic     #7                  // Field instance:LClassSingleton;
      19: dup
      20: putstatic     #7                  // Field instance:LClassSingleton;
      23: areturn
}

通过 long=bad 的旧指标,第二个版本显然更差。不过,严肃地说,它在所有情况下都只执行 2 条额外指令。首先 dup 复制堆栈中的最后一项,然后它可以将该额外的项目用于 putstatic,后者将 instance 分配给堆栈中的顶部值。我们可以推测,如果另一个线程未在 ClassSingleton 上同步,并且 instance 具有正确的属性,那么理论上我们可能会遇到一些奇怪的行为,其中 instance 可能未正确设置。然而,考虑到 synchronized 为我们处理了大部分,这似乎不太可能。

虽然最后,JIT 编译器可能会通过使用寄存器消除对 dup 的需求,并且它有很大的机会弄清楚它可以摆脱额外的 putstatic 作为出色地。但是,我对 JIT 编译器的经验不足,只能推测它的行为方式。

也就是说,只使用第一个版本。它更容易阅读并生成更短的字节码。