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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2665993/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 10:33:23  来源:igfitidea点击:

Is is possible to make a method execute only once?

java

提问by Gandalf StormCrow

I have a for loop and structure like this:

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

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

public void doTrick()
...
...
..end

Is it possible for a method in for loop to be executed only once?

for 循环中的方法是否可以只执行一次?

采纳答案by Rosdi Kasim

Sure!..

当然!..

if(!alreadyExecuted) {
    doTrick();
    alreadyExecuted = true;
}

回答by Paul Whelan

perhaps the break keyword is what you need? After running you method call break; I am sorry its not 100% clear what you mean from your question.

也许 break 关键字是您所需要的?运行你的方法调用 break 后;很抱歉,您的问题不是 100% 清楚您的意思。

Have a look herefrom the sun docs

从太阳文档看这里

回答by Aaron Digulla

You can avoid the if()by using this trick:

你可以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();
        ...
    }
}

回答by Mike

Another overkill solution:

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

Depending on what you want to do, it might be possible to use a static initialization block.

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

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 
    }
}

Simple solution:

简单的解决方案:

Or, instead you just want to execute the first part outside of the loop:

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

int i = 0;
if( condition ){
    // ... (1)
    // do trick
    // ... (2)
}
for(i = 1; condition; i++){
    // ... (1)
    // ... (2)
}

回答by Ranga Reddy

import java.util.ArrayList;

class RemoveDuplicate {
    public static void main(String[] args) {
        ArrayList<String> originalList = new ArrayList<String>();
        originalList.add("foo");
        originalList.add("bar");
        originalList.add("bat");
        originalList.add("baz");
        originalList.add("bar");
        originalList.add("bar");
        String str="bar";
        ArrayList<String> duplicateList = new ArrayList<String>();

        // adding duplicates to duplicateList
        for(String currentString : originalList) {
        if(currentString.startsWith(str)) {
                duplicateList.add(currentString);
            }
        }
        // removing duplicates in duplicatesList
        for(String removeString : duplicateList) {
            originalList.remove(removeString);
        }
        // finally adding duplicateElement
        originalList.add(str);

        for(String currEntry : originalList) {
            System.out.println(currEntry);
        }
    }
}

回答by Joolah

my sample from my app:

我的应用程序示例:

boolean alreadyExecuted = false;

then :

然后 :

private void startMyService() {

    if(!alreadyExecuted) {

        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
          @Override
          public void run() {
            //Do something after 4 seconds
              context.startService(new Intent(context, myService.class));
              alreadyExecuted = true;
          }
        }, 4000);
       }

回答by mkrufky

In Java 8, you can effectively do this using automatic memoization as described here: Do it in Java 8: Automatic memoization

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

I'll admit that memoization could be considered overkill for a "run once" scenario, but it is a rather clean alternative to some described in previous answers.

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

For instance:

例如:

public void doSomething() { ... }

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

public void doSomethingOnce() {
  cache.computeIfAbsent(true, x -> {
    doSomething();
    return true;
  });
}

回答by Hover Ruan

Your can use AtomicBooleanto make sure the task is only called the first time:

你可以AtomicBoolean用来确保任务只在第一次被调用:

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

    public void run(Runnable task) {
        if (done.get()) return;
        if (done.compareAndSet(false, true)) {
            task.run();
        }
    }
}

Usage:

用法:

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

// or java 8
once.run(() -> foo());

回答by JIE WANG

if you use kotlin, you can do this:

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

val execOnce by lazy {
   print("hello, world")
}

回答by Salix alba

I want to do something slight more complex. In a multi-threaded environment ensure that the methods is run only one (which is solved by Hover Ruan's answer above), but also block any thread so none return until the method is done.

我想做一些稍微复杂的事情。在多线程环境中,确保方法只运行一个(这可以通过上面 Hover Ruan 的回答解决),但也要阻止任何线程,因此在方法完成之前不会返回任何线程。

My solution is to use a Semaphore to do the blocking.

我的解决方案是使用信号量来进行阻塞。

public class Once implements Runnable {
    private static Semaphore signal = new Semaphore(1,true);
    private static boolean done=false;  

    @Override
    public void run() {
        if(done)
            return;
        signal.acquireUninterruptibly();
        if(done) {
            signal.release();
            return;
        }
        doTrick(); // actually run the task
        done=true;
        signal.release();
        return;
    }

    static int result; // Result of running the task
    static int count;  // number of times its been called

    /**
     * The task we only want to run once
     */
    public void doTrick() {
        ++count;
        Random rnd = new Random();
        for(int i=0;i<10000;++i) {
            result += rnd.nextInt(100);
        }
        try {
            Thread.sleep(1000); // just to ensure all thread start
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(10);
        for(int i=0;i<5;++i) { // multiple instances
            final Once task = new Once();
            for(int j=0;j<5;++j) { // multiple calls of same instance
                executor.submit(() -> {
                    task.run();
                    System.out.println("Result "+Once.result+" count "+Once.count);
                } );
            }
        }
        executor.shutdown();
        try {
            executor.awaitTermination(1, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }           
    }
}

The program should pause, waiting until the first thread has finished, then all other threads should finish printing the result stored from the first run.

程序应该暂停,等待第一个线程完成,然后所有其他线程应该完成打印第一次运行时存储的结果。