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