我使用的是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并在函数结束时返回它。
如何编译此代码?
感谢。
答案 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)
Cyclops有Mutable个和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)
答案 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);
});
}