File I/O without clutering of exceptions - java

What is the best way to use e.g. FileOutputStream without cluttering my code.
Example the following code:
What I need to do is:
FileOutputStream fOut = new FileOutputStream(file);
while(!Thread.currentThread().isInterrupted()){
fOut.write(data);
//other code
}
But if I add the exception handling is all messy. I thought for example something like the following:
private FileOutputStream openStream(String file){
try{
return new FileOutputStream(file);
}
catch(FileNotFoundException e){
return null;
}
}
But then it makes the logic weird. I mean when I close the stream, e.g. in another method etc.
What is the way to get clearer code

What about a wrapper like this:
public class StreamWrapper {
private FileOutputStream fileOutputStream;
public FileOutputStream open(String file) {
try {
fileOutputStream = new FileOutputStream(file);
} catch (FileNotFoundException e) {
// Define action
}
return fileOutputStream;
}
public void close() {
try {
fileOutputStream.close();
} catch (IOException e) {
// Define action
}
}
}
And use it like:
StreamWrapper wrapper = new StreamWrapper();
FileOutputStream fOut = wrapper.open("file");
// something
wrapper.close();

There is no direct way of avoiding checked exceptions in Java, unfortunately. Few work-arounds:
Use different language
Both groovy and scala treat checked exceptions as unchecked.
try-with-resources idiom in Java 7
It doesn't really help with catch, but substantially reduces the amount of finally blocks surrounding close().
Throwables.propagate(Throwable) in Guava
Avoid returning null and swallowing exceptions:
private FileOutputStream openStream(String file){
try{
return new FileOutputStream(file);
}
catch(FileNotFoundException e){
return Throwables.propagate(e);
}
}
See also: Long try statements.

Applicative exceptions are there for a reason (and nobody likes RT exceptions...)
You could use a factory to hide the exception handling, but the "catch" clause would have to be in your code somewhere.
One idea is to implement your own wrapper to FileOutputStream that will swallow the exception during instantiation, but since the exception is thrown at the constructor you'll end up in an unstable state if the file indeed doesn't exists.
public class MyFileOutputStream {
private FileOutputStream fis;
public MyFileOutputStream(File file){
try{
fis = new FileOutputStream(file);
} catch (FileNotFoundException e){
fis = null;
}
}
public boolean isOpened(){
return fis!=null;
}
public void write(Byte b) throws IOException {
fis.write(b);
}
}

There are couple options that you can do:
First of all you sample code is good only thing is "in case of a exception you are returning a null object". So rather than returning a FileOutputStream object you can actually send a boolean and store the FileOutputStream object as a class variable.
So if other program want to access that can make this call and the caller will get True/False depending on whether it could create a object successfully or not, and if that is True then can use the class variable for the FileOutputStream object. I am attaching some sample code with that:
FileOutputStream fOutSt;
private boolean isOpenStream(String file){
try{
fOutSt = new FileOutputStream(file);
return true;
}
catch(FileNotFoundException e){
return false;
}
}
Then the caller can make call like:
if(isOpenStream) {
obj.GetfOutSt;
}

Related

Problem with: "Variable used as a try-with-resources resource should be final or effectively final"

From my point of view, I use try with resources so I don't have to close resources manually in try block. So in case of making a FileWriter, I wouldn't have to try, then catch and close it in finally, but just do this:
void m1(){
try(FileWriter fileWriter = new FileWriter ("test.txt")) {
//some operations
}catch (IOException ioException){
//some code
}
}
But what if I have a class that takes a reference of already instantiated FileWriter? Then I get a problem. I think I have a big "hole" in this use-case. Can someone point what am I missing? I tried doing this:
public class Test {
private FileWriter fileWriter;
public Test (FileWriter fileWriter) {
this.fileWriter = fileWriter;
}
public void m1 () {
try(fileWriter) { //compile error
//Says:Variable used as a try-with-resources resource should be final or effectively final
}catch (IOException ioe){
//some code
}
}
}
My only goal was ("as I am lazy") to automatically close the resource using its reference. Unfortunately, it didn't quite work. How to better understand why I get quoted warning?
You can use try with resources for any resources created outside the try block if you declare a new variable for the scope of the try block. Change m1 to:
public void m1 () {
try(var autoclosedhere = fileWriter) {
// or try(FileWriter autoclosedhere = fileWriter) {
// now fileWriter will close at the end
}catch (IOException ioe){
//some code
}
}
This works in Java 9 onwards. A local variable in try clause is required so that there is no ambiguity in case fileWriter was changed inside the block - see JDK-7196163.

