Java Runnable作为参数评估



我正在用java开发一个客户端服务器,在将自定义Runnable实现作为参数从一个对象传递到另一个对象时遇到了问题。问题是Runnable代码是在定义时评估(而不是执行(的,但我希望它在调用时评估。有什么方法可以实现这种行为吗?

受此问题影响的代码如下:

  • 自定义可运行实现
public abstract class ChallengeReportDelegation implements Runnable
{
private ChallengeReport fromChallengeReport = null;
private ChallengeReport toChallengeReport = null;
@Override
public abstract void run();
public ChallengeReport getFromChallengeReport()
{
return fromChallengeReport;
}
public ChallengeReport getToChallengeReport()
{
return toChallengeReport;
}
public void setFromChallengeReport(ChallengeReport fromChallengeReport)
{
this.fromChallengeReport = fromChallengeReport;
}
public void setToChallengeReport(ChallengeReport toChallengeReport)
{
this.toChallengeReport = toChallengeReport;
}
}
  • 这里Runnable作为参数传递:
// Record challenge
this.challengesManager.recordChallenge(whoSentRequest, whoConfirmedRequest,
new ChallengeReportDelegation()
{
@Override
public void run()
{
ChallengeReport fromReport = getFromChallengeReport();
ChallengeReport toReport = getToChallengeReport();
sendMessage(whoSentRequest, new Message(MessageType.CHALLENGE_REPORT, String.valueOf(fromReport.winStatus), String.valueOf(fromReport.challengeProgress), String.valueOf(fromReport.scoreGain)));
sendMessage(whoConfirmedRequest, new Message(MessageType.CHALLENGE_REPORT, String.valueOf(toReport.winStatus), String.valueOf(toReport.challengeProgress), String.valueOf(toReport.scoreGain)));
}
});
  • 接收对象将ChallengeReportDelegation实例存储为completionOperation,等待超时,然后执行此代码
private void complete()
{
stopTranslations();
int fromStatus;
int toStatus;
if (this.fromScore > this.toScore)
{
fromStatus = 1;
toStatus = -1;
}
else if (this.fromScore < this.toScore)
{
fromStatus = -1;
toStatus = 1;
}
else
{
fromStatus = 0;
toStatus = 0;
}
this.completionOperation.setFromChallengeReport(new ChallengeReport(this.from, fromStatus,this.fromTranslationsProgress, this.fromScore));
this.completionOperation.setToChallengeReport(new ChallengeReport(this.to, toStatus, this.toTranslationsProgress, this.toScore));
this.completionOperation.run();
}

上面的代码在run方法中执行代码的最后一部分时引发NullPointerException

[编辑]

抛出CCD_ 4异常是因为CCD_ 5和CCD_,但它们将在调用时返回一致的值run()(代码的第三部分(

[编辑2]

我在这个简单的代码中重现了这种情况:

public class TestEvaluation
{
public static void main(String[] args) throws InterruptedException
{
Middle middle = new Middle();
middle.register(new Task() {
@Override
public void run() {
System.out.println("a is: " +  getA());
System.out.println("b is: " +  getB());
}
});
Thread.sleep(2000);
}
abstract static class Task implements Runnable
{
private int a = 0;
private int b = 0;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
@Override
abstract public void run();
}
static class Middle
{
private ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(1);
public void register(Task task)
{
Leaf leaf = new Leaf(new Task() {
@Override
public void run() {
System.out.println("Middle");
task.run();
}
});
pool.schedule(leaf, 1, TimeUnit.SECONDS);
}
}
static class Leaf implements Runnable
{
public Task task;
public Leaf(Task task)
{
this.task = task;
}
@Override
public void run()
{
task.setA(5);
task.setB(5);
System.out.println("Leaf");
task.run();
}
}
}

我想要实现的行为是打印

Leaf
Middle
a is: 5
b is: 5

但这就是我得到的

Leaf
Middle
a is: 0
b is: 0

一个非常简单的例子。让我们创建一个带有字段的可运行程序。

public static void main (String[] args) {
var x = new Runnable(){
int a = 0;
int getA(){
return a;
}
void setA(int v){
a = v;
}
public void run(){
System.out.println("A : " + getA());
}
};
x.run();
x.setA(5);
x.run();
}

第一次是0,第二次是5,因为调用run时会计算getA。

我为这个问题找到了一个有效的解决方案,对于那些来自函数式编程的人来说,这可能是微不足道的。

根据上次编辑([EDIT2](中的示例

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
public class TestEvaluation
{
public static void main(String[] args) throws InterruptedException
{
Middle middle = new Middle();
middle.register(new Consumer<Values>() {
@Override
public void accept(Values values) {
System.out.println("a is: " +  values.getA());
System.out.println("b is: " +  values.getB());
}
});
Thread.sleep(2000);
}
static class Values
{
private int a = 0;
private int b = 0;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
}
static class Middle
{
private ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(1);
public void register(Consumer<Values> passed)
{
Consumer<Values> middleConsumer = new Consumer<Values>() {
@Override
public void accept(Values values) {
System.out.println("Middle");
passed.accept(values);
}
};
Leaf leaf = new Leaf(middleConsumer);
pool.schedule(leaf, 1, TimeUnit.SECONDS);
}
}
static class Leaf implements Runnable
{
public Consumer<Values> task;
public Leaf(Consumer<Values> task)
{
this.task = task;
}
@Override
public void run()
{
Values values = new Values();
values.setA(5);
values.setB(5);
System.out.println("Leaf");
task.accept(values);
}
}
}

这段代码产生了我想要的行为。希望这能帮助到别人。干杯

如果您想立即评估某个内容。我建议不要使用Runnable。这听起来像是一种反模式,当你想要的只是值/调用时,试图传递代码。

此外,请尝试使用Callable或Supplier,因为您显然有兴趣从子程序中返回一些值。

最新更新