Call a block of a method only for the first call of the method

后端 未结 6 1720
后悔当初
后悔当初 2021-01-20 02:54

I have a method and inside this method I have a block:

public void method()
{
   [block instructions]
}

But this method is called twice in

相关标签:
6条回答
  • 2021-01-20 03:01

    You should probably redesign your method. It's confusing for someone trying to understand your program if a method does something different the second time it's run.

    Is it called from a different place in your program, the second time? If that's the case, the easiest thing to do is to extract the bit that's duplicated into another method.

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

    If it's called from the SAME place, you should ask yourself why your code is expecting something different to happen the second time.

    0 讨论(0)
  • 2021-01-20 03:04

    At the risk of greatly over-engineering I actually suggest state-pattern. Essentially you have a State abstraction:

    interface State extends Runnable {}
    

    with two implementations:

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

    The FirstState switches current state:

    private State state = new FirstState();
    

    Your method() now has no conditional logic:

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

    However in 99% of cases boolean flag is enough...

    UPDATE: the solution above is not thread-safe. If you need it, simple AtomicReference<State> state won't will be enough (see Marko Topolnik comment below) or you need to synchronize the whole method():

    public synchronized void method()
    {
        state.run();
    }
    
    0 讨论(0)
  • First of all, if you want to easy and quick way, use a simple boolean flag (just don't forget the concurrency issue and use @Marko Topolnik solution).

    But if we already opened a theoretical discussion and talked about design pattern, rather than using the state-pattern like @Tomasz Nurkiewicz mention, I would suggest to think of singleton (some will say it's more anti design pattern) and how to achieve only one instance of this class, so if requesting an instance of this class, the constructor will be called only in the first call.

    if you altentivly want more "outside the box" solution, you can use aop

    0 讨论(0)
  • 2021-01-20 03:10
    private static final AtomicBoolean hasRunAtom = new AtomicBoolean();
    
    public void method() {
      if (hasRunAtom.getAndSet(true)) return;
      [block instructions]
    }
    
    0 讨论(0)
  • 2021-01-20 03:16

    Marko's answer is simple conceptually, but every call to method now needs to perform an atomic operation on the AtomicBoolean. If method() is very commonly called, this will incur a significant performance penalty.

    Here's another thread-safe solution I came up with, based on the singleton pattern. I expect this to have significantly less performance overhead.

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

    This solution is based on the Singleton lazy-init concept described here.

    If my understanding is correct, when BlockRunner is first invoked by calling runIfFirst(), the static block of code will get invoked. All future calls to runIfFirst() will simply just return immediately, without any real code being executed. From a performance perspective, you're replacing a heavy atomic operation, with a simple branch-and-return operation.

    0 讨论(0)
  • 2021-01-20 03:19

    A simple solution would be to use a static boolean flag:

    static boolean flag = true;
    
    public void method()
    {  
      if (flag)
      {
    
          [block instructions]
          flag = false;  
    
      }
    } 
    
    0 讨论(0)
提交回复
热议问题