Destination field assignment in try-catch block inside constructor

So, I'm trying to initialize a DatagramSocket in the constructor, and I want this field to be final , but my compiler (i.e. Eclipse) gives me the following error:

An empty field datagram field may not have been initialized

It's clear. Here's the code snippet:

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

Now I know that there is a way around this, but this requires creating a temporary variable. Here's the code snippet:

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

So, I suppose, my question is: is there a more elegant way to do this, or is it something I just need to live with if I want this field to be final ?

EDIT:

For those of you who are interested, here is a solution that I came up with from your recommendations:

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

Please let me know if this is correct, or if you have other suggestions. I appreciate the help!

+7
source share
2 answers

Yes, after catching a SocketException wrap it in a runtime exception and rebuild it. Since your variable is final and you encountered an error while initializing the object, your object is probably in the wrong state and you are guaranteed to remain as such.

Writing exceptions is probably not enough to handle exceptions and hide SocketException hides the fact that the object is invalid and allows you to continue, risking a NullPointerException or others.

If you really want to create such a defective object, your suggestion is fine, just use another method:

 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... } } 

Regarding null return: consider subclassing DatagramSocket and create:

  • NoOpDatagramSocket

  • NullDatagramSocket

  • BrokenDatagramSocket

  • MemoryDatagramSocket

  • ... you get the idea :-)

PS: Why synchronized ?

PS2: comment // Log error before logger.error() doesn’t add much value, does it?

+11
source

A possible alternative is for your constructor to throw a SocketException. This will save you from having to try-catch locking, which will force you to use a temporary variable.

+5
source

All Articles