Oliver,
You could always pass methodA, B and C the int, rather than the
IntegerParseResult.
public mainMethod()
{
methodA(LessException.parseInt("foo").getValue());
methodB...
methodC...
}
This way you will get an IllegalStateException, which is an unchecked
exception, but it's fairly obvious that there is more to the result of
parseInt than an int based on that code snippet, so an experienced
programmers shouldn't miss it.
parseInt() might be an expensive operation, so you'd generally want to
keep the object representing the parsed int around, in case you want to
re-use it, e.g.
mainMethod() {
ParsedInteger pInt = LessException.parseInt("foo");
methodA(pInt.getValue());
methodB(pInt.getValue());
//etc.
}
However, now you have an object which may be in and of itself "invalid",
which to me is a bad code smell. That might just be a matter of opinion, but
I prefer having the exception occur right away (during the call to
parseInt()) than to carry around a bad object, and only find out much later
on that something went wrong.
What if your application parses the int, then serializes the object in a
database.
Months later, another application running on a different computer in the
other side of the world deserializes the object, and then tries to do
something useful with it, only to get an exception thrown. This is obviously
an extreme example, but it illustrates why it's generally better to get the
exception as early as possible.
I'd prefer the test, and there's no reason why it can't be done in
mainMethod:
public mainMethod()
{
IntegerParseResult ipr=LessExceptions.parseInt("foo");
if (ipr.hasValue())
methodA(ipr.getValue());
ipr=LessExceptions.parseInt("25");
if (ipr.hasValue())
methodB(ipr.getValue());
ipr=LessExceptions.parseInt("-42");
if (ipr.hasValue())
methodC(ipr.getValue());
}
If you take the test out of methods A, B and C, and those methods are
public, then you have a fragile interface. Not too mention you also have
code duplication. Conceptually, "testing that your object has a value before
using it" and "using it" should be one indivisible action, which is why I'd
rather the test be IN the methods. But again, that might just be a matter of
opinion.
To get the same using Integer.parseInt you would need 3 separate
try..catch blocks:
public mainMethod()
{
try
{
methodA(Integer.parseInt("foo"));
}
catch (final NumberFormatException exception)
{
logger.fine(exception);
}
try
{
methodB(Integer.parseInt("25"));
}
catch (final NumberFormatException exception)
{
logger.fine(exception);
}
try
{
methodC(Integer.parseInt("-42"));
}
catch (final NumberFormatException exception)
{
logger.fine(exception);
}
}
I know which I'd rather read/write/explain to newbies.
No, actually the equivalent code using try/catch is:
public mainMethod() {
try {
methodA(Integer.parseInt("foo"));
methodB(Integer.parseInt("25"));
methodC(Integer.parseInt("-42"));
} catch(NFE e) {
logger.error(e);
}
}
Notice that with your unchecked exception algorithm that as soon as
method A executes, the exception is thrown, and we're taken OUT of the main
method. That's what the code I posted here does as well.
With your 3 try/catch blocks, what happens is that if A fails, the
program still procees and tries to do B and C. This might be what you want,
or it might not be what you want.
This added flexibility, BTW, is another good reason for having
exceptions (for those who doubt their power), though it's irrelevant now
because you've already said your problem isn't with exceptions in general,
but checked exceptions.
I'm not sure what you mean by that. I meant a failed parse, the kind
of thing parseInt("foo") would return.
The code you posted earlier for NegativeIntergerParseResult is this:
<code>
final class NegativeIntegerParseResult implements IntegerParseResult
{
public NegativeIntegerParseResult()
{
}
public boolean hasValue()
{
return false;
}
public int getValue()
{
throw new IllegalStateException();
}
}
</code>
That's what I mean by it's impossible to get a negative parse value.
- Oliver