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

发布于 2024-11-04 18:15:38 字数 2347 浏览 1 评论 0原文

因此,我试图在构造函数中初始化 DatagramSocket ,并且我希望该字段为 final,但我的编译器(即 Eclipse)给出了以下错误:

空白的最终字段datagramSocket 可能尚未初始化

这是可以理解的。这是一个代码片段:

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

请告诉我这是否正确,或者您是否有任何其他建议。我很感激你的帮助!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

空名 2024-11-11 18:15:39

是的,在捕获 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< /code>

  • MemoryDatagramSocket

  • ...你明白了:- )

PS:为什么要同步

PS2:logger.error()之前的注释// Log error并没有增加太多价值,你不觉得吗?

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?

柒七 2024-11-11 18:15:39

一种可能的替代方法是让构造函数抛出 SocketException。这将消除对强制您使用临时变量的 try-catch 块的需要。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文