1

I am coming back to writing code in Java after a long gap - most of my coding work over the past few years has been in PHP & JavaScript - and am discovering that I have to work harder to satisfy the Java compiler which is far more rigorous about issues such as variable scope and exception handling. A piece of code that caused me some trouble is shown below

File file = new File(path, fname);
FileOutputStream stream = null;
try 
{
 stream = new FileOutputStream(file);
 stream.write(tosave.getBytes());
}
finally 
{
 try
 {
  if (null != stream) {stream.close();}
  return true;
 }
 catch(Exception e){return false;}        
}

This is accepted by the compiler. However, before I got here I had run into several issues.

  • First attempt: No Catch Block. The compiler refused to play ball because it wanted me to deal with the eventuality that the FileOutputStream could not be created. Ditto for writing to that stream. I understand the logic behind this reasoning and like it.
  • Second attempt: Catch Block but...:I was declaring and creating the stream variable INSIDE the try block. The compiler threw a wobbly again - the stream variable was out-of-scope in the finally block.

As you will see I have gotten around the issue by declaring stream above the try block and initializing it to null.

This works. However, given just how rusty my Java skills are I thought I would ask: Is there a right way to write such code?

Mureinik
  • 297,002
  • 52
  • 306
  • 350
DroidOS
  • 8,530
  • 16
  • 99
  • 171

4 Answers4

3

The idiomatic way to handle such scenarios in modern Java versions (since Java 7) would be to use a try-with-resource block that handles all the ugly closing "logic" for you. You'd still have to either catch the exception or propagate it upwards, but that's a relatively small issue. Consider the following:

public static boolean writeToFile(String path, String fname) {
    File file = new File(path, fname);
    try (FileOutputStream stream = new FileOutputStream(file)) {
        stream.write(tosave.getBytes());
    } catch (IOException e) {
        // Should probably log the exception too
        return false;
    }
    return true;
}
Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • Thank you for the various answers - I can only accept one :-). I was unaware of the try-with-resource block. I think the last time i did Java it was still in version 6-- – DroidOS Apr 29 '16 at 09:19
1

You could simply use below code snippet:

try (FileOutputStream stream = new FileOutputStream(file)){
    stream.write(tosave.getBytes());
}catch(IOException e) {
    e.printStackTrace();
    return false;
}

return true;

It's a new feature (try-with-resources Statement) introduced in Java 7.

justAbit
  • 4,226
  • 2
  • 19
  • 34
1

I think you're getting hung up on stuff that isn't important. Yes, in some situations coding try/catch/finally IS important because you actually need to do something to fix an error.

But for opening/closing a file, you don't want to get yourself into knots just to satisfy the compiler. Code Readability is much more important.

How about:

String path="somepath";
String fname="somefile";
String tosave="somedata";
try {
    File file = new File(path, fname);
    FileOutputStream stream = new FileOutputStream(file);
    stream.write(tosave.getBytes());
    stream.close();
}
catch (Exception e) {
    e.printStackTrace();
    return false;
}
return true;
Christian Cerri
  • 1,233
  • 2
  • 15
  • 19
  • I am upvoting your answer because of your comment - _Code Readability is much more important_ - a very valid point. I should mention though that the context here is a Phonegap plugin for Android that writes to internal storage. I suspect that there is a tangible chance there that the device refuses to let the file be created/written to. – DroidOS Apr 29 '16 at 09:18
0

The "right" way is to use Java 7's try with resources. It has been a long time coming, but it cleans up this sort of boilerplate code really well.

Tough luck if you are stuck on an earlier Java version :)

kiwiron
  • 1,677
  • 11
  • 17