views:

498

answers:

9

I have the following example of reading from a buffered reader:

while ((inputLine = input.readLine()) != null) {
   System.out.println("I got a message from a client: " + inputLine);
}

The code in the loop println will be executed whenever something appears in the buffered reader (input in this case). In my case, if a client-application writes something to the socket, the code in the loop (in the server-application) will be executed.

But I do not understand how it works. inputLine = input.readLine() waits until something appears in the buffered reader and when something appears there it returns true and the code in the loop is executed. But when null can be returned.

There is another question. The above code was taken from a method which throws Exception and I use this code in the run method of the Thread. And when I try to put throws Exception before the run the compiler complains: overridden method does not throw exception. Without the throws exception I have another complain from the compiler: unreported exception. So, what can I do?

A: 

input reader is connected to the socket, which is a listener, i.e. keeps listening to incoming messages.

About your second question, you should put a try/catch block inside the method, catch the Exception and handle it. Do not re-throw it.

medopal
A: 

When the socket on the other end is closed, the reader should return a null string. This is the condition that you are looking for. To handle the exception, wrap the reading loop in a try/catch block.

 try {
   while ((inputLine = input.readLine()) != null) {
     System.out.println("I got a message from a client: " + inputLine);
   }
 }
 catch (IOException e) {
   System.err.println("Error: " + e);
 }

You might find this tutorial on reading/writing from/to a socket in Java, helpful.

tvanfosson
+1  A: 

The reader's readLine() will return a string value when it has something read, an empty string when there isn't anything yet, and null when the connection is closed.

I would recommend wrapping a try/catch around your block of code with the IO function and handle errors appropriately.

Bryan Denny
A: 

But I do not understand how it works. .... waits until something appears in the buffered reader and when something appears there it returns true

No, it returns the value of the expression (inputLine = input.readLine()), the inputLine itself. The inputLine is compared to null.

PeterMmm
A: 

null is returned when the "EOF (End Of File)" is reached. Since this is reading from a network socket, the end of file is created when the socket is disconnected (either by the server or the client), but you will likely get an Exception before you actually see the EOF.

M. Jessup
A: 

If this isn't for homework, you might want to look at Apache Commons IOUtils.

Assuming you don't create the BufferedReader, and just stop at the InputStream:

String results = IOUtils.toString(inputStream);
System.out.println(results);
Dean J
A: 
while ((inputLine = input.readLine()) != null) {

Look at each part of the expression:

input.readLine()

Returns a String which will be null if the end of the stream has been reached (or throws an Exception on error).

inputLine = input.readLine()

Assigns this String to inputLine

((inputLine = input.readLine()) != null)

Checks that the String that was assigned is not null (end of stream).

fgb
+1  A: 

For your first question:

But I do not understand how it works. inputLine = input.readLine() waits until something appears in the buffered reader and when something appears there it returns true and the code in the loop is executed. But when null can be returned.

BufferedReader.readLine() does not return true upon success. It returns a String containing the line that was read. If the end of the stream is reached, it returns null.

Your second question:

The above code was taken from a method which throws Exception and I use this code in the run method of the Thread. And when I try to put throws Exception before the run the compiler complains: overridden method does not throw exception. Without the throws exception I have another complain from the compiler: unreported exception. So, what can I do?

You should wrap your code in a try/catch block. If you don't want to handle the caught exception, simply leave that part blank (not recommended)

try {
    while ((inputLine = input.readLine()) != null) {
        System.out.println("I got a message from a client: " + inputLine);
    }
} catch (Exception e) {
    //handle exception
}
Peter Di Cecco
A: 

You have received some good answers. Just catch the exception and deal with it locally. If you need to pass this on to other code but cannot since the run() method does not allow for any check exception, you can wrap the exception in a RuntimeException of some kind. If the run method is executing directly on a Thread (since it is a Runnable probably) then you should take care with re-throwing a wrapped exception.

As for the result from readLine(), it will return null when there is nothing more to read. In the case of a socket this is when the other side cleanly closes the socket (any sudden termination or unclean close would typically result in an exception in your code as the OS will send a different kind of socket close notification).

I do have one word of caution since you are wrapping a socket in a java.io.BufferedReader. You should be very careful about using this in any kind of production code.

The danger is that BufferedReader does not deal well with exceptions in the midst of reading. This is especially an issue if you have enabled a timeout on the socket so the code will receive periodic exceptions automatically from the operating system. The timeout (or other exception) could come while the buffer inside the reader is filling. If you attempt to reuse the object after the exception, it will ignore any previous contents in the buffer. The packet(s) that were previously received are silently lost and there is no way to retrieve those bytes.

Note that there are other kinds of socket exceptions that do not mean that the socket has been lost. For instance, look at the definition of java.io.InterruptedIOException. This has a public variable that reports the number of bytes successfully transferred in the most recent I/O (read or write) request. This means that the IO operation can be executed again to retrieve or send the remaining bytes for the packet.

If upon any exception your design is to immediately close the reader and socket the method will work correctly.

The proper way to read from a socket is to use the socket stream directly, use NIO (ByteBuffers and such), or use a well written network library with good abstractions over these lower level classes (several open source ones are available).

Kevin Brock