What is a good "Error Checking" Pattern (Java)? - java

I'll explain what I mean by input error checking.
Say you have a function doSomething(x).
If the function completes successfully doSomething does something and returns nothing. However, if there are errors I'd like to be notified. That is what I mean by error checking.
I'm looking for, in general, the best way to check for errors. I've thought of the following solutions, each with a potential problem.
Flag error checking. If doSomething(x) completes successfully return null. Otherwise, it returns a boolean or an error string. Problem: Side effects.
Throwing an exception. Throw an exception if doSomething(x) encounters an error. Problem: If you are performing error checking for parameters only, throwing an IllegalArgumentExceptionseems inappropriate.
Validating input prior to function call. If the error checking is only meant for the parameters of the function, then you can call a validator function before calling the doSomething(x) function. Problem: What if a client of the class forgets to call the validator function before calling doSomething(x)?
I often encounter this problem and any help or a point in the right direction would be much appreciated.

Throw an exception is the best way.
If you are performing error checking for parameters only, throwing an
IllegalArgumentException seems inappropriate.
Why? That's the purpose of this Exception.

Flag error checking
This is appropriate in some cases, depending on what you mean by an "error".
An example from the API: If you try to add an object to a Set, which already contains another object which equals the new object, the add method sort of "fails" and indicates this by returning false. (Note that we're on a level at which it's technically not even an "error"!)
2.Throwing an exception
This is the default option.
Question is now, should you go for a checked exception (which you need a throws declaration or try/catch clauses) or an unchecked exception (an exception that extends RuntimeException). There are a few rules of thumbs here.
From Java Practices -> Checked versus unchecked exceptions:
Unchecked exceptions: Represent defects in the program (bugs) - often invalid arguments passed to a non-private method.
Checked exceptions: Represent invalid conditions in areas outside the immediate control of the program (invalid user input, database problems, network outages, absent files)
Note that IllegalArgumentException is an unchecked exception, perfectly suitable for throwing when arguments are not as they should be.
If you want to throw a checked exception, you could A) roll your own by extending Exception, B) use some existing checked exception or C) "chain" a runtime exception in, for instance, an IOException: throw new IOException(new IllegalArgumentException("reason goes here..."));
3.Validating input prior to function call
Relying on the fact that the client should have sanitized / checked his arguments before the call seems like a bad idea to me.

