2011-05-02 4 views
7

그래서 생성자에서 DatagramSocket을 초기화하려고하는데이 필드가 final이 되길 원하지만 내 컴파일러 (예 : Eclipse)는 나에게 다음 오류 :생성자 내의 try-catch 블록에서 최종 필드 할당하기

The blank final field datagramSocket may not have been initialized

이것은 이해할 수 있습니다. 코드 스 니펫은 다음과 같습니다.

public class Foo 
    { 
     private final int DEFAULT_UDPLISTENPORT = 49400; 
     private final DatagramSocket datagramSocket; 

     public Foo() 
     { 
      synchronized(this) 
      { 
       try 
       { 
        datagramSocket = new DatagramSocket(DEFAULT_UDPLISTENPORT); 
       } 
       catch (SocketException e) 
       { 
        // Log error 
        logger.error("Trouble opening UDP port: ", e); 
       } 
      } 
     } 
    } 

이제 이것을 우회하는 방법이 있지만 임시 변수를 만들어야합니다.

public class Foo 
    { 
     private final int DEFAULT_UDPLISTENPORT = 49400; 
     private final DatagramSocket datagramSocket; 

     public Foo() 
     { 
      synchronized(this) 
      { 
       DatagramSocket tempSocket = null; 
       try 
       { 
        tempSocket = new DatagramSocket(DEFAULT_UDPLISTENPORT); 
       } 
       catch (SocketException e) 
       { 
        // Log error 
        logger.error("Trouble opening UDP port: ", e); 
       } 

       datagramSocket = tempSocket; 
      } 
     } 
    } 

그래서, 내 질문은 가정 :이 일을 더 우아한 방법이 있나요, 아니면 그냥 내가 원하는 경우 살 해야이 뭔가 여기에 코드입니다 그 필드는 final이 될까요?

편집 : 관심이있는 분들을 위해

, 여기에 내가 당신의 권고에서 함께했다 솔루션입니다 :

public class Foo 
{ 
    private static final Foo INSTANCE; 
    static 
    { 
     try 
     { 
      INSTANCE = new Foo(); 
     } 
     catch (SocketException e) 
     { 
      throw new ExceptionInInitializerError(e); 
     } 
    } 
    private final int DEFAULT_UDPLISTENPORT = 49400; 
    private final DatagramSocket datagramSocket; 

    public Foo() throws SocketException 
    { 
     synchronized (this) 
     { 
      datagramSocket = new DatagramSocket(DEFAULT_UDPLISTENPORT); 
     } 
    } 

    public static Foo getInstance() 
    { 
     return INSTANCE; 
    } 
} 

날이 올 알고, 또는 경우 주시기 바랍니다 다른 제안이 있습니다. 도움에 감사드립니다!

+1

질문 : SocketException의 경우에는 어떻게해야합니까? –

+0

글쎄, 그건 일종의 부적절한 일이지만, 지금은 응용 프로그램이 사용자에게 알리고 그 다음에 종료되도록 처리합니다. – mre

+1

관련성이 있습니다 : SocketException의 경우, tempSocket은 여전히'null'이고'datagramSocket'도 마찬가지입니다. 아마도 당신이 원하는 것이 아니기 때문에 @ 칼의 해결책이 당신이 정말로 원하는 것일 수 있습니다. –

답변

11

예, SocketException을 catch 한 후 런타임 예외로 감싸서 다시 던집니다. 변수가 final이고 개체 초기화 중 오류가 발생했기 때문에 개체의 상태가 잘못되었을 수 있으며 개체가 그대로 유지됩니다.

예외 처리에 대한 로깅은 예외 처리 및 숨기기로 충분하지 않습니다. SocketException은 개체가 유효하지 않다는 사실을 숨기고 계속해서 NullPointerException 또는 다른 위험을 감수 할 수 있도록합니다. DatagramSocket를 서브 클래 싱하고 만드는 것이 좋습니다 : null를 반환으로

public Foo() 
    { 
     synchronized(this) 
     { 
      datagramSocket = createSocket(); 
     } 
    } 

private DatagramSocket createSocket() { 
     try 
     { 
      return new DatagramSocket(DEFAULT_UDPLISTENPORT); 
     } 
     catch (SocketException e) 
     { 
      logger.error("Trouble opening UDP port: ", e); 
      return null; //I beg you, don't return null here... 
     } 
} 

:

당신이 정말로 이러한 잘못된 개체를 만들려면, 당신의 제안은 괜찮지 만 다른 방법을 사용

  • NoOpDatagramSocket

  • NullDatagramSocket

  • BrokenDatagramSocket

  • MemoryDatagramSocket

  • ... 당신이

P.S : 왜 synchronized :-) 생각을?

P.S.2 : 바로 logger.error() 앞에 덧글 // Log error이 많은 가치를 더하고 있지 않습니까?

+0

다른 스레드에서'datagramSocket'을 사용하고 인스턴스와 관련이 없기 때문에'RunTimeExceptions'를 받았기 때문에'synchronized'가 사용되었습니다 'SocketException' 던짐 – mre

+0

해결책을 제공했습니다. 당신이 무슨 생각을하는지 제게 알려주세요! – mre

+1

먼저, 생성자는'private'이어야합니다. 그렇지 않으면 여러분의 객체는 더 이상 싱글 톤이 아닙니다. 또한 클래스 정적 초기화 블록에서 이상한'ExceptionInInitializerError' 처리를 피하기 위해 C 런타임의 일부 런타임 예외에서'SocketException'을 래핑하는 것이 좋습니다. –

5

가능한 대안은 생성자가 SocketException을 throw하는 것입니다. 이렇게하면 임시 변수를 사용해야하는 try-catch 블록의 필요성이 제거됩니다.

+2

좋은 점에 대해 확인되지 않은 예외가 발생했는지 확인하십시오. 클래스가 올바르게 작동하려면 데이터 그램 소켓이 필요하다면 소켓없이 데이터 그램 소켓을 만드는 것이 무엇입니까? (아마도 필드가 final이기 때문에 클래스는 나중에 다시 시도하지 않습니다.) –

관련 문제