【问题标题】:Is my usage of nested try-with-resource correct?我对嵌套 try-with-resource 的使用是否正确?
【发布时间】:2015-03-15 20:12:32
【问题描述】:

我有一个简单的 TCP 服务器,它打印客户端发送的消息。我正在尝试修改它以使用 try-with-resource 功能。在我的示例中使用嵌套的 try-with-resource 语句是否正确?

public static void main(String args[]) throws IOException {
    String receivedMessage;

    try (ServerSocket serverSocket = new ServerSocket(777)) {
        while (true) {
            Socket socket = serverSocket.accept();
            System.out.println("Client connected");
            try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                while ((receivedMessage = in.readLine()) != null) {
                    System.out.println(receivedMessage);
                }
                System.out.println("Client disconnected");
            }
        }
    }
}

}

【问题讨论】:

  • 是什么让你觉得不是?
  • 谷歌搜索让我想到了这一点。一些用户建议在 try 子句中放置两个用分号分隔的语句。就我而言,它不起作用。我只是想知道使用嵌套的 try-with-resource 子句是否是一种好习惯,或者是否存在其他一些有效的解决方案。
  • 您不能将两者都放在一个 try 块中,因为您的第二个 try 块中的 socket.getInputStream() 取决于发生在第一个 try 块中的 Socket socket = serverSocket.accept();
  • 我用一个示例更新了我的答案,说明您的代码可以在 try 子句中适当地使用多个资源。
  • 关于try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())))中的链式资源的一些建议请参见this question

标签: java


【解决方案1】:

是的,你的例子是正确的。

try-with-resources try 块可以独立存在,因为它有一个隐含的 finally 块;而传统的try 块后面需要catch 块和/或finally 块。

因此,您的示例代码等效于以下代码(除了资源变量在其各自的 try 块范围之外可见):

        final ServerSocket serverSocket = new ServerSocket(777);
        try {
            while (true) {
                Socket socket = serverSocket.accept();
                System.out.println("Client connected");
                final BufferedReader in = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));
                try {
                    while ((receivedMessage = in.readLine()) != null) {
                        System.out.println(receivedMessage);
                    }
                    System.out.println("Client disconnected");
                } finally {
                    in.close();
                }
            }
        } finally {
            serverSocket.close();
        }

我会建议您将这两个资源放在同一个 try 块中,除非您的情况不起作用,因为在请求其 inputStream() 之前,必须在 serverSocket 上调用 accept()

但是,您的代码示例中仍有适当的机会在您的第二个 try-with-resources 中放置多个资源:

try (Reader stream = new InputStreamReader(socket.getInputStream());
     BufferedReader in = new BufferedReader(stream)) {
  // do stuff, still preferring to use 'in' here rather than 'stream'
}

【讨论】:

  • serverSocket = new ServerSocket(777); 应该放在 try 子句中,打开它们时也会发生 io 异常,阅读器代码也是如此。
  • @ThomasJungblut 很多开发人员似乎都有这样的误解,这是不幸的并导致很多不干净的代码:资源变量是否被初始化?他们按照我写的方式,毫无疑问。由于示例代码中没有捕获异常,因此封闭方法无论如何都会抛出 IOException。
  • 我不想对一个 6 岁的答案发起一场激烈的战争,但是当人们复制和粘贴它而不考虑并由于套接字泄漏而适当地捕获错误时,你的代码就会出现问题。而且它与 OP 的实际正确代码并不完全相同,它保证创建的套接字被正确关闭。当您的 ServerSocket 构造函数抛出异常时,它会悬空。
  • @ThomasJungblut 很抱歉,但你错了……如果构造函数抛出异常,则永远不会分配 serverSocket 变量,因此无需清理
猜你喜欢
  • 2023-03-26
  • 2013-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-12
  • 1970-01-01
相关资源
最近更新 更多