I am implementing an interface which defines a method that can throw an exception if the parameters are not valid. What constitutes valid parameters depends on the implementing class. The interface also defines an isValid()
method which can be used to check the parameters but returns a boolean rather than throwing an exception. I have found that implementing both methods will cause a lot of duplication. Consider this made up example:
public class Something implements SomeInterface {
// Other class stuff
public void doTheThing(SomeParameter sp) throws SpecificRuntimeException {
if(sp == null) throw new ParameterCannotBeNullException();
if(sp.getNonZeroInt() == 0) throw new ShouldBeNonZeroException();
if(!sp.someOtherCondition()) throw new SomeConditionNotMetException();
...
}
public boolean isValid(SomeParameter sp) {
if(sp == null) return false;
if(sp.getNonZeroInt() == 0) return false;
if(!sp.someOtherCondition()) return false;
...
return true;
}
}
The problem is the checks in both methods must be consistent, and are essentially duplicated logic. I've been trying to consolidate the checks so that both methods use the same checks but the behaviour is still retained. Some things I considered:
- in
doTheThing()
have the lineif(!isValid(sp) throw new RuntimeException();
- separate the exception throwing part into a separate, private method, say
checkParameter()
and inisValid()
do:try { checkParameter(sp); return true; } catch (SpecificRunTimeException e) { return false; }
The problem with 1. is that the specific exception is lost, and I want to provide as detailed an exception as possible. The problem with 2. is using the exception mechanism seems... wrong somehow. This part of the code may be performance sensitive, and I don't want to depend on something that's fundamentally slower than it needs to be (if I have to do it this way and profiling doesn't show a problem, fair enough... but what if is a problem?). Or has the performance hit of using exceptions this way been shown to be negligible?
What is the best way to refactor this code to use the same validity checking logic?