Related
I understand, Assertions are used in tests to check if the programmer's pre- and post- conditions are true and if the assertions fail, there is/are bug/bugs that need to debugged and fixed.
An assertion is a software construct where the developer states ("asserts") a condition that he believes will always be true. If the condition evaluates to false in some languages an exception is thrown, in others a message is printed, and in others the program ceases to operate.
"A message is printed" highlighted in the above definition caught my attention.
My question is, can we extend the use of assert statements in the actual code itself and catch AssertionErrors to log the messages and not just tests?
Basically to avoid too much verbose with if-else statements(I hate if-else btw, personally).
For example, all of below
String response = aMethod(sendSomething);
if (response!=null && response!="") {
//blah blah
} else {
log.error("Response is null");
throw new NoDataFoundException();
}
could be replaced with the below that provides more detailed messages.
try{
assertThat(aMethod(sendSomething), notNullValue());
} catch (AssertionError e) {
log.error(e.getMessage());
}
You don't want to catch an assertion failure(*). By definition, the program is operating outside its design perimeter. The only safe thing to do is get out.
(*) OK, you can catch it if the point of catching it is to log whatever you anticipating you'll need to diagnose the problem, and then get out quickly.
In your example, it appears that after testing for a response and logging the failure, you'll carry on inline. In general, that would be a bad idea, but perhaps this was just a quick illustration on your part and should not be taken too literally.
As to what I take to be your overall point: yes, if you're checking pre/postconditions at all, leave the checks in shipping code.
My code would look like:
response = aMethod(sendSomething);
if (response == null || response.isEmpty())
throw new InternalError("....");
and there would be something catching the error at some outermost layer, a point of exception handling being that you can transfer control far away rather than having to deal with everything at the point it occurs -- especially if "it can't happen".
Consider the following code snippet:
int index = FindClosestIndex(frame);
if (_data[index].Frame == frame)
return _data[index];
else
return interpolateData(frame, _data[index - 1], _data[index]);
Now, in this case I have done some checking before this code block to make sure that FindClosestIndex() will never return 0. It should be impossible. However, the logic in FindClosestIndex is somewhat complex, so it's very possible that a bug has yet to be discovered in some rare corner case that no one anticipated, and even though my code is correct, FindClosestIndex may incorrectly return 0.
If it does return 0, I will get an ArgumentOutOfRangeException on the _data[index - 1] statement. I could let that exception bubble up, but I would rather do this:
if (index == 0)
throw new ApplicationLogicException("There is a bug that caused FindClosestIndex to return an int <= 0 when it shouldn't have.");
Would you recommend this practice of throwing a custom exception if your code detects an error state? What do you do when you have a situation like this?
Personally, I do include custom exceptions like that. It's like the condom argument: it's better to have it and not need it than to need it and not have it. If in the rare case that it does occur, including the custom exception message will make tracking down the logic error that much easier, yet your executable is only a tiny bit bigger. Otherwise, your ArgumentOutOfRangeException could happen anywhere. The time it takes you to add the exception far outweighs the time it takes you to track down the error without it.
Is it always a bad programming technique to leave a catch block empty when using a try-catch block?
In cases where I am expecting an exception, for example, I am reading 10 values from a file...and converting each value into a String. There is a possibility that one of the 10 values can be a null, but I don't want to stop my execution at that point and rather continue (obvious use of try catch)
A lame example of what I am trying:
String _text = textReader.ReadLine(); //Assuming this RETURNS a NULL value
try {
String _check = _text.ToString();
//Do something with _check, but it should not be NULL
}
catch (Exception)
{ //Do Nothing }
At this point, when I catch an exception:
1. I don't want to log this. Since I am expecting a buggy value.
2. I don't want to re-throw the exception up the call-stack.
3. I want to simply continue with my execution
Under these cases, is it acceptable to leave the catch empty? Or is this a complete NO-NO and there is a better way to handle this?
I presume this can be a community wiki since it also deals with programming techniques.
- Ivar
I assume that you mean
_text.ToString()
and you're concerned about the case when _text may be null?
I don't like your use of exceptions in this case. Put yourself in the mind of someone needing to maintain this code. They see:
catch (Exception) { }
Can they really deduce that all this is doing is catching the Null case? They have to consider what other Exceptions might be thrown. At the very least this raises uncertainty in the maintainer's mind.
Why could you not code:
if ( _text != null ) {
String _check = _nullValue.ToString();
}
This says exactly what you mean.
But taking this further, what does getting a value of NULL mean? You're reading a file that may have 10 values in it. I'm guessing that maybe blank line gives a null for you?
What do intend if you get:
1
2
<blank line>
4
...
10
So that's 9 good values and a blank line. What will you do if instead you get 10 good values and a blank line? 11 good values? 11 good values and a blank line?
My point is that silently ignoring oddities in user input is often a bad idea. It's quite likely that some of the cases above are actually typos. By warning in some of these cases you may be very helpful to the user. This implies that probably most odditities in input need at least some kind of count, if not an actual immediate error log.
You might, for example, emit a message at the end
Your file contained 13 lines, two lines were blank. We processed 10 valid values and ignored one.
At the very leasyt for debugging purposes you might have trace statements in the error paths.
Summary: completely ignoring Exceptions is rarely the right thing to do.
If it's expected it's not really exceptional. Is this a good use of exceptions? It may be more appropriate to test for a null value before trying to do stuff.
if(_text != null)
// do something
The best argument I liked was that the code will become highly un-maintainable. And my aim was to make my code as easy to understand as possible.
With the suggestions above, I have an army of ternary operators in place (my personal favorite over big if-else blocks).
And the code definitely looks better! and I think unless the try-catch is well documented, I don't myself see a good reason for having empty catch statements anymore.
Thanks Guys!!
-Ivar
//
// To Throw
void PrintType(object obj)
{
if(obj == null)
{
throw new ArgumentNullException("obj")
}
Console.WriteLine(obj.GetType().Name);
}
//
// Not to Throw
void PrintType(object obj)
{
if(obj != null)
{
Console.WriteLine(obj.GetType().Name);
}
}
What principle to keep?
Personally I prefer the first one its say developer-friendly(notified about each "anomaly").
The second one its say user-friendly(let user continue work even if "inside" not everything does right).
I think that is more complicated to find errors and bugs in the maintenance phase when you silently let the things to go on. If something goes wrong you are not notified at once, and sometimes have errors far away from the main error cause, and spend a lot of time to find it.
What do you think?
The second one is lethal. Failing silently is always the wrong thing to do. Suppose this were the banking system in the bank that holds your account. Would you like it if there was a problem paying in your salary and the system silently ignored it?
If the method body handles the null obj properly (in other words, obj != null is not a requirement), then there's no need to throw an exception.
In all other cases: Throw. Let the client take responsibility for their flawed input.
Throwing an exception (if null is an error) seems far better than silently ignoring an error.
There is a third option you can consider:
void PrintType(object obj)
{
Console.WriteLine(obj.GetType().Name);
}
This also throws an exception when obj is null. The advantage of this, is that less code is involved. The disadvantage of this approach is that it is more difficult to tell whether obj can be null.
Throw.
Let the caller of a function determine if it is important enough to throw an exception to the user on a null value, but the function itself should throw because of the invalid argument.
I'd say that it depends on your (developer) preference. From the user perspective, he should never see an unhandled exception, but it does not mean you cannot use exceptions.
I prefer the first one, because I find null to be a totally unnecessary (and annoying) construct, so I make effort to code without it. If there is a null somewhere, someone made a mistake, so the best thing is to just barf out instead of pretending everything is ok.
In the end it depends on what you consider to be the semantics of the method. If the method is supposed to accept nulls, then you should pick option number two. If the method is supposed to only accept real arguments (which I prefer), then you should pick option number one.
Always Throw, except in debugging/diagnostic code. It is most embarassing to have a NullPointerException that occurs in production code at a point where only a debugging message should be generated, e.g.
log.debug("id of object is " + obj.getId())
where the logger is turned off, and obj is null.
It is highly subjective, but I always prefer to just ignore non-fatal or recoverable errors. Put them in logs, if you must, but if you know how to continue - please do so.
Note, that when I say fatal, it actually depends on the function itself. Say, there's API function that gets ID and handful of other parameters. Suppose, that this ID also can be guessed from those other stuff that is passed in. API function should guess it if it can but the function somewhere inside that does all the work should get non-null ID and throw otherwise. Because for high level API function it is not fatal, it knows how to guess it, but for low level function it is fatal, it supposed to do something with that ID and with null value it can't continue.
All fatal errors should be noted, of course.
If you api if exposed outside, do always argument checking and throw a argument based exception so the api user can get the result.
Consider using the Null Object pattern is very useful to not clutter your code with try-catch, null checks (or god forbid swallowed errors).
In this particular example, giving nothing to a printer is like saying "print nothing", thus working as it should.
I do know this is an example, but it's just to clarify that this is relative.
If your code displays user-friendly messages on exceptions somehow, what difference does it make ? the first one would be both developer and user friendly.
It really depends on what your invariants are. If the parameter is optiona, then ignoring a null parameter is just fine, but if the parameter is required then that will hide a bug in your application. Also, and depending on the language, if the invariant is bad enough you may consider a third option: abort the application.
All discussions on whether to use or not exceptions can always be mapped to the decision on whether the situation is exceptional or not, and if it is exceptional, throwing or rather aborting the application depends on whether it is recoverable or not.
Id go for
void PrintType(object obj)
{
Console.WriteLine(obj.GetType().Name);
}
Third option, half in pseudocode:
// To Throw A Clean Error
void PrintType(object obj)
{
if(obj == null)
{
throw new ArgumentNullException(STANDARD_ERROR_MESSAGE, obj)
}
Console.WriteLine(obj.GetType().Name);
}
Either catch all errors and wrap them in a single place, so the user sees standard text:
There has been an error. If this error
persists, please contact an
administrator.
Or throw a select few errors, all of which are user-friendly, and display them directly to the user. "A connection error has occurred." "An authentication error has occurred." "A system error has occurred." And so on.
On the backend, have all errors and their stack trace logged, so you can use the debugging information that way.
It really depends on what the function is defined to do. The most important aspect is to have a clearly defined behavior and for the function to implement it correctly.
Now, if the question is whether is better to define the function to accept null and print it out, or to not accept it and throw an exception, I would say the latter, because it's probably less error prone for the user to check for null before calling the function, if that is a possibility.
This is a refactoring question.
try
{
string line = GetFirstLineFromFile(); //Gets first line from a text file, this line would be a number.
int value = ConvertToInteger(line); // Gets the integer value from the string.
int result = DivideByValue(value); // Divides some number with the value retrieved.
}
catch(Exception ex)
{
}
My main concern is, what is the best approach for exception handling in such situations. Certainly wrapping the whole thing in a single try catch is like saying I expect an exception about everything. There must be some place we catch a generic exception right?
Just don't catch a "generic exception".
How can you possibly handle ANY exception and know how to keep your application in a clean state ?
It hides bugs and it's a really bad idea.
Read this serie of posts on catch (Exception).
You need to think about what exceptions can be thrown from the methods in the try block, as well as which ones of those you can deal with at the current level of abstraction.
In your case, I'd expect that the getFirstLineFromFile methods, for example, can definitely throw exceptions you'd want to catch here. Now whether you wrap and rethrow the exception, or take other action, depends on whether you can actually deal with the exception at this level. Consider the case where you have a default file you can fall back to - the approach may just be to log a warning and continue with the default. Or if the whole application is based on reading a file supplied by the user, then this is more likely to be a fatal exception that should be propagated up to the top level and communicated to the user there.
There's no hard-and-fast rule like "always throw" or "never throw"; in general, I consider that one should throw exceptions whenever there's an exceptional-type situation that is not considered a normal result of the method, and consequently cannot be adequately described by the return type of the method. (For example, an isValidDbUser method returning boolean might be able to handle SQLExceptions as just return false; but a getNumProductsRegisteredInDB returning an int should almost certainly propagate an exception).
Don't listen to the (hordes) of people that will tell you that you should never catch multiple exceptions in one big general block. It's a perfectly reasonable way to do general error handling in some cases, which is why the ability to do so exists in the language.
There will be some exceptions that you can do something specific and useful about (i.e. recover from them in the catch block.) These are the kinds of exceptions that you want to catch individually, and as close to the place where they occur as possible.
But the majority of exceptions that you'll face in real life will be completely unexpected, unchecked exceptions. They are the result of programmer error (bugs), failed assertions, failing hardware, dropped network connections, etc.
You should design your software defensively, by designating specific "chokepoints" to handle these unpredictable exceptions with a minimum of disruption to the rest of the application. (Remember, in many cases, "handling" the exception often just means aborting the current operation and logging an error or otherwise telling the user that an unexpected error occurred.)
So for example, if your program saves a file to the disk, you could wrap the entire save operation in a try block to catch things that goes wrong during the save:
try {
// attempt to perform the save operation
doSave();
} catch (Throwable t) {
// tell the user that the save failed for unexpected reasons
// and log the error somewhere
informUser("save failed!");
log("save failed!", t);
} finally {
// last minute cleanup (happens whether save succeeded or failed)
...
}
Notice that we choose a nice chokepoint method here ( doSave() ) and then stop any unexpected errors from bubbling up any further than this point. The chokepoint represents a single, cancellable operation (a save). While that operation is obviously toast if you're getting an unexpected exception, the rest of the application will remain in a good state regardless of what happens on the other side of the chokepoint.
Also notice that this idiom does NOT stop you from handling some of your exceptions further down in doSave() somewhere. So if there are exceptions that might get thrown that you can recover from, or that you want to handle in a special way, go ahead an do so down in doSave(). But for everything else, you have your chokepoint.
You might even want to set up a general uncaught exception handler for your entire program in your main method:
public static void main(String [] args) {
try {
startApplication();
} catch (Throwable t) {
informUser("unexpected error! quitting application");
log("fatal application error", t);
}
But if you've set your other chokepoints up wisely, no exceptions will ever bubble up this far. If you want to make your general error handling complete, you can also create and assign an UncaughtExceptionHandler to important threads, including your main thread or the AWT thread if you are using Swing.
TL;DR; Don't believe the dogma that you should always catch exceptions as specifically as possible. There are times when you want to catch and handle a specific exception, and other times when you want to use chokepoints to catch and deal with "anything else that might go wrong".