简体   繁体   中英

Assign a value to a final variable

Suppose I have this code:

public HttpResponse myFunction(...) {
    final HttpResponse resp;
    OnResponseCallback myCallback = new OnResponseCallback() {
        public void onResponseReceived(HttpResponse response) {
            resp = response;
        }
    };
    // launch operation, result will be returned to myCallback.onResponseReceived()
    // wait on a CountDownLatch until operation is finished
    return resp;
}

Obviously I can not assign a value to resp from onResponseReceived because it is a final variable, BUT if it was not a final variable onResponseReceived could not see it. Then, how can I assign a value to resp from onResponseReceived?

What I thought is to create a wrapper class for enclosing the resp object. The final object would be an instance of this wrapper class and I could assign the value to resp working on the object inside the final class (which is not final).

The code would be this one:

class ResponseWrapper {
    HttpResponse resp = null;
}

public HttpResponse myFunction(...) {
    final ResponseWrapper respWrap = new ResponseWrapper();
    OnResponseCallback myCallback = new OnResponseCallback() {
        public void onResponseReceived(HttpResponse response) {
            respWrap.resp = response;
        }
    };
    // launch operation, result will be returned to myCallback.onResponseReceived()
    // wait on a CountDownLatch until operation is finished
    return respWrap.resp;
}

What do you think about this solution?

java.util.concurrent.atomic.AtomicReference

Standard practice is to use a final AtomicReference, which you can set and get. This adds the benefit of thread safety as well :) As you mentioned, a CountDownLatch is helpful in waiting for completion.

Your solution is as valid as any other. Other popular choices include the one element array

final HttpResponse[] resp = new Response[1];
// In the callback
resp[0] = response;
// After the operation
return resp[0];

and the generic wrapper

public class Ref<T> {
  public T value;
}

final Ref<HttpResponse> resp;
// In the callback
resp.value = response;
// After the operation
return resp.value;

You can combine the hand-back and the wait into one using a SynchronousQueue (exception handling omitted)

public HttpResponse myFunction(...) {
    final Queue<HttpResponse> resp = new SynchronousQueue<HttpResponse>();
    OnResponseCallback myCallback = new OnResponseCallback() {
        public void onResponseReceived(HttpResponse response) {
            resp.put(response);
        }
    };
    return resp.take();
}

The change I would make would be to use an AtomicReference since this is obviously multi-threaded and you wouldn't have to write your own wrapper. Otherwise, seems reasonable to me.

You can make it mutable and final ;) The simplest approach is to use na array but an AtomicReference can also be used.

public HttpResponse myFunction(...) {
    final HttpResponse[] resp = { null };
    OnResponseCallback myCallback = new OnResponseCallback() {
        public void onResponseReceived(HttpResponse response) {
            resp[0] = response;
        }
    };
    // launch operation, result will be returned to myCallback.onResponseReceived()
    // wait on a CountDownLatch as soon as operation is finished
    return resp[0];
}

or

public HttpResponse myFunction(...) {
    final AtomicReference<HttpResponse> resp = new AtomicReference<HttpResponse>();
    OnResponseCallback myCallback = new OnResponseCallback() {
        public void onResponseReceived(HttpResponse response) {
            resp.set(response);
        }
    };
    // launch operation, result will be returned to myCallback.onResponseReceived()
    // wait on a CountDownLatch as soon as operation is finished
    return resp.get();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM