简体   繁体   中英

Assigning a final field in a try-catch block within a constructor

So, I'm trying to initialize a DatagramSocket in a constructor, and I want this field to be final , but my compiler (ie 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, 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:-)

PS: Why the synchronized ?

PS2: 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM