try with resources closing the resources unexpectedly - java

I am trying to invoke the following method inside a while loop. First time, it invokes fine but on 2nd loop execution, it throws an IOException
public String getInputString(String prompt){
System.out.print(prompt);
String inputLine = null;
try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))){
inputLine = br.readLine();
if(inputLine.length() == 0){
return null;
}
}
catch(IOException e){
e.printStackTrace();
}
return inputLine;
}
I am getting this IOException:
java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:162)
at java.io.BufferedInputStream.read(BufferedInputStream.java:325)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at ch5.GameHelper.getInputString(GameHelper.java:14)
at ch5.SimpleDotComTestDrive.main(SimpleDotComTestDrive.java:19)
On the other hand, it is working fine when i try to execute it as follows:
try{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
inputLine = br.readLine();
if(inputLine.length() == 0){
return null;
}
}
catch(IOException e){
e.printStackTrace();
}
What is the reason for such a behaviour?

I suspect you're calling getInputString more than once.
The first time, it should work fine - but then you're closing System.in (by closing the BufferedReader wrapping InputStreamReader wrapping System.in)... which means the next time you try to read from System.in, you won't be able to.
If you remove the try-with-resources statement, you could still have problems, because you'll be creating multiple readers around the same stream - if one of those reads more input than you actually use, it won't be available later on.
I suggest you create a BufferedReader wrapping an InputStreamReader wrapping System.in once, at the start of your program, and use that BufferedReader instance everywhere.

Related

How do I automate a command line script with Java ProcessBuilder

I'm relative newbie to java and am trying to automate command line using java. I tried to search for the solution here, but couldn't find it.
I created a simple test shell script like below for testing my program:
#!/bin/bash
echo "What is your name?";
read name;
echo "Hello, $name"
echo "What is your contact number?";
read num;
echo "Saved contact number $num for $name"
The Java code is below:
import java.io.*;
import java.util.*;
public class CmdLineMain {
public static void main(String args[]) throws InterruptedException, IOException {
List<String> command = new ArrayList<String>();
command.add("./test.sh");
ProcessBuilder builder = new ProcessBuilder(command);
final Process process = builder.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = "";
BufferedWriter bw = null;
while (process.isAlive()) {
line = br.readLine();
// since stream may be closed earlier, re-open it
bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
System.out.println(line);
if (line != null) {
switch (line) {
case "What is your name?":
bw.write("John Doe");
bw.close();
break;
case "What is your contact number?":
bw.write("123456789");
bw.close();
break;
}
}
}
System.out.println("Program terminated!");
}
}
Problem: The second input to the process fails with error:
What is your name?
Hello, John Doe
What is your contact number?
Exception in thread "main" java.io.IOException: Stream Closed
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:326)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at java.io.FilterOutputStream.close(FilterOutputStream.java:158)
at sun.nio.cs.StreamEncoder.implClose(StreamEncoder.java:320)
at sun.nio.cs.StreamEncoder.close(StreamEncoder.java:149)
at java.io.OutputStreamWriter.close(OutputStreamWriter.java:233)
at java.io.BufferedWriter.close(BufferedWriter.java:266)
at nkh.app.CmdLineMain.main(CmdLineMain.java:34)
Closing the BufferedWriter will close its underlying streams, this includes the process OutputStream which you get through process.getOutputStream(). Thus, once it is closed in one loop, in the next loops you have your BufferedWriter wrapping a closed stream. Instead wrap the output stream only once and reuse that.
Like this:
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
// while the stream is open and there is something to read
// probably a better condition than `process.isAlive()`
while ((line = br.readLine()) != null) {
switch (line) {
case "What is your name?":
bw.write("John Doe");
bw.newLine();
bw.flush();
break;
case "What is your contact number?":
bw.write("123456789");
bw.newLine();
bw.flush();
break;
}
}
The reason your original code died on close() rather than on the write() that came before it when your new BufferedWriter was wrapping the closed underlying stream was because BufferedOutputStream.write() may not actually write to the underlying stream yet, since it's buffered. Calling flush() should tell the stream to actually write, and as you see in the stack trace close() is calling flush() which is ultimately writing the buffered bytes to the underlying FileOutputStream, which is then realizing that the FileOutputStream is already closed.

what is the purpose of BufferedWriter writefile = null;

