[英]Java8 - “effectively final”
我正在使用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);
}
});
}
編譯錯誤是:“在封閉范圍內定義的局部變量游戲必須是最終的或有效的最終”
我無法將'游戲'定義為最終,因為我在分配\\ set並在函數結束時返回它。
我怎樣才能編譯這段代碼?
謝謝。
我有一個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() ....
由於您不需要修改對象的引用,因此您可以將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
字段的新類,然后再設置該字段。
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());
}
你不能。 至少不是直接的。 你可以使用包裝類:只需定義一個以游戲為屬性的類“GameContainer”,然后改為對該容器進行最終引用。
@ dkatzel的建議很好,但還有另一種選擇:將關於檢索/創建Game的所有內容提取到幫助方法中,然后聲明final Game game = getOrCreateGame();
。 我認為這比最終的陣列方法更清晰,盡管最終的陣列方法肯定會有效。
雖然其他方法看起來可以接受,但我想提一下,你不能確定訂閱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);
});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.