Java 是否可以使一个方法只执行一次?
我有一个for循环和如下结构:Java 是否可以使一个方法只执行一次?,java,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循环中的方法是否可能只执行一次?也许break关键字就是您所需要的?运行方法后调用break;很抱歉,你的问题没
for(....)
....
....
if(isTrue)
... do something..
.. method to be executed once (doTrick) is declared outside for loop.
....endif
endfor
public void doTrick()
...
...
..end
for循环中的方法是否可能只执行一次?也许break关键字就是您所需要的?运行方法后调用break;很抱歉,你的问题没有100%清楚你的意思 从sun文档看一看当然
if(!alreadyExecuted) {
doTrick();
alreadyExecuted = true;
}
您可以使用以下技巧避免使用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();
...
}
}
另一个过度杀戮的解决方案: 根据您想要执行的操作,可以使用静态初始化块
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)
}
import java.util.ArrayList;
类移除副本{
公共静态void main(字符串[]args){
ArrayList originalList=新的ArrayList();
原始列表。添加(“foo”);
原始列表。添加(“条”);
原始列表。添加(“bat”);
原始列表。添加(“baz”);
原始列表。添加(“条”);
原始列表。添加(“条”);
String str=“bar”;
ArrayList duplicateList=新的ArrayList();
//将重复项添加到重复项列表
for(字符串currentString:originalList){
if(currentString.startsWith(str)){
duplicateList.add(当前字符串);
}
}
//删除duplicatesList中的重复项
用于(字符串重新投资:重复列表){
原始列表。移除(重新投资);
}
//最后添加重复元素
原始列表添加(str);
for(字符串currEntry:originalList){
系统输出打印项次(currEntry);
}
}
}
我的应用程序示例:
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);
}
在Java 8中,您可以使用如下所述的自动备忘录来有效地执行此操作: 我承认,对于“运行一次”的场景来说,记忆可能被认为是过火了,但它与前面的答案中描述的一些场景相比,是一个相当干净的替代方案 例如:
public void doSomething() { ... }
Map<Boolean, Boolean> cache = new ConcurrentHashMap<>();
public void doSomethingOnce() {
cache.computeIfAbsent(true, x -> {
doSomething();
return true;
});
}
public void doSomething(){…}
映射缓存=新的ConcurrentHashMap();
公共无效doSomethingOnce(){
cache.computeIfAbsent(true,x->{
doSomething();
返回true;
});
}
您可以使用AtomicBoolean
确保只在第一次调用任务:
import java.util.concurrent.atomic.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();
}
}
}
用法:
Once once = new Once();
once.run(new Runnable() {
@Override
public void run() {
foo();
}
});
// or java 8
once.run(() -> foo());
如果使用kotlin,可以执行以下操作:
val由lazy执行一次{
打印(“你好,世界”)
}
我想做一些稍微复杂一点的事情。在多线程环境中,确保只运行一个方法(这由上面的Hover Ruan的答案解决),但还要阻止任何线程,以便在方法完成之前不会返回任何线程
我的解决方案是使用信号量进行阻塞
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();
}
}
}
public类一旦实现Runnable{
私有静态信号量信号=新信号量(1,真);
私有静态布尔值done=false;
@凌驾
公开募捐{
如果(完成)
返回;
信号。不间断地获取();
如果(完成){
信号。释放();
返回;
}
doTrick();//实际运行任务
完成=正确;
信号。释放();
返回;
}
static int result;//运行任务的结果
静态int count;//调用它的次数
/**
*我们只想运行一次的任务
*/
公共空间{
++计数;
随机rnd=新随机();
对于(int i=0;i,这里有一个示例方法。只需使用“new Getlineonce();”
class Getlineonce{
静态int[]linesRun=新int[0];
公共Getlineonce(){
布尔lineRan=false;
int line=Thread.currentThread().getStackTrace()[2].getLineNumber();
对于(int i=0;i
或使用共享首选项:
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
}
“所有大写字母都意味着它是首字母缩写词,而事实并非如此。@Gandalf它不是首字母缩写词,而是一个名称,所以你不用大写字母书写。我们都知道我的意思,所以正如James所说,没有什么不同。在多线程环境中,你可能希望同步该块。虽然alreadyExecuted可能是一个局部变量though、 这会管用,但有点过分了,不是吗?罗斯迪的答案更简单/更清楚。@Tomas:拓展你的视野:-)@vickirk:这是针对这样一个简单的案例。一旦情况变得更复杂,你需要不止一次“跑一次”对于每个循环,这个技巧可以变得更具可读性,因为您可以以很低的成本从循环中提取代码。对不起,我不相信,如果if中的代码很复杂,那么请将其移动到一个私有方法中,如果逻辑变得更复杂,那么op将需要在此时进行重构,可能会沿着策略/模板方法路线进行重构。这种方式使单元测试变得更加复杂,使用runnable会让开发人员试图找出线程在何处变得复杂。聪明。:)我使用C编写了一个代码库,它通过将指针移到全局void nil()来做类似的事
method。似乎是同一个想法!中断会立即结束for循环。由于循环包含的代码比方法调用多,我假设中断不是故意的。-1第一个解决方案是多余的,第二个解决方案不在循环中。这与问题有何关系?import java.util.concurrent.atomic.AtomicBoolean;
注意第二次调用Once.run(Runnable)
可能会在第一次调用之前返回
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;
}
}
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
}