Your second suggestion ("Throwing an exception") is the best choice. The other two options rely on the invoker either doing something before ("Validating input prior to function call") or after ("Flag error checking") the call to the method. Either way, the extra task is not mandated by the compiler so someone invoking the function isn't forced to call the "extra thing" so problems are not spotted till run-time.
As for "Throwing an Exception" and your suggested 'problem', well the answer is throw appropriate exception types for the code. If the input parameters are invalid, then throw an InvalidArgumentException (since that's the appropriate error). If the exception is for functionality (e.g. cannot open network connection), use another exception type or create your own.

I agree with throwing exceptions. I want to add another option that combines #2 and #3 - the proxy pattern. That way your code stays fairly cohesive - validation in one place and business logic in another. This makes sense if you have a large set of calls that need to be validated.
Create a proxy to handle validation. Have it delegate all calls to the actual implementation of your business logic interface after it validates, otherwise it can throw exceptions if something does not validate.

I decide which method to use usually on the type of interface.
User interface (GUI): I validate before calling business methods, because the user wants to know what was wrong.
On technical interfaces between components or systems, the interface should have been tested and work properly in this case I throw exceptions.

Exceptions is the way to go. Your stated problem with exceptions can be mitigated by the proper implementation of exception throwing / handling. Use exceptions to your advantage by validating parameters at the lowest level that you need them and throwing an exception if the validation fails. This allows you to avoid redundantly checking for validity at multiple levels in the call stack. Throw the exception at the bottom and let the stack unroll to the appropriate place for handling the error.

The method you choose depends on the situation, and they are not mutually exclusive so you can mix them all in the same solution (although whether that's a good idea really depends on your situation).
Choose this method if you want a very simple method for handling errors. This method might be OK for situations where the calling function can accept any value the called function returns. There might be situations where business logic dictates this as an OK choice, such as returning a specific message string when a resource cannot be properly located, or a server does not respond. Generally, I don't use this or see this technique in Java very much, as exceptions are a better mechanism for error handling.
Throw an exception when your function runs into un defined behaviour. If you have a math function that can only operate on positive integers and someone passes -1, you should thrown an InvalidArguementException. If your function is given the ID of a product in a database, but the product cannot be found by a query, you could throw a custom ProductNotFound exception.
Validating input is a good idea, I would say it should be done by the called function, rather than the caller - unless the caller can avoid an exception from the callee by validating the input before passing it. If you work in a language that supports Design By Contract, validating input would be done as the function's precondition.
I usually use #2 and #3. I haven't written code with error flags for a while. The exception to that might be a function that returned an enum, where one possible value indicated an error code. That was driven more by a business rule than anything else.
And generally, try to keep it simple.

Throw a custom checked exception.
doSomething(WithX x ) throws BusinessRuleViolatedException

Input validation is surprisingly complicated and all three of the suggested approaches in the original post are needed and sometimes more. Exceptions are appropriate when input is outside the bounds of business logic, if it is corrupt or cannot be read for example.
Flag checking quickly becomes an anti-pattern if you have more than one or two flags to check, and can be replaced with a slightly specialized version of the visitor pattern. I do not know the exact name of this specific pattern, but I'll informally call it the "validator list pattern" and will describe it in more detail below.
Checking input early and failing fast is usually good, but not always possible. Often there is a lot of input validation, all input received from outside of your control should be treated as hostile and requires validation. Good program design and architecture will help make it clear when exactly this needs to happen.
'The Validator List Pattern'
As an example, let's first describe in code the "Validation Flag" anti-pattern, and then we'll transform it to the "validation list" pattern.
public Optional<String> checkForErrorsUsingFlags(
ObjectToCheck objToCheck ) {
// the small series of checks and if statements represent the
// anti-pattern. Hard to test and many other problems crop up.
String errMsg = checkForError1( objToCheck );
if(errMsg != null ) {
return Optional.of(errMsg);
}
errMsg = checkForError2( objToCheck );
if(errMsg != null ) {
return Optional.of(errMsg);
}
return Optional.empty();
}
/**** client usage ****/
ObjectToCheck obj = doSomethingToReadInput(obj);
Optional<String> error = checkForErrors( obj);
if (error.isPresent()) {
// invalid input, throw object away and request input again
} else {
// do stuff, we have a valid input
}
To fix, start by creating a common interface that will represent a single validator. Then each check is converted to a validator instance. Finally we create a list of validators and pass it to the validator code.
/** The common validator interface each validator will use */
private interface MyValidator {
public boolean isValid(ObjectToCheck obj);
public String getErrorMessage(ObjectToCheck obj);
}
// this method should look familiar to the above, now we
// have a list of validators as an additional parameter
public Optional<String> checkForErrors( ObjectToCheck objToCheck,
List<MyValidator> validators ) {
for(MyValidator validator : validators ) {
if (!validator.isValid(objToCheck)) {
String errMsg = validator.getErrorMessage(objToCheck);
return Optional.of(errMsg);
}
}
return Optional.empty();
}
/****** client usage *****/
// now in this pattern, the client controls when the validators
// are created, and which ones are used.
MyValidator validator1 = new MyValidator() {
#Override
public boolean isValid(ObjectToCheck obj) {
return checkForError1( objToCheck ) != null;
}
#Override
public boolean getErrorMessage(ObjectToCheck obj) {
return checkForError1( objToCheck );
}
}
// note: above we call checkForError1 twice, not optimal.
// typical in real examples this can be avoided,
// and the error message generation logic split from the detection
// logic often simplifies things.
MyValidator validator2 = new MyValidator() { ... }
List<MyValidator> validators =
ImmutableList.of( validator1, validator2);
Optional<String> error = checkForErrors(objToCheck, validators);
if (error.isPresent()) {
// invalid input, throw object away and request input again
} else {
// do stuff, we have a valid input
}
Now to test, create a series of mock validators and check that each one has their validate called. You can stub validator results and ensure the correct behavior is taken. Then you also have access to each validator individually so you can test them one by one on their own.
Cheers - hope that helps, happy coding.

Related

Is a method that returns a Try allowed to throw?

We're using Vavr in our project to ease exception handling. I always make sure that a method that returns a Try can never throw anything, like so:
public Try<Result> someSafeMethod() {
return Try.of(() -> someService.generateId())
.map(someOtherService::getValueForId)
.map(mappingService::mapToResult);
}
but some of my colleagues would implement it like this:
public Try<Result> someSafeMethod() {
String generatedId = someService.generateId(); // <- Might throw an Exception that is not caught by the Try clause
return Try.of(() -> someOtherService.getValueForId(generatedId))
.map(mappingService::mapToResult);
}
Arguing that if something is wrong with the generation of the ID that they would rather the exception is thrown instead of the returned Try being a failure.
The documentation does not prohibit that a method returning a Try should not throw, but it does state that:
Try is a monadic container type which represents a computation that may either result in an exception, or return a successfully computed value.
Am I being too too strict? Imagine you would use an API where all methods return a Try, wouldn't it be bad when they still throw?
You are not being too strict.
The whole point of using Try as a return value is the resulting benefit of programming with total functions and having a composable way of handling errors. Total functions are functions that always return a value of the declared return type for all possible argument values. If they are throwing exceptions, their functions are not total functions anymore, and—without explicit error handling—non-totality will propagate transitively through their code, 'infecting' all other functions that call them with non-totality. As a result, they will end up with code that will be much harder to reason about and it will take more effort to make sure it is correct.
Throwing exceptions while using Try would also defy the purpose of using Try in the first place and it would unnecessarily complicate the code consuming their API for no obvious benefit, because the API consumers will have to do error handling both using Try and catching exceptions.

Why not have Jave methods return a tuple instead of an object reference (or null)?

Typically Java methods look like:
public <U,V> U doSomething(V aReference) {
// Do something
}
This typically means that the method doSomething() returns a null if it
fails (for whatever reason) or a valid object reference. In some cases the
"valid object reference" may itself be null. For example, the method
aMap.get(k) may return null if there is no key k or if there is a key
k but its corresponding value is null. Confusion!
Not to mention NullPointerExceptions if 50% of your LOC isn't just
null-checking.
What's wrong with methods looking like this:
public <T> ReturnTuple<T> doSomething(V aReference) {
T anotherObjRef = getValidObjT();
if (successful) {
return ReturnTuple.getSuccessTuple(anotherObjRef);
} else {
return ReturnTuple.getFailureTuple("aReference can't be null");
}
}
where the class ReturnTuple<T> is defined something like:
class ReturnTuple<T> {
private boolean success;
// Read only if success == true
private T returnValue;
// Read only if success == false
private String failureReason;
// Private constructors, getters, setters & other convenience methods
public static <T> ReturnTuple<T> getSuccessTuple(T retVal) {
// This code is trivial
}
public static <T> ReturnTuple<T> getFailureTuple(String failureReason) {
// This code is trivial
}
}
Then the calling code will look like:
ReturnTuple<T> rt = doSomething(v);
if (rt.isSuccess()) {
// yay!
} else {
// boo hoo!
}
So, my question is: why isn't this pattern more common? What is wrong with it?
Keep in mind I am not asking for a critique of this exact code, but for a
critique of this general idea.
Please note: the point here is not to get the code above to compile, just to
discuss an idea. So please don't be too pedantic about code correctness :-).
Edit 1: Motivation
I guess I should have added this section from the beginning, but better late
than never...
Ever wished a method could return two values at once? Or that the returning
of a value could be de-linked from the ability to indicate success or
failure?
This could also promote the idea of a method being a neat-and-clean
self-contained unit (low coupling and high cohesion): handle all (or most)
exceptions generated during it's execution (not talking about exceptions
like IllegalArgumentException), discreetly log failure reasons (rather
than the ugly stack trace of an uncaught exception) and only bother the
caller with exactly the information required. IMHO this also promotes
information-hiding and encapsulation.
Done your best with testing, but when the code is deployed to the customer,
an uncaught exception's ugly stack trace makes it all look so
unprofessional.
Similar to the point above: you may have code that could possibly generate
20 different exceptions but you're catching only 5-7 of those. As we all
know, customers do the damndest things: rely on them to cause all the other
uncaught 13-15 exceptions :-). You end up looking bad when they see a big
stack trace (instead of a discrete failure reason added to the logs).
This is the difference (for example) between showing a stack trace to a
user in a web app vs. showing them a nicely formatted 5xx error page saying
something like: "There was an error and your request couldn't be completed.
Admins have been notified and will fix as soon as possible." etc.
This idea isn't entirely without merit as Java 8 provides the
Optional
class (as pointed out by #JBNizet) and Google's
Guava library also has an
Optional
class. This just takes that a little further.
This typically means that the method doSomething() returns a null if it fails
No, it does not mean that. It means that the method doSomething() may sometimes legally return null, without a failure. Java provides a powerful system for handling failures - namely, exception handling. This is how the API should indicate failures.
why isn't this [return a tuple] pattern more common? What is wrong with it?
The primary thing that is wrong with this pattern is that it is using a mechanism of reporting failures in a way that is foreign to Java. If your API runs into a failure, throw an exception. This saves you from creating twice as many objects as needed in "mainstream" cases, and keeps your APIs intuitively understandable to people who learned the Java class library well.
There are situations when returning a null can be interpreted both ways - as a failure, and as a legitimate return value. Looking up objects in associative containers provide a good example: when you supply a key that is not in the map, one could claim that that is a programming error and throw an exception (.NET class library does that) or claim that when the key is missing, the corresponding spot in the map contains the default value, i.e. a null - the way this is done in Java. In situations like that it is entirely acceptable to return a tuple. Java's Map decided against this, most likely to save on creating additional objects every time an object is requested from a Map.

Return value: boolean vs int flag vs exception

I need to define a set of functions as part of an interface for a public facing SDK and trying to figure out the best way of signalling to the caller code if something was successful or not, and if not, why not.
My first consideration was return value vs exception. I think I need to use a combination of both for this one. Exceptions for erroneous states/errors caused by bugs. Return value to be used for times when function ran as expected and just want to return the result of the call to the caller.
Now, for return type. I could use ints (flags) or booleans. It has been argued internally that booleans should be used as it is simpler, and no need for flags. Booleans limit you to specifying success or failure, with no explanation.
I would make two arguments for using flags instead. First, you can return more than two possible values. Allowing for { success, fail, fail_reason_1, fail_reason_2, fail_reason_3 }. Note as this is an interface for implementations on various hardware devices it is probably desirable to be able to notify why an operation failed. e.g. the connected device doesn't support beep, has no LCD, doesn't support embedded crypto etc.
Who knows what the requirements will be in the future. Returning a bool locks you in now, whereas using flags allows you greater flexibility in the future. So what if you never need more than two values in the future. At least you have the option.
Considering this will be a public facing SDK I want as much flexibility so as to prevent breaking changes in the future.
Thanks
In my opinion the difference between returning a value to indicate the result of a method call and to throw an exception is that a value is just a notification about what happened. The method call should be considered as being performed successfully regarding the contract it defines. For example have a look how boolean : Set.add() is defined.
If a method throws an exception, this should indicate either an incorrect use of the method or a call while the object / whole system was in an illegal state. For example, trying to buy something for an user while his account does not have enough credits.
An exception is perfectly suited for capturing the different failure types: either by an exception hierarchy or by adding properties to the exception like getFailureCode() or combining them.
I would not use flags to indicate a failure condition in case the failure must be handled. Because ignoring return values is much to easy and can be missed by programmers, while exception have to be ignored actively.
The short answer is that it varies a lot based on your domain, clients, and the specifics of what you're providing. If you haven't already, you need to sit down with your clients and figure out how they're going to be using the library. Just off the top of my head, here are some things I'd be thinking about:
First, all the failure types you identified are basically the same thing - UnsupportedOperationException, with a reason why. Are there other failure types? If not, and you use exceptions, you possibly want one exception class with a type/cause/whatever as an enum property.
Second, it looks like many/most/all of your methods are going to have one or more failure types like this. Is that true? If so, does your API provide any way of determining what features a device supports? Consider this:
// Best if I probably don't care about the result if it's not SUCCESS
final Result result = myApiObject.someMethod();
if (result == Result.BEEP_UNSUPPORTED) {
....
} else if (result == Result.NO_DISPLAY) {
....
} else if ...
and this:
// Best if I have to handle every possible failure condition, and I care what
// the failure type is
try {
myApiObject.someMethod();
} catch (final BeepUnsupportedException e) {
....
} catch (final NoDisplayException e) {
....
}
and this:
// Best if I have to consider every possible failure condition, but it probably
// doesn't matter what the failure type is
try {
myApiObject.someMethod();
} catch (final MyApiException e) {
if (Cause.BEEP_UNSUPPORTED == e.getCause()) {
....
} else ....
and this:
// Best if I know in advance what features I may need
// someMethod() may still return response codes or throw an exception. In this case
// it's possibly OK to make it a RuntimeException, since clients are expected to
// poll for features.
if (myApiObject.supports(Feature.BEEP)
&& myApiObject.supports(Feature.DISPLAY)) {
myApiObject.someMethod();
} else ...
Which of these is closest to the way your clients will want to use your system?
Third, how fatal are these errors? I totally agree with #Harmlezz that failures which must be handled need to be Exceptions. What neither of us can tell you without more information is whether your failures need to be handled or not. If clients will mostly be ignoring failures (they usually want the code to fail silently), or only mostly only care about SUCCESS or !SUCCESS, then return codes are probably okay. If failures need to be handled, then you should be throwing a checked exception. You probably want to stay away from unchecked exceptions, since these failures aren't programming errors and may be handled correctly by clients.

When should an IllegalArgumentException be thrown?

I'm worried that this is a runtime exception so it should probably be used sparingly.
Standard use case:
void setPercentage(int pct) {
if( pct < 0 || pct > 100) {
throw new IllegalArgumentException("bad percent");
}
}
But that seems like it would force the following design:
public void computeScore() throws MyPackageException {
try {
setPercentage(userInputPercent);
}
catch(IllegalArgumentException exc){
throw new MyPackageException(exc);
}
}
To get it back to being a checked exception.
Okay, but let's go with that. If you give bad input, you get a runtime error. So firstly that's actually a fairly difficult policy to implement uniformly, because you could have to do the very opposite conversion:
public void scanEmail(String emailStr, InputStream mime) {
try {
EmailAddress parsedAddress = EmailUtil.parse(emailStr);
}
catch(ParseException exc){
throw new IllegalArgumentException("bad email", exc);
}
}
And worse - while checking 0 <= pct && pct <= 100 the client code could be expected to do statically, this is not so for more advanced data such as an email address, or worse, something that has to be checked against a database, therefore in general client code cannot pre-validate.
So basically what I'm saying is I don't see a meaningful consistent policy for the use of IllegalArgumentException. It seems it should not be used and we should stick to our own checked exceptions. What is a good use case to throw this?
The API doc for IllegalArgumentException:
Thrown to indicate that a method has been passed an illegal or inappropriate argument.
From looking at how it is used in the JDK libraries, I would say:
It seems like a defensive measure to complain about obviously bad input before the input can get into the works and cause something to fail halfway through with a nonsensical error message.
It's used for cases where it would be too annoying to throw a checked exception (although it makes an appearance in the java.lang.reflect code, where concern about ridiculous levels of checked-exception-throwing is not otherwise apparent).
I would use IllegalArgumentException to do last ditch defensive argument checking for common utilities (trying to stay consistent with the JDK usage). Or where the expectation is that a bad argument is a programmer error, similar to an NullPointerException. I wouldn't use it to implement validation in business code. I certainly wouldn't use it for the email example.
When talking about "bad input", you should consider where the input is coming from.
Is the input entered by a user or another external system you don't control, you should expect the input to be invalid, and always validate it. It's perfectly ok to throw a checked exception in this case. Your application should 'recover' from this exception by providing an error message to the user.
If the input originates from your own system, e.g. your database, or some other parts of your application, you should be able to rely on it to be valid (it should have been validated before it got there). In this case it's perfectly ok to throw an unchecked exception like an IllegalArgumentException, which should not be caught (in general you should never catch unchecked exceptions). It is a programmer's error that the invalid value got there in the first place ;) You need to fix it.
Throwing runtime exceptions "sparingly" isn't really a good policy -- Effective Java recommends that you use checked exceptions when the caller can reasonably be expected to recover. (Programmer error is a specific example: if a particular case indicates programmer error, then you should throw an unchecked exception; you want the programmer to have a stack trace of where the logic problem occurred, not to try to handle it yourself.)
If there's no hope of recovery, then feel free to use unchecked exceptions; there's no point in catching them, so that's perfectly fine.
It's not 100% clear from your example which case this example is in your code, though.
Treat IllegalArgumentException as a preconditions check, and consider the design principle: A public method should both know and publicly document its own preconditions.
I would agree this example is correct:
void setPercentage(int pct) {
if( pct < 0 || pct > 100) {
throw new IllegalArgumentException("bad percent");
}
}
If EmailUtil is opaque, meaning there's some reason the preconditions cannot be described to the end-user, then a checked exception is correct. The second version, corrected for this design:
import com.someoneelse.EmailUtil;
public void scanEmail(String emailStr, InputStream mime) throws ParseException {
EmailAddress parsedAddress = EmailUtil.parseAddress(emailStr);
}
If EmailUtil is transparent, for instance maybe it's a private method owned by the class under question, IllegalArgumentException is correct if and only if its preconditions can be described in the function documentation. This is a correct version as well:
/** #param String email An email with an address in the form abc#xyz.com
* with no nested comments, periods or other nonsense.
*/
public String scanEmail(String email)
if (!addressIsProperlyFormatted(email)) {
throw new IllegalArgumentException("invalid address");
}
return parseEmail(emailAddr);
}
private String parseEmail(String emailS) {
// Assumes email is valid
boolean parsesJustFine = true;
// Parse logic
if (!parsesJustFine) {
// As a private method it is an internal error if address is improperly
// formatted. This is an internal error to the class implementation.
throw new AssertError("Internal error");
}
}
This design could go either way.
If preconditions are expensive to describe, or if the class is intended to be used by clients who don't know whether their emails are valid, then use ParseException. The top level method here is named scanEmail which hints the end user intends to send unstudied email through so this is likely correct.
If preconditions can be described in function documentation, and the class does not intent for invalid input and therefore programmer error is indicated, use IllegalArgumentException. Although not "checked" the "check" moves to the Javadoc documenting the function, which the client is expected to adhere to. IllegalArgumentException where the client can't tell their argument is illegal beforehand is wrong.
A note on IllegalStateException: This means "this object's internal state (private instance variables) is not able to perform this action." The end user cannot see private state so loosely speaking it takes precedence over IllegalArgumentException in the case where the client call has no way to know the object's state is inconsistent. I don't have a good explanation when it's preferred over checked exceptions, although things like initializing twice, or losing a database connection that isn't recovered, are examples.
As specified in oracle official tutorial , it states that:
If a client can reasonably be expected to recover from an exception,
make it a checked exception. If a client cannot do anything to recover
from the exception, make it an unchecked exception.
If I have an Application interacting with database using JDBC , And I have a method that takes the argument as the int item and double price. The price for corresponding item is read from database table. I simply multiply the total number of item purchased with the price value and return the result. Although I am always sure at my end(Application end) that price field value in the table could never be negative .But what if the price value comes out negative? It shows that there is a serious issue with the database side. Perhaps wrong price entry by the operator. This is the kind of issue that the other part of application calling that method can't anticipate and can't recover from it. It is a BUG in your database. So , and IllegalArguementException() should be thrown in this case which would state that the price can't be negative.
I hope that I have expressed my point clearly..
Any API should check the validity of the every parameter of any public method before executing it:
void setPercentage(int pct, AnObject object) {
if( pct < 0 || pct > 100) {
throw new IllegalArgumentException("pct has an invalid value");
}
if (object == null) {
throw new IllegalArgumentException("object is null");
}
}
They represent 99.9% of the times errors in the application because it is asking for impossible operations so in the end they are bugs that should crash the application (so it is a non recoverable error).
In this case and following the approach of fail fast you should let the application finish to avoid corrupting the application state.

