Which exception to throw for invalid input which is valid from client perspective
The question is is throwing illegal argument exception the right thing to do?
It depends on how you want / need to "frame" this condition; i.e. is it a bug, a user input error, or something that the program is supposed to be able to deal with?
-
If the case of two lines not intersecting is unequivocally a "bug", then
IllegalArgumentException
is fine. This is what the exception is designed for. (Note that it is an unchecked exception, so the expectation is that it won't be caught / recovered from.) -
If this is a case that you expect the program to be able to recover from by itself, then a custom exception is the best idea. That way, you reduce the possibility of your code getting confused by (say) a library method throwing (say) an
IllegalArgumentException
... than means something other than "two lines intersected". -
If this case is something that you expect to report to the end user as part of input validation, then a generic "validation error" exception might be more appropriate than a specific custom exception. However, this method doesn't look like it is designed to be used (solely) for user input validation.
In some contexts, it may be better to not throw an exception at all, but (IMO) this is not one of those contexts. The alternatives are returning null
or returning a Point
value that means "no such point" to the calling code. The problems with the alternatives are:
- If you return
null
the application has to deal with thenull
case ... or there will be NPEs. - There is no natural
Point
instance that could be used to mean "not a point".
This is not to say that you couldn't make these alternatives work. It is just that in this context, it will probably be more work to do that, and probably there won't be a tangible pay-off.
This almost certainly should not throw an exception, because it makes perfect sense to invoke a method like this with any two Line
values. You have already appropriately handled null values.
You have also, very reasonably, defined the behavior of your class in one of the ill-defined input situations, namely two coincident "constant" (horizontal) lines, where you return the point at x=0
on that line. You ought to similarly select return values for the other cases of ill-defined inputs: coinciding vertical lines, coinciding lines that are neither horizontal nor vertical, and non-coinciding parallel lines.
In my opinion, the most natural result for the last case - non-coinciding parallel lines - would be null
, reflecting the fact that there is no point of intersection.
It would then be up to the client to decide whether a null intersection warrants an exception, an error message, or whatever. E.g. an interactive shell prompting the user for lines to intersect would probably print an error message and ask the user to try again. Some more complicated calculation, e.g. a linear optimizer trying to define boundaries for its search, might want to throw IllegalArgumentException
if the constraints giving rise to the parallel lines contradict each other.
Of course, the return values in all these cases (coincident lines or non-coincident parallel lines) should be precisely documented in the method's javadoc.
I'd say you do the right thing: you catch the condition early. It is either that or people will complain that "your program is buggy, look at this input data, division by 0".
Given that there will be no such error in 99+% of situations, this is an exceptional condition and doesn't grant declaring a checked exception, so an unchecked exception looks indeed like the right choice.
Now, as to whether IllegalArgumentException
is the "good one", it is at least the closest exception describing this case... You can, if you feel you have a better name, always create your own one inheriting RuntimeException
.
IF, on the other hand, this situation is not that infrequent, then maybe the logic to reach that function should be reviewed so as to never hit this condition in the first place.
As @Andy-Lowry and @KamikazeCZ say, this should not be an exception.
This method should not concern itself with whether the client expects lines to always intersect or not; it should only bother with finding the intersection of two lines -- something which inherently might not happen.
If the caller gets back a result indicating no-intersection, then THAT code can decide whether it's invalid-input because the end-user was duly warned, or something they can handle (perhaps by re-prompting), or throw a customized exception.
So, back to what should this method return? Some sort of sentinel value, the same way that indexOf
returns -1 in the collections library. Returning null
is a reasonable sentinel. In Java 8, you can return an Optional<Point>
, to help remind the caller that there might not be a proper Point
.
You have an additional problem, too: what somebody asks for the intersection of a line with itself? (Mathematically, the intersection of two lines is either 0 point, 1 point, or infinitely many points.) You might need to be able to return two sentinel values, which is more involved, in Java. This method could weasel out of the situation this time, by saying "in the case of multiple answers, this method may return any of them", or (what I'd probably do) "...returns the Point nearest the origin".
Btw, this thinking largely follows from a unit-test mindset: start by defining the correct answer should be for a variety of corner-case inputs, before launching into code and kinda committing yourself to a certain return-type etc.
Finally: when comparing the results of getSlope()
using ==
, beware floating-point roundoff errors. It might be the best thing to do here, but it's still problematic. The way you assume (or round) the intersection to int
s, though, suggests you might have very special constraints/assumptions going on in your problem.