Java8 - “有效最终”

时间:2014-10-02 14:57:45

标签: java lambda java-8 rx-java

我使用的是RxVertx,这是一种RxJava和Java8,我有编译错误。

这是我的代码:

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);
        }
    });
}

编译错误是: &#34;在封闭范围内定义的局部变量游戏必须是最终的或有效的最终版本&#34;

我无法定义游戏&#39;因为我做了分配\ set并在函数结束时返回它。

如何编译此代码?

感谢。

6 个答案:

答案 0 :(得分:6)

我有一个Holder课,我在这种情况下使用它。

/**
 * 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);
  }

}

然后您可以执行以下操作:

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

theGame.hold(myGame);
...
{
  // Access the game through the `final Holder`
  theGame.held() ....

答案 1 :(得分:2)

由于您不需要修改对象的引用,因此可以将Game包装在其他内容中。

最快(但很难看)修复是使用大小为1的数组,然后稍后设置数组的内容。这是有效的,因为数组实际上是最终的,数组中包含的内容不一定是。

@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]);
    }

另一个类似的选项是创建一个具有Game字段的新类,然后再设置该字段。

答案 2 :(得分:1)

CyclopsMutable个和LazyImmutable个对象来处理这个用例。 Mutable完全可变,LazyImmutable设置一次。

 Mutable<Game> game = Mutable.of(null);

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

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

LazyImmutable可用于懒惰地设置一次值:

LazyImmutable<Game> game = LazyImmutable.def();

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

     //new Game() is only ever called once
     Game g = game.computeIfAbsent(()->new Game());
}

答案 3 :(得分:0)

你不能。至少不是直接的。你可以使用包装类:只需定义一个以游戏为属性的类“GameContainer”,然后改为对该容器进行最终引用。

答案 4 :(得分:0)

@ dkatzel的建议很好,但还有另一种选择:将关于检索/创建游戏的所有内容提取到辅助方法中,然后声明final Game game = getOrCreateGame();。我认为这比最终的阵列方法更清晰,尽管最终的阵列方法肯定会有用。

答案 5 :(得分:0)

虽然其他方法看起来可以接受,但我想提一下,您无法确定订阅ebs是否会同步,您可能最终总是从内部函数返回null。由于您依赖于另一个Observable,您只需通过以下方式编写它:

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

    return context.findGame(templateId, state)
    .flatMap(gameRawReply -> {
        switch(game_model) {
        case SINGLE: {
            return ebs.map(t1 -> {
                Game game;
                if (!singleGame.contains(0) {
                    game = new Game();
                    singleGames.put(0, game);
                } else {
                    game = singleGames.get(0);
                }
                return game;
            });
        }
        }

        return rx.Observable.just(null);
    });
}