I saw this example on the web and in the Book "Effective Java" (by Joshua Bloch).
try(BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))){
writer.write(str); // do something with the file we've opened
}
catch(IOException e){
// handle the exception
}
There is no problem with this example, BufferedWriter which will automatically get closed and that, in turn, will close the FileWriter; however, in other case, if we declare 2 nested resources this way:
try (AutoClosable res = new Impl2(new Impl1())) {... }
I guess it might happen that new Impl1() performs fine, but new Impl2() crashes, and in this case Java would have no reference to the Impl1, in order to close it.
Shouldn't it be a better practice to always declare multiple resources independently (even if not required in this case), like this?
try(FileWriter fw = new FileWriter(fileName);
BufferedWriter writer = new BufferedWriter(fw)){ ... }
After some searching I was able to find this article: https://dzone.com/articles/carefully-specify-multiple-resources-in-single-try
By definition JLS 14.20.3 a ResourceList consists of Resources separated by ;. Based on that we can conclude that a nested initialization like AutoClosable res = new Impl2(new Impl1()) is a single resource. Because of that rules defined for try-with-resources with multiple resources won't apply here, important ones being:
Resources are initialized in left-to-right order. If a resource fails to initialize (that is, its initializer expression throws an exception), then all resources initialized so far by the try-with-resources statement are closed. If all resources initialize successfully, the try block executes as normal and then all non-null resources of the try-with-resources statement are closed.
Resources are closed in the reverse order from that in which they were initialized. A resource is closed only if it initialized to a non-null value. An exception from the closing of one resource does not prevent the closing of other resources. Such an exception is suppressed if an exception was thrown previously by an initializer, the try block, or the closing of a resource.
What is more, Implt1#close() won't be called unless it is explicitly called inside of Impl2#close()
In short, it is better to declare multiple resources in separate statements separated with ;, like so:
try(Impl1 impl1 = new Impl1();
Impl2 impl2 = new Impl2(impl1))
If the exception happens in the try part, there is no resource leakage (assuming Impl1 is written well). Notice that a raised exception in Impl1() will not reach Impl2 as the constructor argument is evaluated before calling it.
try (AutoClosable res = new Impl2(new Impl1())) {
So it is fine to nest such wrapping constructors; better style if the code does not become to long.
One remark: FileWriter and FileReader are old utility classes using the platform encoding, which will differ per application installation.
Path path = Paths.get(fileName);
try (BufferedWriter writer =
Files.newBufferedWriter(path, StandardCharsets.UTF8)) {
First of all, for the sake of a little sanity check, I would say, that I could not find the example, you provided, in Joshua Bloch's Effective Java (3rd Edition, 2018). If you are reading the previous version, it should be better to get the latest one. If it is my bad, please refer particular page number to me.
Now with respect to the question itself.
Let's begin with JSL §14.20.3, which says, that Resources are separated by ;. This means, that disregarding of how long our decoration chain of the object creations will be (e.g. new Obj1(new Obj2(...new ObjK(..))); it will be treated as a one single resource, as it is a one definition/statement.
As we now know what does a Single Resource constitute, let me shed some light from my observation.
Reasons, why it is better to define resources separately
JSL §14.20.3 also states, that:
If a resource fails to initialize (that is, its initializer expression throws an exception), then all resources initialized so far by the try-with-resources statement are closed. If all resources initialize successfully, the try block executes as normal and then all non-null resources of the try-with-resources statement are closed.
Q: What does that mean for us?
A: If that single resource is a chain of objects passed into wrapping constructors, it does not mean, that throwing an exception from the initialization phase will close those embedded resources, rather the .close() method will be invoked on the parent (wrapper, enclosing) objects, and therefore, you might easily end up with a resource leak.
On the other hand, you can be resting assured that all resources will be closed, if you have defined them separately.
JSL §14.20.3 also states, that:
An exception from the closing of one resource does not prevent the closing of other resources. Such an exception is suppressed if an exception was thrown previously by an initializer, the try block, or the closing of a resource.
Q: What does that mean for us?
A: If you have declared your resources separately, then it does not matter which throws exception and which does not. They all will be closed successfully.
Unfortunately the book you mentioned (at least the 3rd version it) does not cover the question you brought up here; however, I did some more research and found that Core Java (10th Edition), by Cay S. Horstmann, confirms the point I referred to above, in its §7.2.5:
When the block exits normally, or when there was an exception, the in.close()
method is called, exactly as if you had used a finally block.
and
No matter how the block exits, both in and out are closed.
in and out are Autoclosable objects in the examples given in the book.
Q: What does this mean?
A: It means, that exceptions thrown from any phase of one of the resources, does not anyhow affect how another resources are closed.
Based on all above, I think, that it also depends on how the resources are implemented. E.g. if the enclosing resource, upon an invocation of its .close(), implements the logic to close the enclosed resource, then your concern:
I guess it might happen that new Impl1() performs fine, but new Impl2() crashes, and in this case Java would have no reference to the Impl1, in order to close it.
will not really be a problem in your particular case, as the container resource which is being closed, will hold a reference to the contained resource and eventually will close it (or will just implement its closure);
However, it is still a bad idea to construct resources in the decoration of chaining them into wrapper constructors, due to several reasons I brought up.
P. S.
In any case, disregarding of how the resources are implemented or how you chain them or etc. everything, including JLS, Core Java book, OCP Java SE 8 book, and points brought here, indicate that it's always best to declare your resources separately.
Related
If I use FileSystems.getDefault().getPath() it holds resource at FileSystems.getDefault(). Few tools like sonar, coverity give high impact issues of resource leak for using this.
If I replace it with Paths.get() all the such tools quietly accept this and there is no error or warning of resource leak.
If we see the implementation of Paths.get(), it is literally doing FileSystems.getDefault().getPath()
My question here is, how does java handle resource leak for Paths.get() because the code is exactly same but we don't have reference to FileSystems.getDefault() to explicitly close it?
Your tools are reporting a false positive. That's because the declared type returned by FileSystems.getDefault(), FileSystem, implements Closeable. That means that ideally you should close it. However, the default file system is an exception (it even throws an UnsupportedOperationException). You're tools cannot make that distinction.
This happens more often than you'd think. Some examples I've seen too often:
The result of Objects.requireNonNull. The input is returned as-is, but if the input is AutoCloseable my IDE treats it as a new resource.
The input stream or reader from a servlet request, and the output stream or writer from a servet response.
There are some cases where tools and IDEs can be smart. For instance, if I declare a variable as ByteArrayInputStream, ByteArrayOutputStream, StringReader or StringWriter, then my IDE knows they don't need to be closed. However, when I return these from a method as InputStream, OutputStream, Reader or Writer respectively, my IDE starts complaining if I don't close them.
If you know that it is a false positive, you can use #SuppressWarnings("resource") to ignore warnings by some tools. That can often be applied to single variables:
#SuppressWarnings("resource") FileSystem defaultFS = FileSystems.getDefault();
Path path = defaultFS.getPath("foo");
However, even then sometimes your tools will complain, and you have to suppress the resource warnings for the entire method. If that's the case, try to keep your method (and therefore the scope of the warning suppression) as small as possible; split off code to a new method if needed.
What is the reason for the JVM handling SIGPIPE the way it does?
I would've expected for
java foo | head -10
with
public class Foo {
public static void main(String[] args){
Stream.iterate(0, n -> n + 1).forEach(System.out::println);
}
}
to cause the process to be killed when writing the 11th line, however that is not the case. Instead, it seems that only a trouble flag is being set at the PrintStream, which can be checked through System.out.checkError().
What happens is that the SIGPIPE exception results in an IOException.
For most OutputStream and Writer classes, this exception propagates through the "write" method, and has to be handled by the caller.
However, when you are writing to System.out, you are using a PrintStream, and that class by design takes care of the IOException of you. As the javadoc says:
A PrintStream adds functionality to another output stream, namely the ability to print representations of various data values conveniently. Two other features are provided as well. Unlike other output streams, a PrintStream never throws an IOException; instead, exceptional situations merely set an internal flag that can be tested via the checkError method.
What is the reason for the JVM handling SIGPIPE the way it does?
The above explains what is happening. The "why" is ... I guess ... that the designers wanted to make PrintStream easy to use for typical use cases of System.out where the caller doesn't want to deal with a possible IOException on every call.
Unfortunately, there is no elegant solution to this:
You could just call checkError ...
You should be able get hold of the FileDescriptor.out object, and wrap it in a new FileOutputStream object ... and use that instead of System.out.
Note that there are no strong guarantees that the Java app will only write 10 lines of output in java foo | head -1. It is quite possible for the app to write-ahead many lines, and to only "see" the pipe closed after head has gotten around to reading the first 10 of them. This applies with System.out (and checkError) or if you wrap FileDescriptor.
This is a very well discussed topic. Out of many links, I did find the below two useful.
1,
2
My questions is this:
I am writing multiple methods, some for general purposes- say, writing into file, reading from file, splitting a string using some regex.
I am calling these methods from different parts of my application- say class1, class 2 and class 3 calls the file writing method, but with different file names and data.
Where should I include try catch and throws?
1. The outermost method, say the main, from where I am calling the class1, class2 and class 3 methdods have one set of try, catch and use throws in the innermost functions.
Or, have a try catch in the innermost-None to the outer files..
Which is a better option and why? Are there any other ways of dealing with this.
Thanks
The heart of this matter is how to decide logically where your exceptions need to be handled.
Let's take an example. A method that takes a File object and performs some operation.
public void performFileOperation(File f) throws FileNotFoundException{
// Perform logic.
}
In this case, chances are that you want the class/method calling this method to handle the Exception. If you had a try/catch block in the performFileOperation() method, then the method calling the performFileOperation() method would never know if the operation failed (and therefore can't know what to do about it).
It is really a matter of where it makes sense to handle the Exception that is thrown. You need to work out which sections of your code need to know that an exception has occurred, and use try/catch blocks there. If the next level up needs to know as well, then the catch block can throw the Exception so the method further up the stack can know about and handle it as well.
Another good way to look at it is that most exceptions need to be handled. Something needs to be done about them. If your method is not in a position to do something significant to handle that exception then it needs to throw the Exception until it makes it's way to somewhere that can meaningfully handle (read, do something about) it.
I hope this helps.
This came up in a discussion with a colleague today.
The Javadocs for Java's IllegalStateException state that it:
Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.
And Effective Java says (Item 60, page 248):
Another commonly reused exception is IllegalStateException. This is generally the exception to throw if the invocation is illegal because of the state of the receiving object. For example, this would be the exception to throw if the caller attempted to use some object before it had been properly initialized.
It seems there's a bit of discrepancy here. The second sentence of the javadocs makes it sound like the exception could describe a very broad condition about the Java execution state, but the description in Effective Java makes it sound like it's used for conditions related specifically to the state of the state of the object whose method has been called.
The usages I've seen in the JDK (e.g. collections, Matcher) and in Guava definitely seem to fall into the category that Effective Java talks about ("This object is in a state where this method can't be called"). This also seems consistent with IllegalStateException's sibling IllegalArgumentException.
Are there any legitimate IllegalStateException usages in the JDK that do relate to the "Java environment" or "Java application"? Or do any best practices guides advocate using it for the broader execution state? If not, why the heck are the javadocs phrased like that? ;)
Here is one particularly legitimate usage of this exception in JDK (see: URLConnection.setIfModifiedSince(long) among 300+ other usages of it:
public void setIfModifiedSince(long ifmodifiedsince) {
if (connected)
throw new IllegalStateException("Already connected");
ifModifiedSince = ifmodifiedsince;
}
I think the example is pretty clear. If the object is in particular state ("Already connected"), some operations should not be called. In this case when connection was established, some properties cannot be set.
This exception is especially useful when your class has some state (state machine?) that changes over time, making some methods irrelevant or impossible. Think about a Car class that has start(), stop() and fuel() methods. While calling start() twice, one after another, is probably nothing wrong, but fueling a started car is certainly a bad idea. Namely - car is in a wrong state.
Arguably good API should not allow us to call methods in wrong state so that problems like that are discovered at compile time, not at runtime. In this particular example connecting to a URL should return a different object with a subset of methods, all of which are valid after connecting.
Here is an example in the JDK. There is a package private class called java.lang.Shutdown. If the system is shutting down and you attempt to add a new hook, it throws the IllegalStateException. One could argue that this meets the criteria of the "javadoc" guidance - since it is the Java environment that is in the wrong state.
class Shutdown {
...
/* Add a new shutdown hook. Checks the shutdown state and the hook itself,
* but does not do any security checks.
*/
static void add(int slot, Runnable hook) {
synchronized (lock) {
if (state > RUNNING)
throw new IllegalStateException("Shutdown in progress");
if (hooks[slot] != null)
throw new InternalError("Shutdown hook at slot " + slot + " already registered");
hooks[slot] = hook;
}
}
However it also illustrates that there really is no distinction between the "javadoc" guidance and the "Effective Java" guidance. Because of the way Shutdown is implemented, the shutdown-ness of the JVM is stored in a field called state. Therefore it also meets the "Effective Java" guidance for when to use IllegalStateException, since the "state" field is part of the state of the receiving object. Since the receiving object (Shutdown) is in the wrong state, it throws the IllegalStateException.
In my opinion the two descriptions of when to use IllegalStateException are consistent. The Effective Java description is a bit more practical, that's all. For most of us, the most important part of the entire Java environment is the class that we are writing right now, so that is what the author is focusing on.
I guess if you see usage of IllegalStateException I would say second if more appropriate. This exception is used in lot of packages
java.net
java.nio
java.util
java.util.concurrrent etc
To specify one example ArrayBlockingQueue.add throws this exception if queue is already full. Now full is state of the object and it is being invoked at inappropriate or Illegal time
I guess both means same but difference of wording.
Given a library, it should throw an IllegalStateException or IllegalArgumentException whenever it detects a bug due to the user code, whereas the library should throw an AssertionError whenever it detects a bug due to the library's own implementation.
For example, in the library's tests, you may expect the library throws an IllegalStateException when the order of method calls are wrong. But you will never expect the library throws an AssertionError.
There is no 'discrepancy' here. There is nothing in Bloch's wording that excludes what it says in the JLS. Bloch is simply saying that if you have circumstance A, throw this exception. He is not saying that this exception is/should be thrown only in this condition. The JLS is saying this exception is thrown if A, B, or C.
I ran into this with:
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
...
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
I think it will be impractical for me to throw IllegalStateException here in place of AssertionException even though this falls into the "the Java environment" category.
I'm writing a test for a piece of code that has an IOException catch in it that I'm trying to cover. The try/catch looks something like this:
try {
oos = new ObjectOutputStream(new FileOutputStream(cacheFileName));
} catch (IOException e) {
LOGGER.error("Bad news!", e);
} finally {
The easiest way seems to make FileOutputStream throw a FileNotFoundException, but perhaps I'm going about this all the wrong way.
Anyone out there have any tips?
You could set cacheFileName to an invalid name or to one you know doesn't exist.
From your comment:
Yes, I suppose the question should
really have been "How do I create a
file that does not exist on both Linux
and Windows?" On windows, I can use
'new File("X:/")', where X: is a drive
letter that does not exist. On Linux,
this does not work because that is a
valid file name.
Look at java.io.File.createTempFile. Use it to create the file and then delete it.
Probably pass it something like:
File tempFile;
tempFile = createTempFile(getClass().getName(),
Long.toString(System.currentTimeMillis());
tempFile.delete();
That should give you a unique name in a platform indendent manner that you can safely use without (much) fear of it existing.
There are two parts to any test: getting it to happen and measuring that you got the correct result.
Fault Injection
The easiest answer is the one that's already been mentioned, which is to set cacheFileName to a file that will never exist. This is likely the most practical answer in this situation.
However, to cause an arbitrary condition such as an IOException, what you really want is Fault Injection. This forces faults in your code without forcing you to instrument your source code. Here are a few methods for doing this:
Mock objects You could use a factory method to create an overridden ObjectOutputStream or FileOutputStream. In test code the implementation would throw an IOException when you wanted to, and in production code would not modify the normal behavior.
Dependency Injection In order to get your Mock Object in the right place you could use a framework such as Spring or Seam to "inject" the appropriate object into the class that's doing the work. You can see that these frameworks even have a priority for objects that will be injected, so that during unit testing you can override the production objects with test objects.
Aspect Oriented Programming Instead of changing the structure of your code at all, you can use AOP to inject the fault in the right place. For instance, using AspectJ you could define a Pointcut where you wanted the exception to be thrown from, and have the Advice throw the desired exception.
There are other answers to fault injection on Java; for instance a product called AProbe pioneered what could be called AOP in C long ago, and they also have a Java product.
Validation
Getting the exception thrown is a good start, but you also have to validate that you got the right result. Assuming that the code sample you have there is correct, you want to validate that you logged that exception. Someone above mentioned using a Mock object for your logger, which is a viable option. You can also use AOP here to catch the call to the logger.
I assume that the logger is log4j; to solve a similar problem, I implemented my own log4j appender which captures log4j output: I specifically capture only ERROR and FATAL, which are likely to be the interesting log messages in such a case. The appender is referenced in log4j.xml and is activated during the test run to capture error log output. This is essentially a mock object, but I didn't have to restructure all my code that got a log4j Logger.
I'm writing a test for a piece of code
that has an IOException catch in it
that I'm trying to cover.
I'm not entirely sure I understand your goal, but if you want to test if the exception is thrown, you can tell the test you expect it to throw the exception:
#Test(expected=IOException.class)
Your test will then fail if the exception is not thrown, and succeed if it is thrown (like, if the cacheFileName file does not exist).
A FileNotFoundException would obviously trigger the catch. The javadoc states the cases where it will be thrown.
You should also consider that the ObjectOutputStream constructor can throw an IOException so may want to cover this case in your tests.
Two easy ways would be either set cacheFileName to a non-existent file or set the specified file to read-only access.
-John
As the code is currently written, you could try to mock out the error() call on the LOGGER object and check to see if it gets called when you expect an IOException.
Your desire to test may have uncovered a fundamental problem with the code as it's written. An error is occurring but there's no boolean or flag value (set the filename to a special pattern) that provides other sections of code to determine if writing to the file was successful. If this is contained in a function, maybe you could return a boolean or set an object level variable.
cacheFileName = "thisFileShouldNeverExistAndIfItDoesYouAreScrewingUpMyTests";
Sure you could take steps and jump thru hoops to programatically make sure that the file name will never, ever, ever exist, or you could use a String that will never exist in 99.99999% of cases.
I hope this is what you meant.
if(new File(cachedFile).exists()) {
oos = new ObjectOutputStream(new FileOutputStream(cacheFileName));
//do your code here
} else {
throw new FileNotFoundException("File doesn't exist!");
}