Should I use precondition checks to check intermediate results?

Guava offers helper functions to check the preconditions but I could not find helper functions to check intermediate results.
private void foo(String param)
{
checkNotNull(param, "Required parameter is not set");
int x = get(param);
if (x == -1) {
throw new RuntimeException("This should never have happened and indicates a bug.");
}
}
Should I wrap the if (...) {....} part in my own helper?
Or should I use checkState from Guava?
Or should I view the failure of get() as a consequence of param and use checkArgument?
Should I use asserts in these cases?
Or am I missing something?
It's somewhere between a matter of preference and a matter of convention.
Generally, people will use asserts to indicate programming errors; that is, "if I did my job right, then a non-null param should never result in a -1 from get, regardless of user input or other outside forces." I treat them almost as comments that can optionally be verified at runtime.
On the other hand, if get might return -1 in some cases, but that input is invalid, then I would generally throw an IllegalArgumentException, and checkArgument is a perfectly reasonable way to do this. One drawback this has is that when you later catch that, it could have come from pretty much anywhere. Consider:
try {
baz();
bar();
foo(myInput);
} catch (IllegalArgumentException e) {
// Where did this come from!?
// It could have come from foo(myInput), or baz(), or bar(),
// or some method that any of them invoked, or really anywhere
// in that stack.
// It could be something totally unrelated to user input, just
// a bug somewhere in my code.
// Handle it somehow...
}
In cases where that matters -- for instance, you want to pop up a helpful note to the user that they're not allowed to enter -1 in their input form -- you may want to throw a custom exception so that you can more easily catch it later:
try {
baz();
bar();
foo(myInput);
} catch (BadUserInputException e) {
reportError("Bad input: " + e.getMessage());
log.info("recorded bad user input", e);
}
As for checkState, it doesn't really sound right to me. That exception usually implies that the problem was the state that this was in (or some other, more global state in the application). From the docs:
Signals that a method has been invoked at an illegal or inappropriate time.
In your case, a -1 is never appropriate, so checkState is misleading. Now, if it had been:
if (x == -1 && (!allowNegativeOne()) { ... }
...then that would be more appropriate, though it still has the drawback that IllegalArgumentException had above.
So, lastly, there's the question of whether you should just keep the if as it is, or use a helper method. That really comes down to taste, how complex the check is, and how often it's used (e.g. in other methods). If the check is as simple as x == -1 and that check isn't ever performed by other methods (so code reuse is not an issue), I would just keep the if.
If the get method is simply converting the string to an int, then it should do the validation there, preferably throwing an illegalArgumentException or some such RuntimeException. With the above you are also mixing levels of abstraction in your method. E.g. your checkNotNull abstracts away the checking of param for null, but the checking for param as an int is split across the get method and the foo method. Why not have one checkPreCondition type method? E.g.
private void paramShouldBeNonNullInt(String value) {
if (value == null) throw new IllegalArgumentException("value was null");
try {
Integer.parseInt(value)
} catch (NumberFormatException e) {
throw new IllegalArgumentException("value was not an integer");
}
}
First of all you need to make a distinction between contracts (e.g assertions/programming errors) and error handling (e.g. recoverable exceptions that could and should be caught and recovered from).
If you have the need to check an intermediate result, it seems like you don't trust the invoked service and you want to make sure your assumptions hold. Right? This should be expressed as an assertion, and Guava don't have very good support for that.
Have a look at valid4j. Found here https://github.com/helsing/valid4j and here http://www.valid4j.org.
I would then have expressed the code like this (using valid4j's support for hamcrest-matchers):
private int getFoo(String param) {
require(param, notNullValue()); // Violation means programming error at client
int x = get(param);
ensure(x, not(equalTo(-1)); // Violation means programming error at supplier
return x;
}
Some other excellent answers here.
From the Preconditions javadoc:
Precondition exceptions are used to signal that the calling method has made an error. (...) Postcondition or other invariant failures should not throw these types of exceptions.
So ...
Should I wrap the if (...) {....} part in my own helper?
No, existing facilities should be good enough.
Or should I use checkState from Guava?
Yes possibly: if parameters need to be loaded from a file before this method is called, then that would be part of the contract of how this class must be used.
Or should I view the failure of get() as a consequence of param and use checkArgument?
Yes possibly: e.g. if there was some formatting restriction on the syntax of parameters. (Although perhaps that would go inside get())
Should I use asserts in these cases?
Yes. If it's not a precondition check like the above, then normally I'd just use an assert here. Don't forget you can still add a message:
assert x != 1 : "Indicates a bug.";
I find this appropriate to document expectations and verify the internal / private implementation of a class or method.
If you want to make that a runtime check, you could do if (...) throw AssertionError but that's probably only necessary if you're working with dodgy code that you don't trust.

Categories