2014-10-02 3 views
4

RxVertx를 Java8과 함께 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을하고 함수의 끝에서 그것을 반환하기 때문이다.

어떻게이 코드를 컴파일 할 수 있습니까 ??

감사합니다.

+1

'public void call'이 바로 실행됩니까? 나는이 코드가 당신이 생각하는 바를 잘 모르겠다. – Sebas

+0

[최종 로컬 변수를 할당 할 수 없다] 가능한 복제본 (http : // stackoverflow.com/questions/10166521/final-local-variable-can-assign-un-assigned) – user11153

+0

Sebas : 당신 말이 맞아요, 저는 RxJava에 새로운 브랜드이고 이해하기 힘들었습니다. 하지만 주로 한 번에 하나의 문제를 해결하려고합니다 :-) – Shvalb

답변

4

나는 이런 상황에 대해 사용하는 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() .... 
+0

깨끗하고 간단한 래퍼. – Shvalb

+0

좋아, 솔루션을 더 잘 살펴본 후 - 더 깔끔하고 견고하기 때문에 선택했습니다. 감사합니다. – Shvalb

+2

'toString' 메쏘드에 대해서는 문자열이 null이면 null을 반환하고 그렇지 않은 경우에는 held.toString()을 호출하면 실제로 String.valueOf (held)를 할 수 있습니다. – insumity

0

수 없습니다. 적어도 직접적으로. 그러나 래퍼 클래스를 사용할 수 있습니다. 게임을 속성으로 사용하여 클래스 "GameContainer"를 정의하고 대신이 컨테이너에 대한 최종 참조를 전달하십시오.

+0

나는 dkatzel이 제안한 것을 할 것이다. – Shvalb

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 필드가 새로운 클래스를 만드는 것입니다 그리고 당신은 그 분야 나중에 설정합니다.

+0

당신이 말했듯이 : "못 생겼어"-하지만 더 좋은 해결책이 생길 때까지! 감사합니다 :-) – Shvalb

0

@ dkatzel의 제안은 좋은 방법이지만 다른 옵션이 있습니다. 게임을 검색/생성하여 도우미 메서드로 추출한 다음 final Game game = getOrCreateGame();을 선언하십시오. 최종 배열 접근 방식이 확실히 작동 할지라도 최종 배열 접근 방식보다 더 깨끗하다고 ​​생각합니다.

1

CyclopsMutable을 가지고 있으며,이 사용 사례를 처리하기위한 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()); 
} 
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); 
    }); 
}