带参数的可运行?

我需要一个“接受参数的可运行对象”,尽管我知道这样的可运行对象实际上并不存在。

这可能是我的应用程序设计的根本缺陷和/或我疲惫的大脑中的一个心理障碍,所以我希望在这里找到一些关于如何完成以下事情的建议,没有违反基本的OO原则:

  private Runnable mOneShotTask = new Runnable(String str) {
public void run(String str) {
someFunc(str);
}
};

你知道如何完成上面的事情吗?

217930 次浏览

从我最初发表这篇文章到现在已经快9年了,老实说,从那时起Java已经做了一些改进。我将把我最初的答案留在下面,但人们没有必要按照里面的内容去做。9年前,在代码审查期间,我会质疑他们为什么要这样做,也许会批准,也许不会。在现代lambdas可用的情况下,有这样一个高度投票的答案推荐一种过时的方法是不负责任的(公平地说,一开始就很可疑……)在现代Java中,这种代码审查会立即被拒绝,建议如下:

void foo(final String str) {
Thread t = new Thread(() -> someFunc(str));
t.start();
}

像以前一样,以一种有意义的方式处理线程之类的细节留给读者练习。但是坦率地说,如果您害怕使用lambdas,那么您应该更害怕多线程系统。

原来的答案,只是因为:

你可以在方法中声明一个类

void Foo(String str) {
class OneShotTask implements Runnable {
String str;
OneShotTask(String s) { str = s; }
public void run() {
someFunc(str);
}
}
Thread t = new Thread(new OneShotTask(str));
t.start();
}

你有两个选择:

  1. 定义一个命名类。将参数传递给命名类的构造函数。

  2. 让你的匿名类关闭你的“参数”。请确保将其标记为final

我首先想知道你在这里要完成什么,需要一个参数传递给new Runnable()或run()。 通常的方法应该是有一个Runnable对象,它通过在启动前设置成员变量将数据(str)传递给它的线程。run()方法然后使用这些成员变量值执行someFunc()

你可以把它放到一个函数里。

String paramStr = "a parameter";
Runnable myRunnable = createRunnable(paramStr);


private Runnable createRunnable(final String paramStr){


Runnable aRunnable = new Runnable(){
public void run(){
someFunc(paramStr);
}
};


return aRunnable;


}

(当我使用这个时,我的参数是一个整数ID,我用它来创建ID的hashmap——> myRunnables。这样,我可以使用hashmap在处理程序中发布/删除不同的myRunnable对象。)

theView.post(new Runnable() {
String str;
@Override
public void run() {
par.Log(str);
}
public Runnable init(String pstr) {
this.str=pstr;
return(this);
}
}.init(str));

创建init函数,返回对象本身并初始化参数。

我使用下面的类来实现可运行的接口。使用这个类,您可以轻松地创建带有参数的新线程

public abstract class RunnableArg implements Runnable {


Object[] m_args;


public RunnableArg() {
}


public void run(Object... args) {
setArgs(args);
run();
}


public void setArgs(Object... args) {
m_args = args;
}


public int getArgCount() {
return m_args == null ? 0 : m_args.length;
}


public Object[] getArgs() {
return m_args;
}
}

从Java 8开始,最好的答案是使用Consumer<T>:

https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html

它是函数接口之一,这意味着你可以将它作为lambda表达式调用:

void doSomething(Consumer<String> something) {
something.accept("hello!");
}


...


doSomething( (something) -> System.out.println(something) )


...
/**
* @author AbdelWadoud Rasmi
* <p>
* The goal of this class is to pass some parameters to a runnable instance, a good example is
* after caching a file you need to pass the new path to user to do some work on it.
*/
public abstract class ParameterizedRunnable implements Runnable {
private Object[] params;


/**
* @param params: parameters you want to pass the the runnable.
*/
public ParameterizedRunnable(Object... params) {
this.params = params;
}


/**
* Code you want to run
*
* @param params:parameters you want to pass the the runnable.
*/
protected abstract void run(Object... params);


@Override
public final void run() {
run(params);
}


/**
* setting params
*/
public void setParams(Object... params) {
this.params = params;
}


/**
* getting params
*/
public Object[] getParams() {
return params;
}
}

目前为止最好的方法:

Consumer<String> oneShot = str -> {
    

somefunc(str);
    

};


oneShot.accept("myString");