6

I have simple TCP server which prints the message sent by client. I'm trying to modify it to use try-with-resource feature. Is using nested try-with-resource statement in my example correct?

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

}

Daniil Molchanov
  • 113
  • 1
  • 1
  • 9
  • 2
    What makes you think it's not? – MadProgrammer Jan 17 '15 at 07:33
  • Googling made me think of it. Some users suggested to place two statements separated by semicolon in try clause. In my case it's not working. I'm just wondering if it is a good practice to use nested try-with-resource clauses, or some other effective solution exist. – Daniil Molchanov Jan 17 '15 at 08:06
  • 3
    you can't put both in one try block, because `socket.getInputStream()` in your second try block depends on `Socket socket = serverSocket.accept();` which happens inside the first try block – Ubica Jan 17 '15 at 08:11
  • I updated my answer with an example of where your code could appropriately use multiple resources in try clause. – gknicker Jan 17 '15 at 22:50
  • 1
    See [this question](http://stackoverflow.com/questions/12552863/correct-idiom-for-managing-multiple-chained-resources-in-try-with-resources-bloc) for some advice with respect to your chained resources in `try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())))` – rxg Jan 21 '15 at 20:31

1 Answers1

3

Yes, your example is correct.

A try-with-resources try block can stand alone because it has an implicit finally block; whereas a traditional try block is required to be followed by a catch block and/or a finally block.

Thus your example code is equivalent to the following (besides the resource variables being visible outside the scope of their respective try blocks):

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

I would have recommended you put both resources inside the same try block, except in your case that doesn't work because it's necessary to call accept() on the serverSocket before asking for its inputStream().

However, there's still an appropriate opportunity in your code example to put multiple resources in your second 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'
}
gknicker
  • 5,509
  • 2
  • 25
  • 41
  • `serverSocket = new ServerSocket(777);` should go inside the try clause, io exceptions can also happen when opening them, same goes for the reader code. – Thomas Jungblut Jan 17 '15 at 22:51
  • @ThomasJungblut a lot of developers seem to have that misconception, which is unfortunate and results in a lot of unclean code: did the resource variable get initialized or not? They way I wrote it, there is no question. And since exceptions are not being caught in the example code, the enclosing method throws IOException regardless. – gknicker Jul 11 '21 at 17:22
  • I don't want to start a flame war on a 6yo answer, but your code is problematic when people copy&paste it without thinking and catching the errors appropriately due to leaking sockets. And it is not exactly the same as the OP's actually correct code which guarantees that the socket created is properly closed. When your `ServerSocket` constructor throws an exception it's left dangling. – Thomas Jungblut Jul 12 '21 at 06:57
  • @ThomasJungblut sorry but you're just wrong... if the constructor throws an exception, the serverSocket variable is never assigned, hence there is nothing to clean up – gknicker Jul 13 '21 at 19:14