So, I'm trying to initialize a DatagramSocket
in a constructor, and I want this field to be final
, but my compiler (i.e. Eclipse) is giving me the following error:
The blank final field datagramSocket may not have been initialized
This is understandable. Here's a 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 there's a way to bypass this, but it requires me to create a temporary variable. Here's a 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 of doing this, or is this something that I'll just have to live with if I want that field to be final
?
EDIT:
For those of you who are interested, here's the solution 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 any other suggestions. I appreciate the help!
Yes, we can write try catch and finally block in a constructor ant it works properly.
catch statement is comprised of a try block and either a catch block, a finally block, or both. The code in the try block is executed first, and if it throws an exception, the code in the catch block will be executed. The code in the finally block will always be executed before control flow exits the entire construct.
yes we can write a try catch block within a constructor same as we can write in inside a method.
When a field is defined as final , it has to be initialised when the object is constructed, i.e. you're allowed to assign value to it inside a constructor. A static field belongs to the class itself, i.e. one per class. A static final field is therefore not assignable in the constructor which is one per object.
Yes, after catching SocketException
wrap it in runtime exception and rethrow it. Since your variable is final
and you have encountered error during object initialization, your object is probably in incorrect state and you are guaranteed that it will remain as such.
Logging the exception isn't probably enough for exception handling and hiding SocketException
hides the fact that the object is invalid and allows you to continue, risking NullPointerException
or others.
If you really want to create such a faulty 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...
}
}
As for returning null
: consider subclassing DatagramSocket
and creating:
NoOpDatagramSocket
NullDatagramSocket
BrokenDatagramSocket
MemoryDatagramSocket
...you get the idea :-)
P.S.: Why the synchronized
?
P.S.2: The comment // Log error
right before logger.error()
isn't adding much value, don't you think?
A possible alternative is make your constructor throw SocketException. This will get rid of the need for the try-catch block that forces you to use the temporary variable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With