I currently have a technical point of difference with an acquaintance. In a nutshell, it's the difference between these two basic styles of Java exception handling:
Option 1 (mine):
try {
...
} catch (OneKindOfException) {
...
} catch (AnotherKind) {
...
} catch (AThirdKind) {
...
}
Option 2 (his):
try {
...
} catch (AppException e) {
switch(e.getCode()) {
case Constants.ONE_KIND:
...
break;
case Constants.ANOTHER_KIND:
...
break;
case Constants.A_THIRD_KIND:
...
break;
default:
...
}
}
His argument -- after I used copious links about user input validation, exception handling, assertions and contracts, etc. to back up my point of view -- boiled down to this:
"It’s a good model. I've used it since me and a friend of mine came up with it in 1998, almost 10 years ago. Take another look and you'll see that the compromises we made to the academic arguments make a lot of sense."
Does anyone have a knock-down argument for why Option 1 is the way to go?
When you have a switch statement, you're less object oriented. There are also more opportunities for mistakes, forgetting a "break;" statement, forgetting to add a case for an Exception if you add a new Exception that is thrown.
I also find your way of doing it to be MUCH more readable, and it's the standard idiom that all developers will immediately understand.
For my taste, the amount of boiler plate to do your acquaintance's method, the amount of code that has nothing to do with actually handling the Exceptions, is unacceptable. The more boilerplate code there is around your actual program logic, the harder the code is to read and to maintain. And using an uncommon idiom makes code more difficult to understand.
But the deal breaker, as I said above, is that when you modify the called method so that it throws an additional Exception, you will automatically know you have to modify your code because it will fail to compile. However, if you use your acquaintance's method and you modify the called method to throw a new variety of AppException, your code will not know there is anything different about this new variety and your code may silently fail by going down an inappropriate error-handling leg. This is assuming that you actually remembered to put in a default so at least it's handled and not silently ignored.
the way option 2 is coded, any unexpected exception type will be swallowed! (this can be fixed by re-throwing in the default case, but that is arguably an ugly thing to do - much better/more efficient to not catch it in the first place)
option 2 is a manual recreation of what option 1 most likely does under the hood, i.e. it ignores the preferred syntax of the language to use older constructs best avoided for maintenance and readability reasons. In other words, option 2 is reinventing the wheel using uglier syntax than that provided by the language constructs.
clearly, both ways work; option 2 is merely obsoleted by the more modern syntax supported by option 1
I don't know if I have a knock down argument but initial thoughts are
Option 2 works until your trying to catch an Exception that doesn't implement getCode()
Option 2 encourages the developer to catch general exceptions, this is a problem because if you don't implement a case statement for a given subclass of AppException the compiler will not warn you. Ofcourse you could run into the same problem with option 1 but atleast option 1 does not activly encourage this.
With option 1, the caller has the option of selecting exactly which exception to catch, and to ignore all others. With option 2, the caller has to remember to re-throw any exceptions not explicitly caught.
Additionally, there's better self-documentation with option 1, as the method signature needs to specify exactly which exceptions are thrown, rather than a single over-riding exception.
If there's a need to have an all-encompassing AppException, the other exception types can always inherit from it.
The knock-down argument would be that it breaks encapsulation since I now I have to know something about the subclass of Exception's public interface in order to handle exceptions by it. A good example of this "mistake" in the JDK is java.sql.SQLException, exposing getErrorCode and getSQLState methods.
It looks to me like you're overusing exceptions in either case. As a general rule, I try to throw exceptions only when both of the following are true:
An unexpected condition has occurred that cannot be handled here.
Somebody will care about the stack trace.
How about a third way? You could use an enum for the type of error and simply return it as part of the method's type. For this, you would use, for example, Option<A> or Either<A, B>.
For example, you would have:
enum Error { ONE_ERROR, ANOTHER_ERROR, THIRD_ERROR };
and instead of
public Foo mightError(Bar b) throws OneException
you will have
public Either<Error, Foo> mightError(Bar b)
Throw/catch is a bit like goto/comefrom. Easy to abuse. See Go To Statement Considered Harmful. and Lazy Error Handling
I think it depends on the extent to which this is used. I certainly wouldn't have "one exception to rule them all" which is thrown by everything. On the other hand, if there is a whole class of situations which are almost certainly going to be handled the same way, but you may need to distinguish between them for (say) user feedback purposes, option 2 would make sense just for those exceptions. They should be very narrow in scope - so that wherever it makes sense for one "code" to be thrown, it should probably make sense for all the others to be thrown too.
The crucial test for me would be: "would it ever make sense to catch an AppException with one code, but want to let another code remain uncaught?" If so, they should be different types.
Each checked Exception is an, um, exception condition that must be handled for the program behavior to be defined. There's no need to go into contractual obligations and whatnot, it's a simple matter of meaningfulness. Say you ask a shopkeeper how much something costs and it turns out the item is not for sale. Now, if you insist you'll only accept non-negative numerical values for an answer, there is no correct answer that could ever be provided to you. This is the point with checked exceptions, you ask that some action be performed (perhaps producing a response), and if your request cannot be performed in a meaningful manner, you'll have to plan for that reasonably. This is the cost of writing robust code.
With Option 2 you are completely obscuring the meaning of the exception conditions in your code. You should not collapse different error conditions into a single generic AppException unless they will never need to be handled differently. The fact that you're branching on getCode() indicates otherwise, so use different Exceptions for different exceptions.
The only real merit I can see with Option 2 is for cleanly handling different exceptions with the same code block. This nice blog post talks about this problem with Java. Still, this is a style vs. correctness issue, and correctness wins.
I'd support option 2 if it was:
default:
throw e;
It's a bit uglier syntax, but the ability to execute the same code for multiple exceptions (ie cases in a row) is much better. The only thing that would bug me is producing a unique id when making an exception, and the system could definitely be improved.
Unnecessary have to know the code and declare constants for the exception which could have been abstract when using option 1.
The second option (as I guess) will change to traditional (as option 1) when there is only one specific exception to catch, so I see inconsistencey over there.
Use both.
The first for most of the exceptions in your code.
The second for those very "specific" exceptions you've create.
Don't struggle with little things like this.
BTW 1st is better.
Related
I'm refactoring some code and came across a large function with several input parameters. It checks whether the parameters are correct and throws exceptions if they're not:
public void fun(int param1, int param2) Throws Exception {
if(check_param(param1)) {
throw new Exception("param1 not okay");
}
// ... large chunk of code
}
I'd like to refactor the code, to move initial parameters checking into a separate function:
public void checkParams(int param1, int param2) Throws Exception {
if(check_param(param1)) {
throw new Exception("param1 not okay");
}
}
public void fun(int param1, int param2) Throws Exception {
checkParams(param1, param2);
// ... large chunk of code
}
Note: the function fun no longer throws an exception directly. I'd like to let the exception flow through fun but I'm not sure if this is considered good style or is recommended? Try&catch-ing the exception seems redundant. What's the right way to let "internal" exception flow through? (just ignore?)
(just ignore?)
That is exactly right, and it is the whole point of the semantics of exceptions: signaling error at one point and handling it at a separate, possibly very distant point, where the same type of error can be handled uniformly regardless of the exact location on the code path where it was detected.
Precondition checking is a well-known and frequent use case for exceptions which flow through the caller method. Typically you will want to define a custom exception type, such as ValidationException, and have only one place in your codebase where you catch and handle it.
(Judgemental)
A checkParam throwing an exception makes much sense. The error message has appearantly sufficient knowledge, and needs only to be formulated once. It is a kind of DRY (don't repeat yourself).
Even more important: error cases give rare control flow paths. Are hard to test, are seldom seen. Should steel little developer effort. So who checks that the exception (message) still makes sense. And having all those extra code and strings.
I even often iincline to unchecked exceptions like IllegalArgumentException, but IOException is a good second.
If you want to check for disparate exceptions as they bubble up the call stack then it's a neat idea to create exception classes like Param1NotOKException which extend the java.lang.Exception class.
Then you can add throws Param1NotOKException to the relevant functions. You then know exactly what is and isn't going to be thrown and the logic is checked at compile time.
Obviously this fine level of granularity could make things unwieldy so some half-way house between this idea and throwing and catching java.lang.Exception instances is probably what you ought to end up doing.
There is no coding standard that says that this is good style ... or bad style.
You need to think of this in terms of what matters:
Does it make the code easier to read?
Does it make the code easier to maintain?
Does it reduce code duplication ... significantly?
In the example you have given, I'd be inclined to say that it doesn't meet any of those criteria, and that this refactoring is probably a bad idea. However, it is clear that this example is not "real code".
Try & catching the exception seems redundant. What's the right way to let "internal" exception flow through? (just ignore?)
I don't know exactly what you are saying here. But in the context of your example, catching the exception inside fun would be just plain wrong. And catching it and ignoring it (anywhere) is even worse.
The whole point is that the exception needs to propagate to the caller (or beyond) and that it ultimately should be caught and properly dealt with. (What "properly dealt with" means will depend on what the exception was, whether it can be anticipated, and what if anything can be done to recover.)
Catching and ignoring an exception is almost always wrong. The only case where it is right is when you know exactly what it means, and have decided that it is safe and correct to ignore it.
Of course, declaring the "internal" class as throwing an exception is NOT ignoring it.
I hope that you are using Exception as just an example.
In fact, it is a very bad idea to throw Exception, RuntimeException or one of the other exception base classes. You should always throw a more specific exception, to allow the caller to discriminate expected exceptions from unexpected ones. If you throw Exception it is next to impossible to be distinguish an anticipated exception (e.g. the Exception that you throw) from an unanticipated one; e.g. a NullPointerException caused by some bug.
I also hope that you are NOT in the habit of declaring your "internal" methods as public.
I use assertions in Java in a standard way, having them turned on in my IDE. So they are not part of production release. Lately I have been seeing code examples with throw new AssertionError() and I started thinking about the situation where AssertionError should be used instead of assertion.
My guess is that main difference is the optionality of asserts so they don't slow down the production performance and so they can occur quite often in the code, but fixing hardly reproducible bugs reported from users is harder.
For AssertionError, the exact opposite applies.
I also find AssertionError more practical in places in code where the execution should not get, instead of using assert false //We should not be here. Especially if the return value is required. For example:
int getFoo(AnEnum a){
if (a == AnEnum.ONE)
return bar();
else if (a == AnEnum.TWO)
return SOME_VALUE;
//else
assert false; //throw new AssertionError();
return -1; //not necessary when usin AssertionError
}
Is my reasoning correct?
What are the other differences/use cases/best practices/limitations
of either approach?
In regards to providing a description in the AssertionError - Should it be provided or is the mere fact that it is an Error (and
of assertion type) enough to be more or less sure that stack trace
will be provided in case of found bugs?
In the technote "Programming With Assertions: Control Flow Invariants" the following code is given:
void foo() {
for (...) {
if (...)
return;
}
assert false; // Execution should never reach this point!
}
But the following note is given as well:
Note: Use this technique with discretion. If a statement is unreachable as defined in the Java Language Specification, you will get a compile time error if you try to assert that it is not reached. Again, an acceptable alternative is simply to throw an AssertionError.
You may not expect an AssertionError to be thrown when assertions are turned off. As AssertionError constructors are public, and since there is likely no substitution for AssertionError(String message, Throwable cause), I guess that you should expect them even if they are turned off.
Throwing an AssertionError on unreachable code (i.e. without any real expression to be evaluated) will never slow down the code, as Jon Skeet suggested, so it won't hurt with regards to performance.
So in the end throwing the AssertionError seems OK.
I would advise against throwing AssertionErrors directly. If you choose to rely on AssertionErrors for checking invariants, pre/post conditions, state conditions, etc. you're still better off using regular assertions with the "-ea" flag turned on in production as well.
The reason is that the assertions mechanism (other than being optimized at the compiler level) gives you a chance to turn on or off all assertions at once. Even if you can't think of a reason to do that now, if you come across a reason in the future, just consider that you'll have to go over all your throw new AssertionError(...) type code and surround it with a nasty if clause. You get the picture.
Just as you wouldn't want a magic number hard coded into many places in your code, and would probably use a constant instead, you shouldn't infect your code with many duplications (i.e. the throw new AssertionError(...) part).
Another word about assertions though. I believe that you should think twice before relying on assertion errors in production code. The reason is that an AssertionError is very generic. It has a message and a cause, but that's pretty much it.
Consider instead using specific RuntimeException subclasses that will convey more information both by being of a specific class more related to the problem, as well as by carrying actual data related to the problem.
As a simple example, consider a case you mentioned in your question where there's some part of the code that you don't expect to reach. An assertion or an AssertionError would convey the fact that you reached some unexpected code, but not much more. Using a specific RuntimeException could also deliver the state of the local variables and parameters of the method at that point in time. You could argue that this is doable with setting the message of the assertion or AssertionError to contain this information, but this does not work when using automatic error logging/handling mechanisms. Such mechanisms can handle unexpected behaviors using the visitor pattern on the different sub classes of RuntimeException you're using to check unexpected behavior (by handle I also mean fail-fast, not necessarily recovery).
Let say you have a method that checks if the argument (Answer) is correct and check if the question already have answers in the list that is also correct:
public void addAnswer(Answer answer) {
if (answer.isCorrect()) {
...
}
}
However, I only want one answer to be correct in the list. I have multiple options. I could throw an exception, I could ignore it, I could return some boolean value from the addAnswer that tells me if the operation was ok or not. How are you supposed to think in such scenarios?
The rule is pretty simple: Use exceptions on exceptional, erroneous, unpredicted failures. Don't use exceptions when you expect something to happen or when something happens really often.
In your case it's not an error or something truly rare that an answer is not correct. It's part of your business logic. You can throw an exception, but only as part of some validation (assertion) if you expect an answer at given point to always be correct and suddenly it's not (precondition failure).
And of course if some failure occurs while checking correctness (database connection lost, wrong array index) exception are desired.
This entirely depends on what you want to achieve. Should the caller of your method already have made sure that it doesn't add two correct answers? Is it a sign of a programming error if that happens? Then throw an exception, but definitely an unchecked exception.
If your method's purpose is to relieve the caller from enforcing the one-true-answer invariant (I doubt that, though), then you can just arrange to signal via a boolean return value, which makes it only an optional information channel for the caller.
If there is no way to know in advance whether there are other correct answers—for example, the answers are added concurrently from several threads or even processes (via a database)—then it would be meaningful to throw a checked exception.
Bottom line: there is no one-size-fits-all best practice, but there is a best practice for every scenario you want to accomplish.
The exception police will be down on you like a ton of bricks, and me for this answer, with statements like "don't use exceptions for flow control" and "don't use exceptions for normal conditions".
The trouble with the first statement is that exceptions are a form of flow control. This makes the argument self-contradictory, and therefore invalid.
The trouble with the second statement is that it seems to inevitably go along with endlessly redefining exceptional conditions as normal. You will find examples in this very site: for example, a lively discussion where the police insisted that EOF was 'normal' and therefore that EOFException shouldn't be caught, despite the existence of dozens of Java APIs that don't give you any choice in the matter. Travel far enough down this path and you can end up with nothing that is exceptional whatsoever, and therefore no occasion to use them at all.
These are not logical arguments. These are unexamined dogmas.
The original and real point, back in about 1989 when it was first formulated, was that you shouldn't throw exceptions to yourself, to be handled in the same method: in other words, don't treat it as a GOTO. This principle continues to have validity.
The point about checked exceptions is that you force the caller to do something about handling them. If you believe, on your own analysis, that this is what you want, use an exception. Or, if you are using an API that forces you to catch them, catch them, at the appropriate level (whatever that is: left as an exercise for the reader).
In other words, like most things in the real world, it is up to your discretion and judgment. The feature is there to be used, or abused, like anything else.
#Exception police: you will find me in the telephone book. But be prepared for an argument.
An exception thrown from a method enforces the callers to take some action in the anticipation of the exception occurring for some inputs. A return value doesn't enforce the same and so it is up to the caller to capture it and take some action.
If you want the callers to handle the scenario to take some corrective action, then you should throw a checked exception (sub class of java.lang.Exception).
The problem here is that your API is error prone. I'd use the following scheme instead:
public class Question {
private List<Answer> answers;
private int mCorrect;
// you may want a List implementation without duplicates
public void setAnswers(List<Answer> answers, int correct) {
this.answers = answers;
// check if int is between bounds
mCorrect = correct;
}
public boolean isCorrect(Answer answer) {
return answers.indexOf(answer) == mCorrect;
}
}
because an Answer by itself is simply a statement, and usually cannot be true of false without being associated to a Question. This API makes it impossible to have zero or more than one correct answers, and forces the user to supply the correct one when he adds answers, so your program is always in a consistent state and simply can't fail.
Before deciding how to signal errors, it's always better to design the API so that errors are less common as possible. With your current implementation, you have to make checks on your side, and the client programmer must check on his side as well. With the suggested design no check is needed, and you'll have correct, concise and fluent code on both sides.
Regarding when to use a boolean and when to use Exceptions, I often see boolean used to mirror the underlying API (mostly low level C-code).
I agree with Tomasz Nurkiewicz's response. I cant comment on it because I'm a new user. I would also recommend that if the addAnswer() method is not always going to add the answer (because they already exists a correct one), name it to suggest this behaviour. "add" is suggest normal collections behaviour.
public boolean submitAnswer(Answer answer); // returns true is answer accepted
Your exact solution may depend on the bigger picture about your application that we dont know about. Maybe you do want to throw an Exception but also make it the responsibility of the caller to check if adding the Answer is valid.
It's all a rich tapestry.
I would implement it in this way:
public class Question {
private int questionId;
private final Set<Answer> options = new HashSet<Answer>();
private final Set<Answer> correctAnswers = new HashSet<Answer>();
public boolean addAnswer(Answer answer) throws WrongAnswerForThisQuestionException {
if(!answer.isValid(questionId)) {
throw new WrongAnswerForThisQuestionException(answer, this);
}
if (answer.isCorrect(questionId)) {
correctAnswers.add(answer);
}
return options.add(answer);
}
}
Will declaring the function in this way have any implications on the performance?
public init(){
try{
initApplication();
}catch(A1Exception){
}catch(A2Exception){
...
}catch(A5Exception){
}
}
private void initApplication() throws A1Exception, A2Exception, A3Exception, A4Exception, A5Exception {
initApp1(); //throws A1, A2, A3
initApp2(); //throws A4, A5
}
Are there any issues with implementing initApplication() in this way?
In recent years there's been a feeling that checked exceptions are fairly harmful. Each of these exceptions, if they are checked, forces the calling methods to have to handle them or declare them. This breaks encapsulation, because now something of the lower level implementation details leaks up into the higher levels.
Joshus Bloch talks about this in Effective Java, which I highly recommend.
There is no limitation as to how many exceptions can be thrown by a method.
The more exception you throw, the more you can be specific about any exceptions being caught.
Just I would like to point out a few suggestions which I follow.
1) Atleast have a generic exception at the last so if any other exception which may occur in your code is caught than being thrown to the calling class.
2) You can have category of Exception Classes like BusinessLogic Exception, InvalidDataException, SystemsException so you may have actually less no of exceptions being thrown from any method. (Unless your business demand exact exception
3) Always have error codes than throwing actual text messages which will make your application language independant.
I don't see a problem throwing whatever Exception your code requires. My first impression when looking at the example is that Exceptions might be used here to control the flow of your application. Be careful not to do that. Exceptions should only be triggered in exceptional cases.
One reason why process flow should not be handled via Exceptions is that raising Exceptions is an expensive process. Though the structure of multiple catch blocks shouldnt result in a performance hit, the (potential) underlying process that uses Exceptions to control flow would not perform well.
With that in mind, is there a 'smell'? Only if the above concern is true in the design of the code.
Q1. Will this have performance impact?
No, not if they are 'genuine' exceptions (i.e. not being used for normal program control flow)
Q2. Do you see smell in initApplication()?
No, not if initApplication() can be expected to raise N exceptions, i.e. if there are N - exceptional circumstances that could prevent initApplication() from completing it's work.
1: The performance impact will be minimal...
2: But it's not necessarily a good idea, as having excessive boiler plate code makes it hard to read. If every exception is going to be handled the same way, then you should either do a catch of the base class Exception. Or you can have initApplication() throw a custom exception -- something like ApplicationInitializationException, which conveys a little more meaning about what went wrong. You can set the message for the exception to be the exact details.
There are some cases where you might get 5 different exceptions, and might have to deal with all of them differently. In that case, catching all 5 would be the proper thing to do. But it's worth thinking about if that's really necessary before you implement it.
If there is no exception there is no performance impact, if an exception is thrown, there is some overhead finding the matching catch which will grow as you add more exceptions, but it should not matter, because exceptions should be er.. exceptional. The should not happen under ordinary circumstances.
In other words if you do not use throwing exceptions to control the flow of your program yuo should be ok, and if you do this is certainly a smell no matter how many catch clauses you have
On a purely technical note, the class file format introduces an upper limit of 65536 exceptions. The u2 type of exceptions_table_length is shorthand for an unsigned two byte quantity.
The Code attribute has the following format:
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
I only bring this up in case you are generating code. JSP developers often have to worry about problems with generated methods exceeding 64KB code size. This and other limitations are listed in Section 4.10 Limitations of the Java Virtual Machine.
I guess this answer is mostly related to the Q2 but view of it that is not so technical but might be worth considering anyway are the one behind the following two questions?
Does it make sense for the user to catch all of them?
Do you want to risk the user getting fed up with having lots of catch blocks and instead just insert a single "catch(Exception ex) {// ex.printStackTrace(); // enable this if we see problems}" or something similar and stupid.?
In this case I guess it might not be relevant but I think it is worth considering when doing API design in general.
Do not throw any exceptions unless you are going to take an action if an exception is caught. Convert your checked exceptions to runtime exceptions for logging purposes.
More info on the topic can be found here
Are there any hard and fast rules regarding returning boolean in a method signature to indicate a successful operation as opposed to declaring void? I find that for more critical operations in my calling method I want to know if an operation completed so I can log any issues. Is this an "inappropriate" use of boolean?
Usually I use Exceptions to signal when something went wrong.
Instead of returning false, you can throw an Exception with a detailed message about what the problem was.
Returning false doesn't give you much information about the problem.
Then, instead of checking for a false return value, just put the method call in try/catch if you expect that the method could easily fail.
Many people will complain that this method is slower. But, the benefits you gain greatly outweigh the slowdown. Besides, if you are using Java speed shouldn't be your #1 concern.
I generally find that throwing an exception in the case of a failure is a far better solution than returning a boolean, because generally do not care if the process has succeeded - I only care if it's failed. By using an exception I can provide any amount of information about why the process actually failed.
If exceptions seem distasteful, you can return a custom Status object which contains a boolean and a status message (something like "Added 6 new Foobars!" or "Could not add Foobars because the Foobin is full!"), although that is of course more complex.
Only do this in scenarios where it's clear that something has a boolean outcome. Like IsValidCustomer() or some such.
For all other things where you think you could introduce it, it probably means you're dealing with some kind of Exception, and you really don't want to wrap that with a simple boolean true/false, because you can have a variety of flavours (different exceptions) and reasons why something goes wrong, which you would want to know about.
So either let the exception bubble up the stack, or catch it and turn it into a custom exception or log it or whatever.
Use boolean values to indicate non-exceptional failure outcomes. An example would be a search function. The nominal failure would be not-found. Communicating that outcome with exceptions is unwieldy. Save exceptions for exceptional cases; the difference between not-found and cannot-search.
This is an ok paradigm, but if you want to force the caller to handle the case wehre the operation doesn't complete successfully, you might want to throw a checked exception instead.
This pattern does occur in the core Java libraries, though. See File.delete() as an example.
For returning success generally what you see is:
Return a boolean
Return void, but throw exception on error
Return a status code (less common in java).
Can't see anything wrong with returning a boolean for success, unless you'd need information on exception behavior.
If there is an unexpected result, throw an exception.
If you just want the function to tell you "did I do X" then return a boolean.
In practice, I find that throwing an Exception is the best thing to do when failure means that we need to abort the process. Like, if you're trying to process an order -- bill the customer, arrange shipping, pay sales taxes, etc -- if you can't find the order record, there's probably little point in doing all the other work. You just want to get out of there. Exceptions let you do this easily. Just catch at the bottom of the block, display or log the error, and get out.
On the other hand, if an "error" means that my program takes a different flow path, returning a boolean makes more sense. Like, if I'm looking for a specific customer and if he exists I update his record and if he doesn't I create a new customer record, then it makes a lot of sense to return a boolean, and in the caller test it and when true follow one path and when false the other.
Really this is two very different meanings of the word "error", and they call for different handling. It is quite possible that the same function could do both. Like, on found return true, on not found return false, on I/O error trying to read throw an exception.
It seem ok, but the devil lies into the details. ;-)
Throwing an exception is the main alternative, with pros and cons.
I think you could get more insight by providing precise coding samples...