我在Java 8中有一个异步操作,它返回一个onError回调或onSuccess回调。如果操作成功与否,我需要返回我的方法内部。所以我返回一个布尔值来说明这个信息。我遇到的问题是我得到以下编译错误:
错误:从内部类引用的局部变量必须是final或 有效的最终
谷歌搜索错误我可以看到你不允许这种类型的操作,但是如果操作成功与否,我怎么能回来?
public Boolean addUser(String email, String password) {
Boolean isSuccess = false;
Map<String, AttributeValue> item = new HashMap<String, AttributeValue>();
item.put("email", new AttributeValue(email)); //email
item.put("password", new AttributeValue(password)); //password
dynamoDB.putItemAsync(new PutItemRequest().withTableName("Users").withItem(item), new AsyncHandler() {
@Override
public void onError(Exception excptn) {
}
@Override
public void onSuccess(AmazonWebServiceRequest rqst, Object result) {
isSuccess = true;
}
});
return isSuccess;
}
答案 0 :(得分:8)
首先,我将解释错误信息的含义,然后我将告诉您设计有什么问题,并建议做什么。
首先是错误信息。 isSuccess
是一个局部变量,也就是说,一旦方法addUser
完成,它就消失了。但是,您创建的AsyncHandler
实例可能会比这更长。如果是,它将指的是不再存在的变量。
如果变量是最终的或有效的最终变量,这不会成为问题。然后我们就知道变量永远不会改变,所以我们可以将变量复制到新创建的对象并引用该副本。请注意,在引用变量的情况下,引用不会发生变化,它所引用的对象可能仍会被修改。
为了避免这个问题,Java的创建者已经决定从匿名内部类(或lambda表达式)中不能引用非最终(或有效最终)的局部变量。错误消息告诉您,您正是这样做的。
所以现在你的设计。您的设计无法以这种方式工作。 AsyncHandler
实例可能会持续到方法完成之后。它的方法可能会在不同的线程中执行,因此在addUser
方法完成后调用其方法很可能。那么addUser
应该返回什么?在它完成的那一刻,它甚至可能不知道操作是否成功!
您执行异步操作,即在另一个线程上执行操作。此操作可能需要1毫秒,或1分钟,甚至10年。如果要查看该操作是否成功,则必须以某种方式将其结果传递给执行addUser
的线程。
线程间通信不是一项简单的任务,但您很幸运:putItemAsync
返回Future
个实例,而Future
类的目的正是为了您想做:找出异步操作是否已经完成并获得结果。
要检查异步操作是否已完成,请轮询返回的isDone()
的{{1}}方法。如果完成,您可以通过调用Future
的{{1}}方法获取操作结果。如果操作由于抛出异常而异常中止,get()
将抛出Future
,其get()
是抛出异常。
或者,当然,您决定使用ExecutionException
方法同步(在同一个线程上)运行操作。然后你的方法将等待操作完成,你立即得到结果。
答案 1 :(得分:1)
这不是一个好习惯,也可能不起作用。在您的代码中,new AsyncHandler()
将在单独的线程中运行。由于它不是阻塞调用,因此主线程不会等待它完成。
所以,会发生的事情是,在调用dynamoDB.putItemAsync(...)
之后,即使在AsyncHandler()
完成执行之前,return语句也会执行并更改isSuccess
的值。这意味着,return isSuccess;
可能会返回默认值false
。
注意:如果您真的想这样做,可以将布尔变量设为 field 变量。
public boolean isSuccess = false;