Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java8 - "effectively final"

I'm using RxVertx which is a sort of RxJava along with Java8 and I have a compilation error.

Here is my code:

public rx.Observable<Game> findGame(long templateId, GameModelType game_model, GameStateType state) {

return context.findGame(templateId, state)
    .flatMap(new Func1<RxMessage<byte[]>, rx.Observable<Game>>() {

        @Override
        public Observable<Game> call(RxMessage<byte[]> gameRawReply) {

            Game game = null;

            switch(game_model) {

                case SINGLE: {

                    ebs.subscribe(new Action1<RxMessage<byte[]>>() {

                        @Override
                        public void call(RxMessage<byte[]> t1) {

                            if(!singleGame.contains(0) {
                                game = new Game();       // ERROR is at this line
                                singleGames.put(0, game);
                            } else {
                              game = singleGames.get(0); // ERROR is at this line
                            }
                        }
                    });
                }
            }

            return rx.Observable.from(game);
        }
    });
}

The compilation error is: "Local variable game defined in an enclosing scope must be final or effectively final"

I cannot define 'game' as final since I do allocation\set and return it at the end of the function.

How can I make this code compile??

Thanks.

like image 574
Shvalb Avatar asked Dec 25 '22 03:12

Shvalb


2 Answers

I have a Holder class that I use for situations like this.

/**
 * Make a final one of these to hold non-final things in.
 *
 * @param <T>
 */
public class Holder<T> {
  private T held = null;

  public Holder() {
  }

  public Holder(T it) {
    held = it;
  }

  public void hold(T it) {
    held = it;
  }

  public T held() {
    return held;
  }

  public boolean isEmpty() {
    return held == null;
  }

  @Override
  public String toString() {
    return String.valueOf(held);
  }

}

You can then do stuff like:

final Holder<Game> theGame = new Holder<>();
...

theGame.hold(myGame);
...
{
  // Access the game through the `final Holder`
  theGame.held() ....
like image 120
OldCurmudgeon Avatar answered Dec 28 '22 07:12

OldCurmudgeon


Since you need to not modify the reference of the object you can wrap the Game in something else.

The quickest (but ugly) fix is to use an array of size 1, then set the content of the array later. This works because the the array is effectively final, what is contained in the array doesn't have to be.

@Override
    public Observable<Game> call(RxMessage<byte[]> gameRawReply) {

        Game[] game = new Game[1];

        switch(game_model) {

            case SINGLE: {

                ebs.subscribe(new Action1<RxMessage<byte[]>>() {

                    @Override
                    public void call(RxMessage<byte[]> t1) {

                        if(!singleGame.contains(0) {
                            game[0] = new Game();       
                            singleGames.put(0, game[0]);
                        } else {
                          game[0] = singleGames.get(0);
                        }
                    }
                });
            }
        }

        return rx.Observable.from(game[0]);
    }

Another similar option is to make a new class that has a Game field and you then set that field later.

like image 42
dkatzel Avatar answered Dec 28 '22 05:12

dkatzel