局部变量必须是最终的或有效的最终

时间:2016-01-02 21:08:44

标签: java java-8

我在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;

}

2 个答案:

答案 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;