开发者

What's a reasonable way to mutate a primitive variable from an anonymous Java class?

开发者 https://www.devze.com 2022-12-29 15:37 出处:网络
I would like to write the following code: boolean found = false; search(new SearchCallback() { @Override void onFound(Object o) { found = true; }

I would like to write the following code:

boolean found = false;
search(new SearchCallback() {
  @Override void onFound(Object o) { found = true; }
});

Obviously this is not allowed, since found needs to be final. I can't make found a member field for thread-safety reasons. What is the best alternative? One workaround is to define

final class MutableReference<T> {
  private T value;
  MutableReference(T value) { this.value = value; }
  T get() { return value; }
  void set(T value) { this.value = value; }
}

but this ends up taking a lot of space when formatted properly, and I'd rather not reinvent the wheel if at all possible. I could use a List<Boolean> with a single element (either mutating that element, or else emptying the list) or even a Boolean[1]. But everything开发者_StackOverflow中文版 seems to smell funny, since none of the options are being used as they were intended.

What is a reasonable way to do this?


I tend to do the boolean[1] method you mentioned:

final boolean[] found = {false};
search(new SearchCallback() {
  @Override void onFound(Object o) { found[0] = true; }
});

It's a bit hackish, but it tends to be the closest thing to what you actually want


You could go all functional:

Boolean found = search(new SearchCallback<Boolean>() {
    @Override Boolean onFound(Object o) { return true; }
});

Usually if you want to mutate an enclosing variable, you can express a solution more clearly by not doing so.


All solutions are indeed hackish, but the array is the "standard" textbook way of handling it, as even pre-generics it was typesafe.

Another option in this situation is to make a private class like so:

   private class Searcher implements SearchCallback {
        private boolean found;
        @Override public void onFound(Object o) { found = true; }
        public boolean search() {
              OuterClass.this.search(this);
              return found;
        }
   }

And then use it like so:

  boolean found = new Searcher().search();

Edit: If I understand Tom's comment correctly, he is suggesting this as an alternative

 public void foo() { //This is the method that enclosed the code in your question
     new SearchCallBack() {
         private boolean found;
         @Override public void onFound(Object o) { found = true; }
         {
            //The code that was before this in your method
            search(this);
            //The code that was after this in your method
         }
     };
 }

I think that is more hackish and I would really find such code unusual, but it is definitely worth knowing that it is an option.


If you really cant use a field, Michael answers seems right.

Anyway. I dont know what signatures you can touch, but it seems to me that that callback is intented to do something (when the search succeeds) with/to the found object. You, instead, are intending to notify the caller of the search method that it found something. It would seems much more natural if your seach() method were made to return a boolean (the method will surely call s.onFound() somewhere if the search succeeds, then set an internal found flag there and return it).

0

精彩评论

暂无评论...
验证码 换一张
取 消