I'm writing a method which expect some input. Now, I thought that it would be a good practice to write it in a defensive way (i.e. checking that the input is correct).
Basically, the input should be okay since there's only one place (reliable) that uses this method.
So my question is,
Basically, the input should be okay since there's only one place (reliable) that uses this method.
It's great, that you reason about your function this way. You just defined a contract for your function. It says, that this function expects a valid input. In this case, it is a very good practice to employ defensive programming by throwing an exception when invalid input is detected. This exception will greatly simplify detection of callers of your function, who broke contract and called your function with invalid input.
If you did not throw a dedicated exception, than (if you are lucky) your function might break by throwing a generic technical exception, e.g. NullPointerException
or perhaps ArrayIndexOutOfBoundsException
. Such stacktrace still shows, that something wrong happened, when your function was called. However, you need to analyze, "what" happened. In worst case, your function would not throw any exception at all and "somehow" process invalid input. Your program than can later break on seemingly unrelated location or in even worse case, it does not break and it presents wrong result to the user.
Is the defensive programming justified here?
Yes, it definitely is.
If so, should it throw a checked or unchecked exception?
Checked vs unchecked exceptions is still an ongoing debate. You can find many answers to this question on StackOverflow. Scala language only has unchecked exceptions. I personally prefer them too.
What if your function expects invalid input too?
Typically, these are functions, which receive input from humans. For example an user registration form requires password, which is not too short and contains at least one digit. In this case, "failure" is expected and should somehow be encoded in function's return value, so that caller of the function is forced to inspect both kinds of return value - Success and Failure. Such return values can be modeled using algebraic data types. Java does not allow to model ADTs naturally and we got used to model Failure by throwing an exception. Maybe in this case checked exceptions still make sense.
Edit:: Other answers go into more details on "when" to validate and when to not. To summarize: public methods - yes; do not repeat same validation across layers.