local variables must be final or effectively final

我是研究僧i 提交于 2020-01-03 04:30:07

问题


I have an async operation inside of Java 8 which return an onError callback or an onSuccess callback. I need to return inside of my method if the operation was a success or not. So I am returning a boolean to state this information. The problem I am facing is I get the following compilation error:

error: local variables referenced from an inner class must be final or effectively final

Googling the error I can see you this type of operation is not allowed, but then how can I return if the operation was a success or not?

 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;

}

回答1:


This is not a good practice and also, it might not work. In your code, new AsyncHandler() will be running in a separate thread. Since it's not a blocking call, main thread will not wait for it's completion.

So, what will happen is, just after calling dynamoDB.putItemAsync(...), the return statement will get executed even before your AsyncHandler() finishes it's execution and changes the value of isSuccess. That means, return isSuccess; might return the default value false.

Note: If you really want to do it this way, you can make the boolean variable as a field variable.

public boolean isSuccess = false;



回答2:


First I will explain what the error message means, then I will tell you what is wrong with your design and suggest what to do.

First, the error message. isSuccess is a local variable, that is, as soon as the method addUser finishes, it is gone. However, the AsyncHandler instance you create might live longer than that. If it does, it would refer to a variable which doesn't exist anymore.

This would not be a problem if the variable were final or effectively final. Then we would know that the variable will never change, so we could just copy the variable to the newly created object and refer to that copy. Note that in case of a reference variable, it is the reference that doesn't change, the object it refers to might still be modified.

To circumvent this problem, the creators of Java have decided that from an anonymous inner class (or a lambda expression) you cannot refer to a local variable that is not final (or effectively final). The error message tells you that you're doing exactly that.

So now to your design. Your design cannot work in this way. The AsyncHandler instance will probably live until after the method finishes. Its methods will be probably executed in a different thread, so it's likely that its methods are called after your addUser method finishes. So what should addUser return? At the moment that it finishes, it might not even know whether the operation was successful not!

You perform an operation asynchronously, that is, on a different thread. This operation might take 1 millisecond, or 1 minute, or even 10 years. If you want to see if that operation was successful, you must somehow communicate its result to the thread that executes addUser.

Inter-thread communication is not a trivial task, but you're lucky: the putItemAsync returns a Future instance, and the Future class is intended for exactly what you want to do: find out if an asynchronous operation has finished and obtain its result.

To check whether the asynchronous operation has finished, poll the isDone() method of the returned Future. If it finished, you can obtain the result of the operation by calling the get() method of the Future. If the operation was aborted abnormally because it threw an exception, get() will throw an ExecutionException whose getCause() is the thrown exception.

Or, of course, you decide to run the operation synchronously (on the same thread) using the putItem method. Then your method will wait for the operation to finish and you have the result immediately.



来源:https://stackoverflow.com/questions/34570747/local-variables-must-be-final-or-effectively-final

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!