I have a design level doubt regarding creating APIs in Java. Suppose I have a class as follows :-
class Test
{
public final static String DEFAULT_ENCODING = "utf-8";
public byte[] encodeIt(String input)
{
try {
return input.getBytes(DEFAULT_ENCODING);
} catch(UnsupportedEncodingException e) {
// do something
}
}
}
I know that the UnsupportedEncodingException would never arise as I'm using a static string as the input to toBytes. It doesn't make sense to have encodeIt do a throws UnsupportedEncodingException because I dont wish the API users to expect and catch that error either.
In such cases, is the best practice to have an empty catch block?
It is a bad idea to have empty catch blocks. Even though your reasoning seems correct this design will at some stage cause you endless debugging and searching once exceptions do start happening and your code is swallowing them. I would wrap your exception in a RuntimeException here and throw that. Like so:
public encodeIt(String input)
{
try {
return input.getBytes(DEFAULT_ENCODING);
catch(UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
This way your exception will not stay hidden might it occur nor do your API users have to cater for it.
I do something like this:
public byte[] encodeIt(String input) {
try {
return input.getBytes(DEFAULT_ENCODING);
}
catch (UnsupportedEncodingException e) {
throw new ShouldNeverHappenException(e);
// or: throw new IllegalStateException(e);
}
}
(where ShouldNeverHappenException is a runtime exception, of course).
This way, if someone happens to change the constant value, or add an encoding argument, the method will fail fast and the problem will not go unnoticed or buried in log files.
In such cases, is the best practice to have an empty catch block?
I don't feel that's a good idea, ever. Empty catch blocks mean that something could happen and you'll never know.
Don't throw this exception. Catch it and log it so you can check your assumption that it can never happen, but at least you'll know if never arrives.
I usually follow the strategies outlined by other answers to this question (like soften the checked exception to RuntimeException). However, one interesting alternative is to use an assertion:
public byte[] encodeIt(String input)
{
try {
return input.getBytes(DEFAULT_ENCODING);
} catch(UnsupportedEncodingException e) {
assert false;
return null;
}
}
When assertions are enabled with the -ea JVM flag, this method would throw an AssertionError if ever UnsupportedEncodingException were thrown. An annoyance is the need to return a value (such as null), otherwise the code won't compile.
So perhaps the following is "nicer":
public byte[] encodeIt(String input)
{
try {
return input.getBytes(DEFAULT_ENCODING);
} catch(UnsupportedEncodingException e) {
throw new AssertionError("Unexpected.", e);
}
}
Not so materially different than throwing RuntimeException except that AssertionError is nicely self-documenting. And, being a subclass of Error, it represents a more fundamental failure than Exception normally implies. No chance for a catch (Exception e) clause somewhere higher up on the stack handling this thing (were it to ever occur).
The best way I think is to avoid checked exception. Just use an unchecked one. Then you will take the best of 2 worlds: you do will signal the error if it really happens and you won't force the user of your API to handle the exception.
If you are very, very sure that it would never happen, leave an empty catch block.
But for practice, just in case you change the code later on, it is better to log it to the console when the exception happens.
Related
By "method exit" - I mean the actions in a method such as return or throw new... that the compiler considers the end of a method - if you could please tell me the accepted word for "method exit", I will edit the question
My problem is the following:
I do a lot of throw new RuntimeException(...
So, I decided to "tuck it in" as:
public static void quickRaise (String msg) { throw new RuntimeException(msg); }
And then I can reuse it.
(This will help me in the future to enhance the procedure around raising Runtime Exceptions and even
switch to a custom Exception class, without fishing in the code for exception throws)
However, where before I could write:
public MyType doSomething() {
try {
//...
return new MyType (parameter);
} catch (Exception e) {
throw new RuntimeException("msg")
}
}
And the compiler would correctly understand that "this method either exits by return or by throw" and therefore there are no logical "dead ends"
When I changed throw new RuntimeException("msg") to quickRaise("msg"), the compiler no longer considers my method "complete". It complains about a missing return statement, even though quickRaise is semantically equivalent to throw (or at least this is what I am trying to do!)
Let me try to reiterate the problem by a reproductive example (this will not compile, which is the problem):
public static void main(String[] args) {
System.out.println(doSomething());
}
public static String doSomething () {
try {
//... Some fun stuff going on here
return "Something";
} catch (Exception e) {
quickRaise("Could not find handshakes");
//throw new RuntimeException("If you uncomment this line, it will compile!");
}
}
public static void quickRaise (String msg) {
throw new RuntimeException(msg);
}
Your idea is highly inadvisable.
For example, this is just bad codestyle:
try {
someIO();
} catch (IOException e) {
throw new RuntimeException("Problem with IO");
}
The reason it's bad is that you have now obliterated the actual information about the problem. That information is locked into 5 separate parts of that exception you just caught: Its type (for example, FileNotFoundException, its message (e.g. "Directory /foo/bar does not exist"), its stack trace, its causal chain, and as throwables are objects, any particular extra detail for that particular kind of exception (such as the DB-engine-specific error coding for some SQLException).
Throwing this info away is silly.
All you'd need to do to fix this, is to add the cause:
} catch (IOException e) {
throw new RuntimeException("IO problem", e);
}
Now the IOException is marked as the cause of the exception you are throwing, which means in error logs you'll see it + the message + the stack trace of it + the stack trace of any causes it had as well.
All you need to do to make the compiler realize that the method ends here, is to throw it:
public static RuntimeException quickRaise(String msg) {
throw new RuntimeException(msg);
return null; // doesn't matter, we never get here
}
// to use:
throw quickRaise(msg);
But, as I explained before, this is a very bad idea.
Secondarily, having the idea of 'I just want to throw an exception and maybe later I want to replace the kind of exception I throw' also doesn't really work out: You need to pick a proper exception for the situation, therefore you cannot write a one-size-fits-all throw method in the first place.
Okay, so what do I do?
Primarily, learn to embrace throws clauses. If your method fundamentally does I/O (for example, the javadoc of it and/or the name makes that obvious, it is for example saveGame(Path p), or scanUserHome), then it should be declared to throws IOException.
If your method is an entrypoint (as in, it is the first point where your own code begins running), then your method should be declared to throws Exception. For example, your public static void main() method should throws Exception. Sometimes an entrypoint isn't main but something else (a webhandler routing hook for example), and sometimes backwards silly franeworks prevent you from doing that, but there tends to be a wrap functionality (such as } catch (Exception e) { throw new ServletException(e); }).
For exceptions which are both [A] fundamentally not part of the method's purpose, but more part of an implementation detail and [B] is very unlikely to go wrong and there's not much you can do other than hard crash if it would, then, yeah, rewrap as RuntimeException. There isn't a lot of point in ever changing this 'globally' for all such exceptions. At best you belatedly realize that failure is a bit more likely than you originally thought and either create a proper exception for it and document this behaviour. But that's, again, on a per-method basis, not something you can apply in blanket fashion.
Your approach is fundamentally at odds with the need for the compiler to see that the flow terminates at the throw statement.
I'd suggest having a utility method that just constructs an exception, which you then throw from the original point.
It's either than or put dummy returns after each call to quickRaise().
I have to work with lambda expressions. In this case the try block have create a JSON Object with the input strings. But I must implement that, if the creation doesn't work, it should return an Optional.Empty() instead of null.
How can I do that ?
In the current situation, the workflow stops, till the catch happens. So the other strings are ignored.
private Optional<JSONObject> testFile (Optional<String> jsonFileContent)
{
try
{
return jsonFileContent.map(fileContent -> new JSONObject(jsonFileContent)); // this lambda expression needs to be extended
}
catch(Exception e)
{
return null;
}
}
That is not a good way to handle errors, because:
If something goes wrong, neither you nor anyone who calls your code will have any idea why the operation failed.
What will you tell end users? “Something went wrong but we have no idea what, so you can’t do anything about it, and don’t bother trying to tell us either”?
If you aren’t sure of the best way to deal with an exception, don’t catch it at all. Instead, declare your method to throw it, and let a caller who is prepared to handle it deal with the exception. For example, a user interface might catch the exception and provide some of its details to the end user.
private Optional<JSONObject> testFile(Optional<String> jsonFileContent)
throws JSONException
{
if (jsonFileContent.isPresent())
{
return Optional.of(new JSONObject(jsonFileContent.get()));
}
else
{
return Optional.empty();
}
}
A note about catching exceptions:
Most classes which descend from RuntimeException in Java SE are meant to indicate programmer errors. Examples would be:
NullPointerException
IndexOutOfBoundsException
IllegalArgumentException
When these occur, they indicate your program logic is broken. You are not supposed to recover from them; you are supposed to notice them and fix the code responsible. Catching them and suppressing them will not make your program work.
Such exceptions should never be caught. This also means you should never write catch (Exception …) or catch (RuntimeException …). If you must write a catch block, catch only the exceptions you absolutely need to catch.
But the better option is simply not to catch anything and declare your method with throws JSONException.
private Optional<JSONObject> testFile (Optional<String> jsonFileContent)
{
try{
return jsonFileContent.map(fileContent -> a(fileContent));
}
catch(Exceptione)
{
return null;
}
Optional a(Optional<String> jsonFileContent) {
try{
return new JSONObject(jsonFileContent); // this lambda expression needs to be extended
} catch (Exception e) {
return Optional.empty();
}
}
You can write a method which would create a
new JSONObject(jsonFileContent).
And you will wrap the logic in your method in try with catch and will return null if an exception occurred.
Actually then after you invoked map you can do filter and then findFirst which is null and as findFirst returns Optional it
will return an empty Optional as you wanted.
What is the correct way of using return in the following method?
public Image getImage() {
try {
Image img = ImageIO.read(new File(URL));
return img;
} catch (IOException e) {
e.printStackTrace();
}
}
IDE asks me to return something at the end. But I don't know what I'm supposed to return.
The correct answer is: depends on your requirements. Options are:
If the caller of this method could deal with a null answer, return null from the catch block. Alternatively, you could return a "special" pre-defined image object in that case. Might be a slightly better way - as returning null is always the first step to cause Nullpointerexceptions elsewhere.
Or, you catch and rethrow some unchecked exception. Or you don't catch at all and you add "throws IoException" to the signature of the method.
When you are using Java 8, the simple solution is to use the new class Optional.
If your method catches the exception and doesn't throw anything, it must return some default value (perhaps null) after the try-catch block.
I think you shouldn't catch the exception. This way you only return a value if the ImageIO.read operation doesn't throw an exception. Of course you'll have to declare that your method throws IOException, since that's a checked exception.
This will force the caller of your method to handle IOException (or let its own caller handle it).
If you run following code then it will compile and run successfully,
public class Example {
public static void main(String[] args) {
// insert code here
try {
new Example().go();
// throw new OutOfMemoryError();
} catch (Error e) {
System.out.println(e);
}
}
void go() {
go();
}
}
With following output :
java.lang.StackOverflowError
So my question is "Can we catch an Error"..??
Answer to your question is yes, you can catch error in java. And your code is almost correct. Your method go() calls itself infinitely and therefore causes StackOverflowError that is caught in your catch block and printed by System.out.println()
Yes, you can catch an Error, but you are advised not to do it, since Errors indicate serious problems that a reasonable application should not try to catch. (as stated in the Javadoc of Error)
Yes, we can catch an error.
The Throwable class is the superclass of all errors and exceptions in the Java language. Only objects that are instances of this class (or one of its subclasses) are thrown by the Java Virtual Machine or can be thrown by the throw statement.
Similarly, only this class or one of its subclasses can be the argument type in a catch clause. For the purpose of compile-time checking of exceptions, Throwable and any subclass of Throwable that is not also a subclass of either RuntimeException or Error are regarded as checked exceptions.
try {
while(true) {
}
} catch (Throwable e) {
// TODO: handle exception
System.out.println(e);
}
Note that there's a difference between StackOverflowException and StackOverflowError, since you have an error, it's a serious indication that you should never try to catch it.
Just don't do infinite things in your code, when this error happens, no stack space is available, how would you want to proceed?
StackOverFlowError indicates that you have severe problems, it's a bad idea to catch this error, instead, try to understand what problems you have in your code and fix them.
In Java 7, the feature was added to (via getSuppressed()) get exceptions thrown from the implicit finally block of a try-with-resources statement.
There still doesn't seem to be a way (that I know of) to do the opposite - when there is an explicit finally block and that throws an exception, masking the exceptions thrown and pending from the try/catch.
Why does Java not provide functionality to get these buried/lost exceptions through a mechanism similar to getSuppressed()?
It would seem that the implementation of this functionality would be similar to that used in getSuppressed() or chained exceptions, and the provided benefit would be very useful, yet it continues to be left out of each release.
What would be the danger of making these masked exceptions available to programmers through a method call similar to getSuppressed()?
(Apologies in advance if this functionality already exists and I'm just clueless.)
The suppression thing isn't limited to try-with-resources, and you can use it for similar situations yourself. E.g., it is provided for other situations.
try-with-resources puts the logic for closing the resources behind the scenes, so you don't have direct access in your own code to dealing with any exceptions that occur during the process. So they added the "suppression" thing so they could use it in that behind-the-scenes code.
But cleverly, they didn't only make it something that could be used there. You can use it yourself, via Throwable#addSuppressed.
You can see this in the pseudo-code example given in JLS §14.20.3.1; here's a real code version of it:
{
SomeResource someResource = null;
Throwable primaryException = null;
try {
someResource = /*...get the resource...*/;
/*...do something...*/
}
catch (Throwable t) {
primaryException = t;
throw t;
}
finally {
if (someResource != null) {
if (primaryException != null) {
// Dealing with a primary exception, close the resource
// and suppress any exception resulting
try {
someResource.close();
}
catch (Throwable suppressed) {
primaryException.addSuppressed(suppressed);
}
}
else {
// Not dealing with a primary exception, close the
// resource without suppressing any resulting exception
someResource.close();
}
}
}
}
Note the different behaviour (Using exception A for the exception in try, exception B in finally):
In a try-with-resources exception A suppresses exception B.
In a normal try exception B masks exception A.
If you want backwards compatibility (And you ALWAYS want it), you need to make B suppress A. But that is the complete opposite of what try-with-resources does (and actually, the opposite of what most developers want).
As a workaround, you can just use the (slightly modified) code that is in the Oracle blog on how try-with-resources works:
Exception ex;
try {
doWork();
} catch (Exception e) {
ex = e;
throw(e);
} finally {
try {
doFinally();
} catch (Exception e) {
if (ex != null) {
ex.addSuppressed(e);
} else {
throw(e);
}
}
}
Obviously move the throw out of the initial catch if you want the finally exception to suppress the initial one.