java - 在构造函数中的 try-catch block 中分配最终字段

标签 java try-catch final

所以,我试图在构造函数中初始化一个 DatagramSocket,我希望这个字段是 final,但是我的编译器(即 Eclipse)给了我以下错误:

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

请让我知道这是否正确,或者您是否有任何其他建议。感谢您的帮助!

最佳答案

是的,在捕捉到 SocketException 后将其包装在运行时异常中并重新抛出。由于您的变量是 final 并且您在对象初始化期间遇到错误,您的对象可能处于不正确的状态并且您保证它将保持原样。

记录异常可能不足以进行异常处理,隐藏 SocketException 会隐藏对象无效的事实并允许您继续,冒着 NullPointerException 或其他风险。

如果你真的想创建这样一个错误的对象,你的建议很好,只需使用另一种方法:

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

至于返回 null:考虑继承 DatagramSocket 并创建:

  • NoOpDatagramSocket

  • NullDatagramSocket

  • BrokenDatagramSocket

  • MemoryDatagramSocket

  • ...你明白了:-)

附言:为什么要同步

P.S.2:logger.error() 之前的注释 //Log error 没有增加太多值(value),你不觉得吗?

关于java - 在构造函数中的 try-catch block 中分配最终字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5858250/

相关文章:

java - 为什么我们不能在每种情况下都只使用可比较的?

java - 打印时如果数组中的int元素等于6则跳过

python - 类方法包装函数-参数问题

java - 如何防止扫描仪接受字符串、负整数或小于 2 的数字?

java - 方法声明中参数声明之前的 final 关键字

java - 打开新消息框或其他对话框时如何使背景屏幕变暗

java - 在 XML 中定义资源是否会导致解析开销?

c# - 抛出带有代码和消息的新异常

java - final 方法在 Java 中的确切工作方式

java - java中最终变量分配的内存在哪里?