I have used Buffered writer a few times but there is a line of code I am not sure of its purpose. The code is below
BufferedWriter writefile = null;
I wonder if anyone could tell me what this line of code does and if it is needed.
Initialization of BufferedReader can involve calling constructors which can throw exceptions like new BufferedReader(new FileReader(fileLocation)) because calling FileReader constructor may throw FileNotFoundException if location in fileLocation doesn't point to existing and accessible file.
To handle this exception we move initialization in try section. Theoretically we could write
try{
BufferedReader br = new BufferedReader(new FileReader(fileLocation));
//...
}catch(FileNotFoundException e){
//handle exception
}
but then in finally section we want to handle closing that reader and prevent resource leaking. So we need to add
finally{
br.close();
}
Problem 1 - scope
We can't access br from finally section because it was declared in try section so its scope is limited to it.
Solution would be declaring it outside of try but initializing in try. So lets do
BufferedReader br;
try{
br = new BufferedReader(new FileReader(fileLocation));
//...
}catch(FileNotFoundException e){
//handle exception
}finally{
br.close();
}
Problem 2 - usage of possibly uninitialized variable
We can't call br.close() because if exception will be thrown br will not be initialized (not even with null), so compiler can't compile such code.
Solution is to explicitly assign null to br before try section. This will allow us to know in finally section if br was properly initialized and need to be closed or not (if it still holds null). So we used to write code like
BufferedReader br = null;
try{
br = new BufferedReader(new FileReader(fileLocation));
//...
}catch(FileNotFoundException e){
//handle exception
}finally{
if (br != null){
br.close();
}
}
Above was used pre Java 7, before try-with-resources was introduced. Now to have same functionality as above all we need is
try (BufferedReader br = new BufferedReader(new FileReader(fileLocation))) {
//...
}catch(FileNotFoundException e){
//handle exception
}

close() closes input streams permanently

I am trying to make a simple method readIn() that reads something in from System.in. (Can't use Console because System.console() returns null when I run in Eclipse). The idea is to call readIn as needed, like this
classs Foo{
public static void(String[] arg){
String first = readIn("First, please");
System.out.println(first);
String second = readIn("Second, please");
System.out.println(second);
}
}
Here is the simplest form of readIn():
static String readIn(String prompt){
System.out.println(prompt + ": ");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = br.readLine();
br.close(); // PROBLEM STATEMENT
return line;
}
If I omit the br.close() statement it works fine - I can call readIn repeatedly. But if I close br, as I should, then only the first call works. Second call throws IOException: Stream closed. As expected, the same thing happens with try-with-resources in readIn:
static String readIn(String prompt){
System.out.println(prompt + ": ");
String line;
try(
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)) )
{
line = br.readLine();
}
return line;
}
Same thing happens with Scanner(System.in) instead of BufferedReader. It does not happen when reading from files.
Which stream is closed if a new BufferedReader or Scanner is made in every call to readIn? Is this something about close() closing the "underlying Readable/Closeable" (System.in)? Can it be reopened? Trying to understand, thanks.
br.close(); closes also system input stream System.in, so you can't use it unless you restart JVM.
You can use the same BufferedReader instance for all required input from System.in
Don't be shy also to mix calls:
System.out.println
br.readLine();
They are related to different streams, so there shouldn't be any issues.

When we close a resource,is the object instantiated with it destructed?

