有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java只为方法的第一次调用调用方法的块

我有一个方法,在这个方法中我有一个块:

public void method()
{
   [block instructions]
}

但是这个方法在我的程序中被调用了两次。我希望这个块只执行一次,并且只在方法的第一次出现时执行。做这件事的最好和优雅的方式是什么


共 (6) 个答案

  1. # 1 楼答案

    你可能应该重新设计你的方法。如果一个方法在第二次运行时做了一些不同的事情,那么对于试图理解您的程序的人来说,这会让人感到困惑

    第二次是从程序中的其他地方调用的吗?如果是这种情况,最简单的方法就是提取复制到另一个方法中的位

    method() {
        // Do stuff that's run only the first time
        method2()
    }
    
    method2() {
        // Do stuff that's run both times
    }
    

    如果它是从同一个地方调用的,你应该问问自己,为什么你的代码期望第二次发生不同的事情

  2. # 2 楼答案

    冒着过度设计的风险,我实际上建议。基本上你有一个State抽象:

    interface State extends Runnable {}
    

    有两种实现:

    class FirstState extends State {
        public void run() {
            //[block of code]
            state = new SecondState();
        }
    }
    
    class SecondState extends State {
        public void run() {
            //[block instructions]
        }
    }
    

    FirstState开关当前state

    private State state = new FirstState();
    

    你的method()现在没有条件逻辑:

    public void method()
    {
        state.run();
    }
    

    然而,在99%的情况下boolean标志就足够了

    更新:上述解决方案不是线程安全的。如果需要,简单的AtomicReference<State> state就不够了。就足够了(请参见下面的Marko Topolnik注释),或者您需要同步整个method()

    public synchronized void method()
    {
        state.run();
    }
    
  3. # 3 楼答案

    private static final AtomicBoolean hasRunAtom = new AtomicBoolean();
    
    public void method() {
      if (hasRunAtom.getAndSet(true)) return;
      [block instructions]
    }
    
  4. # 4 楼答案

    首先,如果你想要简单快捷的方式,使用一个简单的布尔标志(只是不要忘记并发问题,使用@Marko Topolnik solution)

    但是如果我们已经开始了理论讨论,讨论了设计模式,而不是使用@Tomasz Nurkiewicz提到的状态模式,我建议考虑(有人会说这更反设计模式),以及如何只实现这个类的一个实例,所以如果请求这个类的一个实例,构造函数将仅在第一次调用中被调用

    如果你想要更多“开箱即用”的解决方案,你可以使用

  5. # 5 楼答案

    一个简单的解决方案是使用静态布尔标志:

    static boolean flag = true;
    
    public void method()
    {  
      if (flag)
      {
    
          [block instructions]
          flag = false;  
    
      }
    } 
    
  6. # 6 楼答案

    Marko的答案在概念上很简单,但现在对方法的每次调用都需要对AtomicBoolean执行原子操作。如果经常调用method(),这将导致严重的性能损失

    这里是我提出的另一个线程安全解决方案,基于单例模式。我预计这将大大降低性能开销

    public class MyClass {
        public void method() {
            BlockRunner.runIfFirst();
        }
    
        private static class BlockRunner {
            static {
                [block insturctions]
            }
    
            public static void runIfFirst() {}
        }
    }
    

    这个解决方案基于单例惰性init概念described here

    如果我的理解是正确的,当BlockRunner第一次通过调用runIfFirst()调用时,静态代码块将被调用。以后对runIfFirst()的所有调用都会立即返回,而不会执行任何真正的代码。从性能角度来看,您正在用一个简单的分支和返回操作取代一个重原子操作