New page: It has been mentioned in the page about exceptions that changing a code to throw a new exception is not compatible change. However this is not fully true, ...
New page
It has been mentioned in the [[APIDesignPatterns:Exceptions|page about exceptions]] that changing a code to throw a new exception is not compatible change. However this is not fully true, because [[Java]] exceptions are regular classes, and classes support inheritance, one can define new subtypes of existing exceptions and yet keep the code written by your API users compatible. Imagine there is a method in version one throwing ordinary I/O exception:
<source lang="java">
public static int compute(int x, int y) throws IOException {
if (y - x == 1) throw new IOException("For some reason I cannot deal with this!");
return x + y;
}
</source>
Now people can use this method to do many things, complex ones or trivial like to sum two numbers:
<source lang="java">
int result;
try {
result = compute(1, 2);
} catch (IOException ex) {
Logger.getLogger("mylogger").log(Level.WARNING, "Problem!", ex);
result = -1;
}
</source>
This is a valid use of the compute API method. As authors of the library, we value our users and want to support this API use in future. However we also want to please more and more users. If some other ones require us to provide better information about the values of '''x''' and '''y''', instead of just throwing the '''IOException''', can we help them? Can we change the contract and yet pretend we have not changed anything? Yes, this is possible, just imagine version two of the library:
<source lang="java">
public static int compute(int x, int y) throws IOException {
if (y - x == 1) throw new StrangeXYException(x, y);
return x + y;
}
public final class StrangeXYException extends IOException {
int x, y;
StrangeXYException(int x, int y) {
super("For some reason I cannot deal with this!");
this.x = x;
this.y = y;
}
public int getX() { return x; }
public int getY() { return y; }
}
</source>
The previously written client code remains valid. A subclass of '''IOException''' is thrown, it is matched by the '''catch (IOException ex)''' block and everything continues to work as it used to. Yet, if one is interested in more detailed information about the failure, one can catch the version two newly defined exception:
<source lang="java">
int result;
try {
result = compute(1, 2);
} catch (StrangeXYException ex) {
// compute ourselves meaningful result
result = ex.getX() + ex.getY();
} catch (IOException ex) {
Logger.getLogger("mylogger").log(Level.WARNING, "Problem!", ex);
result = -1;
}
</source>
The object oriented nature of '''try/catch''' statements makes evolution perfectly possible. With every new release one can define new specialized exception as subclass of some already existing one. The previously working code can remain unaffected, the new client code can extract the additional information from the new exception class exposed in the API. This is much more pleasant evolution than for example the one available with [[Talk:Blogs:AndreiBadea:EnumsInAPIs#Joel_Neely_said_...|switch/case]] where inheritance is not taken into account at all.