My doubt mainly arises while reading sockets, within the following code:
String hostName = args[0];
int portNumber = Integer.parseInt(args[1]);
try (
Socket echoSocket = new Socket(hostName, portNumber);
PrintWriter out =
new PrintWriter(echoSocket.getOutputStream(), true);
BufferedReader in =
new BufferedReader(
new InputStreamReader(echoSocket.getInputStream()));
BufferedReader stdIn =
new BufferedReader(
new InputStreamReader(System.in))
) {
String userInput;
while ((userInput = stdIn.readLine()) != null) {
out.println(userInput);
System.out.println("echo: " + in.readLine());
}
Link:http://docs.oracle.com/javase/tutorial/networking/sockets/examples/EchoClient.java
In the above code, as I understand, PrintWriter and BufferedReader are the resources, however I also read in the trywithreasources block, as soon as it ends, all resources within it are closed. But if closing of the resource implies destruction of the object, that would mean stdIn and in are destroyed and it is a separate instance outside the block. Is it so?
The try-with-resource statement will only close resources declared in the parentheses between the inside the try.
try ( /*anything declared here will be closed*/) {
}
The when the try ends, the try with resource will call close() on any resource declared. This doesn't necessarily "destroy" an object like a destructor in C, but it is often used that way. The variable will also fall out of scope outside the try so it can be garbage collected.
IN your example stdIn wraps System.in so System.in WILL BE CLOSED. However since it is still in scope after the try, it will not be garbage collected. (but you can't write to it anymore)
Try-with-resource is just "syntatic sugar" and will be compiled into something like this:
Socket echoSocket =null
PrintWriter out =null
BufferedReader in =null
BufferedReader stdIn =null
try{
echoSocket = new Socket(hostName, portNumber);
out =
new PrintWriter(echoSocket.getOutputStream(), true);
in =
new BufferedReader(
new InputStreamReader(echoSocket.getInputStream()));
stdIn =
new BufferedReader(
new InputStreamReader(System.in));
String userInput;
while ((userInput = stdIn.readLine()) != null) {
out.println(userInput);
System.out.println("echo: " + in.readLine());
}
}finally{
if(stdIn !=null){
try{
stdIn.close()
}catch(Exception e){
//surpress exception if needed
}
}
if(in !=null){
try{
in.close()
}catch(Exception e){
//surpress exception
}
}
if(out !=null){
try{
out.close()
}catch(Exception e){
//surpress exception
}
}
if(echoSocket !=null){
try{
echoSocket.close()
}catch(Exception e){
//surpress exception
}
}
}
Notice that the resources are closed in reverse order to solve the nesting issue. If something threw an exception in the try block AND something else threw an exception in the finally block, then the "surpress exception" gets added to the original Exception object which can be retrieve via the new Throwable.getSuppressed() method. This is so the stacktrace correctly shows the original exception that was thrown inside the try.
for more information about try-with-resource see Oracle's tutorial: http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
Looking at your try-with-resources, let's take only the part wrapping System.in.
try (
...
BufferedReader stdIn =
new BufferedReader(
new InputStreamReader(System.in))
)
stdIn is an object that wraps an InputStreamReader object that wraps an InputStream object. That InputStream object is (unless you've changed it) the Java process' standard input.
When you exit the try block, it will call stdIn.close(), which will cascade and call close() on the InputStreamReader which will cascade and call close() on the object referenced by System.in.
There is no destruction in Java. If the objects referenced by the variables above become unreachable from within your program, they will be garbage collected.
if closing of the resource implies destruction of the object
It doesn't. There is no such thing as 'destruction' in Java.
that would mean stdIn and in are destroyed
No it doesn't.
and it is a separate instance outside the block. Is it so?
No.

closing an buffer reader is compulsory

I am trying an example from
http://www.roseindia.net/java/beginners/java-read-file-line-by-line.shtml
in the example the BufferReader is not closed is that necessary to close the BufferReaderor not? Please explain.
FileInputStream fstream = new FileInputStream("textfile.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
// Print the content on the console
System.out.println (strLine);
}
//Close the input stream
in.close();
Always close streams. It's a good habit which helps you to avoid some odd behaviour. Calling close() method also calls flush() so you don't have do this manually.
The best place where to close streams is probably in a finally block. If you have it like in your example and an exception occurs before the in.close() line, the stream won't be closed.
And if you have chained streams, you can only close the last one and all before it are closed too. This means br.close() in your example - not in.close();
Example
try {
// do something with streams
} catch (IOException e) {
// process exception - log, wrap into your runtime, whatever you want to...
} finally {
try {
stream.close();
} catch (IOException e) {
// error - log it at least
}
}
Alternatively you can use closeQuietly(java.io.InputStream) in Apache Commons library.
From the perspective of resource leak prevention, it is not strictly necessary to close a wrapper stream if you've also closed the stream that it wraps. However, closing the wrapped stream may result in stuff getting lost (specifically in the output case), so it is better to close (just) the wrapper, and rely on documented behavior that the closing the wrapper closes the wrapped stream too. (That is certainly true for the standard I/O wrapper classes!)
Like Peter Lawrey, I question the wisdom of relying on "Rose India" examples. For instance, this one has two more obvious mistakes in it that no half-decent Java programmer should make:
The stream is not closed in a finally block. If any exception is thrown between opening and closing, the in.close() statement won't be executed, and the application will leak an open file descriptor. Do that too often and your application will start throwing unexpected IOExceptions.
The DataInputStream in the chain serves no useful purpose. Instead, they should use fstream as the parameter for the InputStreamReader. Or better still, use FileReader.
Finally, here is a corrected version of the example:
BufferedReader br = new BufferedReader(new FileReader ("textfile.txt"));
try {
String line;
while ((line = br.readLine()) != null) {
// Print the content on the console
System.out.println(line);
}
} finally {
// Close the reader stack.
br.close();
}
or using Java 7's "try with resource":
try (BufferedReader br = new BufferedReader(new FileReader ("textfile.txt"))) {
String line;
while ((line = br.readLine()) != null) {
// Print the content on the console
System.out.println(line);
}
}
Since the underlying stream is closed, it is not absolutely necessary to close BufferedReader, even though it is a good practice to close ALL Closeables in reverse order (relative to the order they were opened in.)

Categories

Resources