Using custom exception in Java

I am trying to throw my custom exception in java but currently I have had no luck. I have two classes a readWrite class which allows the user to enter the file name and a text to be wrote to the file (via the constructor). It has three methods, write, read and a writeToFile which validates if the file ends in .txt if it does now it should throw my custom exception class stating that "Sorry but this system only accepts .txt files" which I have created in a toString() method in my custom exception. I can not seem to make it work, below is the code, some might be able to help, I hope I have explained properly as I am new to Java, note I have commented out some code as I was trying a few different things to make it work
ReadWrite.java
import java.io.*;
public class ReadWrite
{
private final String file;
private final String text;
public ReadWrite(String file, String text)
{
// initialise instance variables
this.file=file;
this.text=text;
}
private void write() //throws InvalidFileException
{
try {
FileWriter writer = new FileWriter(file);
writer.write(text);
writer.write('\n');
writer.close();
}
catch(IOException e)
{
System.out.print(e);
}
}
public boolean writeToFile()
{
boolean ok;
try{
FileWriter writer = new FileWriter(file);
{
if(file.toLowerCase().endsWith(".txt"))
{
write();
ok = true;
} //if end
else{
ok=false;
//throw new InvalidFileException();
} //else end
}
} //try end
catch(IOException e) {
ok=false;
} // catch end
//catch (InvalidFileException e){
//System.out.println(e.toString());
//}
return ok;
}
public void read(String fileToRead)
{
try {
BufferedReader reader = new BufferedReader(new FileReader(fileToRead));
String line = reader.readLine();
while(line != null) {
System.out.println(line);
line = reader.readLine();
}// while end
reader.close();
}//try end
catch(FileNotFoundException e) {
System.out.println(fileToRead + " the system can not find the file specified");
} //catch end
catch(IOException e) {
e.printStackTrace();
} //catch end
}
}
InvalidFileException.java
import java.io.FileNotFoundException;
import java.io.*;
public class InvalidFileException extends Exception
{
/**
* Constructor for objects of class InvalidFileException
*/
public InvalidFileException(String message)
{
super(message);
}
public String toString()
{
return ("Sorry but this system only accepts .txt files");
}
}
try this:
private void write() throws InvalidFileException {
try {
if(!file.getName().endsWith(".txt") {
throw new InvalidFileException(".txt files only.");
}
FileWriter writer = new FileWriter(file);
writer.write(text);
writer.write('\n');
writer.close();
}
catch(IOException e)
{
// handle exception please.
}
Please note, that you have to override the "getMessage()" Method of Exception in order to print your custom message. Or set it in the super() call.
Overriding the toString() method makes your super() call and therefore your custom (detail) message passed to the exception (in my example ".txt files only.") obsolete, because this string won't be printed anymore.
Below is your requirement:
it does not it should throw my custom exception class stating that
"Sorry but this system only accepts .txt files"
I think you got confused because of toString. You really don't need that toString method. You correctly implemented a InvalidFileException which accepts a String argument.
So, now all you need is throw new InvalidFileException("Sorry but this system only accepts .txt files"); or use whatever String message you want while throwing InvalidFileException.
Please note, if you are throwing an exception from a method and catching it in same method looks illogical unless you are doing because APM (application performance monitoring) tools logging purpose.
As other note, if you are throwing exception like this then you need to add a throw statement in your method signature indicating that this method "may" throw so-and-so exception. So, that called of that method can either re-throw or catch it.
If you are catching the exception somewhere then use getMessage method on the exception object and you will get same message as you placed while throwing the exception, in this case - "Sorry but this system only accepts .txt files"
InvalidFileException extends Exception but you only ever try to catch IOException and FileNotFoundException. I think you meant to have InvalidFileException extend IOException.

Why is the catch statement being ignored here?

This is practice code from a book and i'm learning about try/catch statements.
The first method shown calls for the load method an retrieves two images. The error in this code is that the name of the first img in the resources file is called "welcome.png" but as you can see, it says "welcomee.png"(extra e at the end of welcome). When I run the code, it doesn't print out the code in the catch statement. It does show the stacktrace(because it does that regardless), but it doesn't print out " Error while reading: filename". Why is this?
public class Resources {
public static BufferedImage welcome, iconimage;
public static void load() {
welcome = loadImage("welcomee.png");
iconimage = loadImage("iconimage.png");
}
private static AudioClip loadSound(String filename) {
URL fileURL = Resources.class.getResource("/resources/" + filename);
return Applet.newAudioClip(fileURL);
}
private static BufferedImage loadImage(String filename) {
BufferedImage img = null;
try {
img = ImageIO.read(Resources.class.getResourceAsStream("/resources/" + filename));
} catch (IOException e) {
System.out.println("Error while reading: " + filename);
e.printStackTrace();
}
return img;
}
}
You're catching an IOException, but Class.getResourceAsStream doesn't throw an IOException if the resource is not found; it just returns null. And ImageIO.read doesn't throw an IOException if the argument is null; it throws an IllegalArgumentException.
I suggest you refactor the code this way:
private static BufferedImage loadImage(String filename) {
try (InputStream in = Resources.class.getResourceAsStream("/resources/" + filename)) {
if (in == null) throw new IOException("Resource not found");
return ImageIO.read(in);
} catch (IOException e) {
System.out.println("Error while reading: " + filename);
e.printStackTrace();
return null;
}
}
This will ensure you handle the error, and the use of the try-with-resources statement makes sure the stream is always closed after use (which ImageIO.read does not do). The direct return statement is perhaps a bit cleaner as it obviates the need for the img variable.
You should also consider, rather than returning null on error, to throw (or rethrow) some exception to the caller, such as an UncheckedIOException, since a null return value will only cause errors elsewhere once you try to make use of it, and an exception thrown directly from the point of the problem will be more meaningful than some NullPointerException thrown later.
You can only catch IOException. If you want to catch all type of exception, use catch(Exception e).
Try using catch(Exception e){...} instead. It is a way to check if it is just another exception or if it is not an exception, but a run-time error.
You can specify certain catch statements with certain exceptions later in the development process, if needed.

How can I unit test this inputStream has been closed?

I have a Runnable along the lines of:
public void run() {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
//more stuff here
}
catch (Exception e) {
//simplified for reading
}
finally {
if(inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {}
}
}
}
How do I test inputStream.close() was invoked? I am currently using Mockito and JUnit. I know injecting the inputStream in is an idea, but I don't want the resources to be used until run?() is called, hence it being a local variable. So how can I redesign my code in a way that allows me to test whether close was called?
If I understood the task correctly it could be like this
static boolean isClosed;
public void run() {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(file) {
#Override
public void close() throws IOException {
isClosed = true;
super.close();
}
};
// more stuff here
As there is no reason to expose the InputStream outside of the scope of this method you have a testing problem.
But I assume you don't directly care about the InputStream being closed. You want to test that because you've been told it's good practice (and it is). But I think what you actually care about is the negative impact of the stream being left open. What is the effect?
Try modifying this method so it does not close the stream, then execute it many times over. Do you get a memory leak, or run out of file handles or some other tomfoolery? If so, you have a reasonable test.
Alternatively, just go ahead and expose a decorated InputStream that can tell you if it has been closed or not. Make it package protected. That's the "impure", but pragmatic approach.
To check if the close() method is called, you can use Mockito.spy() to create a proxy object that can memorize calls. Spy delegates all the calls to the underlying InputStream, just memorizes what happened:
InputStream inputStreamSpy = Mockito.spy(inputStream);
// a code that is expected to close your stream goes here ...
Mockito.verify(inputStreamSpy).close();
This won't solve your problems with injecting instance of InputStream, actually. It seems like you need some kind of factory, that can open a stream for you, and you can mock that factory in unit tests. Let's call this factory a FileSystem:
public class FileSystem {
public FileInputStream newFileInputStream(File file) {
return new FileInputStream(file);
}
}
Now, you can inject an instance of the FileSystem, and it won't use resources before run method is executed:
public void run() {
InputStream inputStream = null;
try {
inputStream = fileSystem.newFileInputStream(file);
//more stuff here
}
catch (Exception e) {
//simplified for reading
}
finally {
if(inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {}
}
}
}
#Test
public void runShouldCloseInputStream() {
InputStream inputStream = ...
InputStream inputStreamSpy = Mockito.spy(inputStream);
FileSystem fileSystemMock = Mockito.mock(FileSystem.class);
when(mockFileSystem.newFileInputStream(Mockito.any(File.class)))
.thenReturn(inputStreamSpy);
MyRunnable instance = new MyRunnable(mockFileSystem);
instance.run();
verify(inputStreamSpy).close();
}
Spy can do more then just listening, you can teach it to alter behavior using Mockito.when(), just as you would do with a regular mock.
Kotlin implementation for testing a URL stream is closed
//close the connection
streamURL.close()
//stream should not be available if it is closed
try { streamURL.available() }
//java.net.URL provides simple "closed" message on IO URL
catch (ex: IOException) { Assert.assertEquals("closed", ex.message) }
You can write in the test something like:
try {
run();
} catch (IOException e) {
Assert.fail();
}
When your method will close strem and exception will occur, then test will fail.
You can do like this...
try
{
inputStream.readLine();
}
catch (IOException e)
{
Assert.assertEquals(e.getLocalizedMessage(), "Stream closed");
}

Can I avoid such cumbersome try...catch block

Usually, when dealing with Java IO code, here is what I wrote
FileOutputStream out = null;
try
{
out = new FileOutputStream("myfile.txt");
// More and more code goes here...
}
catch (Exception e)
{
}
finally
{
// I put the close code in finally block, to enture the opened
// file stream is always closed even there is exception happened.
if (out != null) {
// Another try catch block, troublesome.
try {
out.close();
} catch (IOException ex) {
}
}
}
As you can see, while I try to close the file stream, I need to deal with another try...catch block.
Look troublesome :(
Is there any way I can avoid? I don't feel comfortable in putting the close code in non-finally block, as exception caused by other codes will make no chance for "close" being called.
It is very important that you close streams in a finally. You can simplify this process with a utility method such as:
public static void closeStream(Closeable closeable) {
if(null != closeable) {
try {
closeable.close();
} catch(IOException ex) {
LOG.warning("Failed to properly close closeable.", ex);
}
}
}
I make it a point of at least logging a stream close failure. The usage then becomes:
FileOutputStream out = null;
try
{
out = new FileOutputStream("myfile.txt");
// More and more code goes here...
}
catch (Exception e)
{
}
finally
{
closeStream(out);
}
In Java 7 I believe that streams will be closed automatically and the need for such blocks should be mostly redundant.
Automatic Resource Management is coming in Java 7 which will automatically provide handling of this. Until then, objects such as OutputStream, InputStream and others implement the Closeable interface since Java 5. I suggest you provide a utility method to safe close these. These methods generally eat exceptions so make sure that you only use them when you want to ignore exceptions (e.g. in finally method). For example:
public class IOUtils {
public static void safeClose(Closeable c) {
try {
if (c != null)
c.close();
} catch (IOException e) {
}
}
}
Note that the close() method can be called multiple times, if it is already closed subsequent calls will have no effect, so also provide a call to close during the normal operation of the try block where an exception will not be ignored. From the Closeable.close documentation:
If the stream is already closed then invoking this method has no effect
So close the output stream in the regular flow of the code and the safeClose method will only perform close if something failed in the try block:
FileOutputStream out = null;
try {
out = new FileOutputStream("myfile.txt");
//...
out.close();
out = null;
} finally {
IOUtils.safeClose(out);
}
Discussion at
Try-catch-finally and then again a try catch
and
Is there a preference for nested try/catch blocks?
basically, the question is whether a close() exception is worth catching.
Project Lombok provides a #Cleanup annotation that removes the need for try catch blocks all together. Here's an example.
I tend to use utility functions for this:
public static void safeClose(OutputStream out) {
try {
out.close();
} catch (Exception e) {
// do nothing
}
}
which changes the code to the slightly more palatable:
FileOutputStream out = null;
try {
out = new FileOutputStream("myfile.txt");
// do stuff
} catch (Exception e) {
// do something
} finally {
safeClose(out);
}
You can't really do much better in Java at least until Java 7 when (hopefully) ARM ("Automatic Resource Management") blocks will help somewhat.
Write a method that looks something like below; call from your finally block...
static void wrappedClose(OutputStream os) {
if (os != null) {
try {
os.close();
}
catch (IOException ex) {
// perhaps log something here?
}
}
Separate your try/catch and try/finally blocks.
try
{
FileOutputStream out = new FileOutputStream("myfile.txt");
try
{
// More and more code goes here...
}
finally
{
out.close();
}
}
catch (Exception e)
{
//handle all exceptions
}
The outer catch will also catch anything thrown by the close.

Categories

Resources