When should an IllegalArgumentException be thrown?
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 namedscanEmail
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.
How to use throws IllegalArgumentException in method declaration
You can do that simply at the beginning of the method:
public double getPrice(double d) throws IllegalArgumentException {
if(d <= 0) {
throw new IllegalArgumentException();
}
// rest of code
}
Also the throws IllegalArgumentException
is not really needed in the declaration of the method. This must only be done with checked exceptions. But IllegalArgumentException
belongs to the unchecked exceptions.
For more information about those I recommend reading this other question.
Should I put throws IllegalArgumentException at the function?
RuntimeException
s like IllegalArgumentException
are used to indicate programming errors. The program itself should rarely be able to handle it. Someone needs to manually fix the code.
Potential RuntimeException
s should be documented somehow in the function contract (i.e. javadoc), either with the explicit @throws
, or while describing the inputs. If you don't have a javadoc for the function, you may want to add the throws clause just to document the potential pitfalls of using the function, but in general adding throws clauses for runtime exceptions is discouraged.
If giving a wrong length is not actually a programming error, but is an exception situation, I would create a new checked exception (such as BadLengthError). If it is not an exceptional situation, don't use exceptions for flow control.
Correct usage of IllegalArgumentException
I think the first usage is correct:
if (!Files.isRegularFile(mazeFile) || !Files.isReadable(mazeFile)) {
throw new IllegalArgumentException("Cannot locate readable file "+mazeFile);
}
Since (as the documentation states) an invalid file was provided as the argument, this should throw an IllegalArgumentException
.
Once you know you have an actual file that meets those requirements, I personally don't think that is a good exception to throw. This will cause other developers to question the type of argument that was given as opposed to the contents of the file. I guess your options are:
Keep it as is, just with very specific error messages explaining
why this was an invalid argument.Use some other, potentially more applicable java exception such as
java.text.ParseException
, since it is the file parsing that is causing the error.Create a custom exception class that more sufficiently describes the issue with the file, e.g. a
MazeParseException
(per the comments) or aFileFormatException
.
I would expect the second or third option to be more beneficial if you anticipate several other developers executing your function.
About throwing IllegalArgumentException
Throwing any exception makes the current method exit immediately, but not the whole program. Furthermore, the exception will continue being thrown at the calling method, from where the first method threw it; this is called propagation. Whether it keeps going at that point depends on whether that calling method catches the exception. If nothing catches the exception, it'll propagate all the way back to the main
method (this is assuming a simple, single-threaded application), and if that method also throws it, then the program will exit.
void callee() {
if (someTrueCondition()) {
throw new IllegalArgumentException("whatever");
}
System.out.println("this will never get called");
}
void caller() {
calle(); // the IllegalArgumentException propagates from here
System.out.println("this will also never get called");
}
The above is true for any exception. What makes IllegalArgumentException
different from others is only the fact that it's unchecked, and thus doesn't need to be declared in a throws
clause on the method that may throw it. (Note that in your question, you said you probably would need to declare throws IllegalArgumentException
, but you actually don't, because it's an unchecked exception.)
If you were instead throwing a checked exception (e.g., throw new SQLException()
), then both callee
and caller
would need to declare that exception. callee
would need to declare it because it throws that exception directly, and caller
would need to declare it because it may throw that exception indirectly, via propagation from callee
.
The only way to stop this propagation (both of the exception at runtime, and of the throws
clauses at compile-time) is to catch the given exception with a try-catch
.
Unable to Throw an IllegalArgumentException
You're almost there... in your if
you're ensuring that all scores are within the proper range.
When the if
fails, you want to throw the IllegalArgumentException in an else
, like this:
if (scores[0] >= 0 && scores[0] <= 100 ||
scores[1] >= 0 && scores[1] <= 100 ||
scores[2] >= 0 && scores[2] <= 100)
{
average = totalScores / 3;
System.out.println("Average Score: " + average);
}
else
{
throw new IllegalArgumentException("Numbers were too low or high.");
}
How do I throw and catch an IllegalArgumentException?
To throw an exception, you use keyword throw
. To catch, you use the try / catch construct. See this for more details:
- http://docs.oracle.com/javase/tutorial/essential/exceptions/try.html
For your case, you'd do something like this - this is a test case:
try {
throw new IllegalArgumentException("Threw an IllegalArgumentException");
} catch(IllegalArgumentException e) {
System.out.println("Caught an IllegalArgumentException..." + e.getMessage());
}
You should, however, look into your code to see why IllegalArgumentException is being thrown anyway and fix that part. Using exceptions and try / catch is for unexpected events, not events that you expect to happen and that you can handle in a better way.
For example, FileNotFoundException gets thrown when a file could not be found. You generally try / catch that, so that you do something if the file was not found. However, if it's expected in a reasonable number of cases that the file might not be there, it would be better to first check if the file exists and then if it does actually do something with it.
Related Topics
Which Part of Throwing an Exception Is Expensive
How to Use a Java8 Lambda to Sort a Stream in Reverse Order
Resize a Picture to Fit a Jlabel
Spring Session-Scoped Beans (Controllers) and References to Services, in Terms of Serialization
How to Set Tls Version on Apache Httpclient
String Replacement in Java, Similar to a Velocity Template
Convert Bufferedinputstream into Image
Pass Data from Java Servlet to Jsp
Java Conventions: Use Getters/Setters Within the Class
Java's Virtual MAChine's Endianness
JSON Consumer of Polymorphic Objects
Why Are Class Static Methods Inherited But Not Interface Static Methods
How to Configure Httponly Cookies in Tomcat/Java Webapps
Logging User Activity in Web App
How to Have Case Insensitive Urls in Spring MVC with Annotated Mappings
How to Convert Int to Unsigned Byte and Back