196

我需要一个“接受参数的 Runnable”,尽管我知道这样的 runnable 并不存在。

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

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

知道如何完成类似上述的事情吗?

4

9 回答 9

247

自从我最初发布这篇文章以来已经快 9 年了,老实说,从那时起 Java 已经做了一些改进。我将在下面留下我原来的答案,但人们不需要做其中的事情。9 年前,在代码审查期间,我会质疑他们为什么这样做,也许批准了,也许没有。有了现代 lambda 表达式,有如此高票数的答案推荐过时的方法是不负责任的(公平地说,一开始是可疑的......)在现代 Java 中,代码审查将立即被拒绝,这将是建议:

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

和以前一样,以有意义的方式处理该线程之类的细节留给读者作为练习。但是说白了,如果你害怕使用 lambda,那你应该更害怕多线程系统。

原始答案,只是因为:

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

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();
}
于 2011-05-02T03:17:52.703 回答
52

你可以把它放在一个函数中。

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 的哈希图 --> myRunnables。这样,我可以使用哈希图在处理程序中发布/删除不同的 myRunnable 对象。)

于 2012-04-19T23:18:27.547 回答
34
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));

创建返回对象本身并用它初始化参数的初始化函数。

于 2013-05-23T17:49:25.667 回答
17

从 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) )

...
于 2020-01-09T09:21:12.077 回答
11

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

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;
    }
}
于 2014-01-30T15:42:00.273 回答
10

你有两个选择:

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

  2. 让您的匿名课程关闭您的“参数”。请务必将其标记为final

于 2011-05-02T03:18:34.517 回答
5

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

于 2011-05-02T03:20:42.053 回答
1
/**
 * @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;
    }
}
于 2021-08-04T16:11:03.073 回答
0

迄今为止最好的方法:

Consumer<String> oneShot = str -> {
    
   somefunc(str);
    
};

oneShot.accept("myString");
于 2021-11-14T13:39:06.803 回答