Java Runnable 作为参数评估
Java Runnable as argument evaluation
我正在 java 中开发客户端服务器,我遇到了将自定义 Runnable 实现作为参数从一个对象传递到另一个对象的问题。
问题是 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();
}
上面的代码在 运行 方法中的代码的最后一部分执行时引发 NullPointerException
。
[编辑]
NullPointerException
异常被抛出,因为 getFromChallengeReport()
和 getToChallengeReport()
(代码的第二部分)最初 return null (当 Runnable 被定义并作为参数传递时),
但它们会 return 在调用时保持一致的值 run()
(代码的第三部分)
[EDIT2]
我在这个简单的代码中重现了这种情况:
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
如果您想立即评估某事。我建议根本不要使用 Runnable
。这听起来像是一种反模式,当你想要的只是 value/invocation.
时试图传递代码
此外,尝试改用 Callable 或 Supplier,因为您显然对从子例程返回一些值感兴趣。
一个非常简单的例子。让我们创建一个带有字段的 运行nable。
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,因为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);
}
}
}
这段代码产生了我想要的行为。
希望这会对某人有所帮助。
干杯!
我正在 java 中开发客户端服务器,我遇到了将自定义 Runnable 实现作为参数从一个对象传递到另一个对象的问题。 问题是 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();
}
上面的代码在 运行 方法中的代码的最后一部分执行时引发 NullPointerException
。
[编辑]
NullPointerException
异常被抛出,因为 getFromChallengeReport()
和 getToChallengeReport()
(代码的第二部分)最初 return null (当 Runnable 被定义并作为参数传递时),
但它们会 return 在调用时保持一致的值 run()
(代码的第三部分)
[EDIT2]
我在这个简单的代码中重现了这种情况:
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
如果您想立即评估某事。我建议根本不要使用 Runnable
。这听起来像是一种反模式,当你想要的只是 value/invocation.
此外,尝试改用 Callable 或 Supplier,因为您显然对从子例程返回一些值感兴趣。
一个非常简单的例子。让我们创建一个带有字段的 运行nable。
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,因为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);
}
}
}
这段代码产生了我想要的行为。 希望这会对某人有所帮助。 干杯!