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

时间:2010-04-19 08:05:36

标签: java

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

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

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

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

12 个答案:

答案 0 :(得分:39)

当然!..

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

答案 1 :(得分:7)

您可以使用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();
        }
    }
}

用法:

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

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

答案 2 :(得分: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();
        ...
    }
}

答案 3 :(得分:3)

在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;
  });
}

答案 4 :(得分:3)

如果您使用Kotlin,则可以执行以下操作:

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

答案 5 :(得分:2)

或许break关键字是你需要的?运行方法后调用break;对不起,我不清楚你的问题是什么意思。

从sun docs看看here

答案 6 :(得分:2)

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

根据您的目的,可以使用静态初始化块。

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

简单解决方案:

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

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

答案 7 :(得分:1)

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

答案 8 :(得分:1)

我想做些更复杂的事情。在多线程环境中,请确保仅运行一种方法(上述方法已通过Hover Ruan的答案解决了),而且还要阻止任何线程,以便在该方法完成之前不会返回任何线程。

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

function GetFrameBytes(detectionSettings, streamSource, frameNumber, callback)
{
    detectionSettings["streamSource"] = streamSource;
    detectionSettings["frameNumber"] = frameNumber;

    client.GetFrame(detectionSettings, (error, response) =>
    {
        if(!error){
            callback(response)
        }
        else
        {
            console.error(error);
        }
    });
}

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

答案 9 :(得分:1)

或使用共享偏好

    sharedpref = PreferenceManager.getDefaultSharedPreferences(this);


isFirstRun = sharedpref.getBoolean("FIRSTRUN", true);

if (isFirstRun)
{

    // Do your unique code magic here

    SharedPreferences.Editor editor = wmbPreference.edit();
    editor.putBoolean("FIRSTRUN", false);
    editor.commit();
}else{
    //this will repeat everytime 
}

答案 10 :(得分:0)

我的应用中的示例:

boolean alreadyExecuted = false;

然后:

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

答案 11 :(得分:0)

这是一个示例方法。只需使用“ new Getlineonce();”

class Getlineonce {
    static int[] linesRun = new int[0];

    public Getlineonce() {
        boolean lineRan = false;
        int line = Thread.currentThread().getStackTrace()[2].getLineNumber();
        for(int i = 0; i < linesRun.length; i++) {
            if(line == linesRun[i]) {
                lineRan = true; //Dont print
            }
        }

        if(!lineRan) {
            add(line);
            System.out.println(line + " ran!");
        }

    }

    public void add(int line) {
        int newSize = linesRun.length+1;
        int[] linesRunBuff = new int[newSize];
        for(int i = 0; i < newSize-1; i++) {
            linesRunBuff[i] = linesRun[i];
        }
        linesRunBuff[newSize-1] = line;
        linesRun = linesRunBuff;
    }

}