是否可以使方法只执行一次?

Gan*_*row 13 java

我有一个for循环和这样的结构:

for(....)
....
....
if(isTrue)
... do something..
.. method to be executed once (doTrick) is declared outside for loop.
....endif
endfor

public void doTrick()
...
...
..end
Run Code Online (Sandbox Code Playgroud)

for循环中的方法只能执行一次吗?

Ros*_*sim 43

当然!..

if(!alreadyExecuted) {
    doTrick();
    alreadyExecuted = true;
}
Run Code Online (Sandbox Code Playgroud)

  • 在多线程环境中,您可能希望同步该块. (23认同)
  • 据推测,虽然已经执行的将是一个局部变量, (2认同)

Hov*_*uan 8

您可以使用AtomicBoolean以确保仅在第一次调用该任务时:

public class Once {
    private AtomicBoolean done = new AtomicBoolean();

    public void run(Runnable task) {
        if (done.get()) return;
        if (done.compareAndSet(false, true)) {
            task.run();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

Once once = new Once();
once.run(new Runnable() {
    @Override
    public void run() {
        foo();
    }
});

// or java 8
once.run(() -> foo());
Run Code Online (Sandbox Code Playgroud)

  • 有人可以向我解释一下为什么要检查 `if (done.get()) return;` 吗?据我对[javadoc](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/atomic/AtomicBoolean.html#compareAndSet(boolean, boolean)) `done.compareAndSet(false, true)` 将在从“false”转换为“true”时运行一次,并且所有后续调用都将进入分支,因为它期望“false”并且它已经设置为“true” 。 (4认同)
  • `导入 java.util.concurrent.atomic.AtomicBoolean;` (2认同)

mkr*_*fky 7

在 Java 8 中,您可以使用自动记忆有效地执行此操作,如下所述:Do it in Java 8: Automatic memoization

我承认,对于“运行一次”场景来说,记忆可能被认为是矫枉过正,但它是之前答案中描述的一些相当干净的替代方案。

例如:

public void doSomething() { ... }

Map<Boolean, Boolean> cache = new ConcurrentHashMap<>();

public void doSomethingOnce() {
  cache.computeIfAbsent(true, x -> {
    doSomething();
    return true;
  });
}
Run Code Online (Sandbox Code Playgroud)


小智 6

另一个矫枉过正的解决方案:

根据您想要做什么,可能可以使用静态初始化块。

public class YourKlass{
    public void yourMethod(){

        DoTrick trick; 

        for( int i = 0; condition; i++){
            // ... (1)
            trick = new DoTrick(); // or any kind of accessing DoTrick
            // ... (2)
        }

    } 
}

public class DoTrick{
    static{
        // Whatever should be executed only once 
    }
}
Run Code Online (Sandbox Code Playgroud)

简单的解决方案:

或者,您只想在循环外执行第一部分:

int i = 0;
if( condition ){
    // ... (1)
    // do trick
    // ... (2)
}
for(i = 1; condition; i++){
    // ... (1)
    // ... (2)
}
Run Code Online (Sandbox Code Playgroud)


Aar*_*lla 5

您可以if()使用以下技巧来避免:

private Runnable once;
private final static Runnable NOP = new Runnable () {
    public void run () {
        // Do nothing
    }
}

public void method () {
    once = new Runnable () {
        public void run () {
            doTrick();
            once = NOP;
        }
    }

    for (...) {
        ...
        once.run();
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Tomas:扩大视野:-) (9认同)
  • 现在使用 lambda 表达式看起来会更好。你甚至不需要`NOP`。只需 `Runnable Once = () -&gt; { doTrick(); 一次 = () -&gt; {}; };` (2认同)

JIE*_*ANG 5

如果你使用 kotlin,你可以这样做:

val execOnce by lazy {
   print("hello, world")
}
Run Code Online (Sandbox Code Playgroud)