异常应表示条件,即使调用方法可能也无法准备立即调用的代码。例如,考虑正在从文件中读取某些数据的代码,可以合法地假定任何有效文件都将以有效记录结尾,并且不需要从部分记录中提取任何信息。
如果读取数据例程不使用异常,而只是报告读取是否成功,则调用代码将看起来像:
temp = dataSource.readInteger();
if (temp == null) return null;
field1 = (int)temp;
temp = dataSource.readInteger();
if (temp == null) return null;
field2 = (int)temp;
temp = dataSource.readString();
if (temp == null) return null;
field3 = temp;
等。为每项有用的工作花费三行代码。相反,如果if readInteger
在遇到文件结尾时将引发异常,并且如果调用方可以简单地传递异常,则代码将变为:
field1 = dataSource.readInteger();
field2 = dataSource.readInteger();
field3 = dataSource.readString();
看起来更加简单和整洁,并且更加注重正常工作的情况。需要注意的是在直接调用方的情况下将被期待来处理的条件,它返回一个错误代码,通常会比一个会抛出异常更有帮助的方法。例如,要合计文件中的所有整数:
do
{
temp = dataSource.tryReadInteger();
if (temp == null) break;
total += (int)temp;
} while(true);
与
try
{
do
{
total += (int)dataSource.readInteger();
}
while(true);
}
catch endOfDataSourceException ex
{ // Don't do anything, since this is an expected condition (eventually)
}
要求整数的代码预期这些调用之一将失败。让代码使用一个无限循环,直到发生这种情况,这要比使用一种通过返回值指示失败的方法要优雅得多。
由于类通常不知道客户会期望或不期望的条件,因此提供两种版本的方法可能会有所帮助,这两种方法可能会以某些调用者期望的方式失败,而另一些调用者不会。这样做将使这两种类型的调用方都能干净地使用这些方法。还要注意,如果情况出现,甚至调用者可能没想到的话,即使是“ try”方法也应该抛出异常。例如,tryReadInteger
如果遇到干净的文件结束条件,则不应引发异常(如果调用者不希望这样,则调用者将使用readInteger
)。另一方面,如果无法读取数据,则可能会引发异常,因为例如已拔出包含数据的记忆棒。尽管应该始终将此类事件视为可能,但立即调用代码不太可能准备做任何有用的响应。当然,不应以与文件结束条件相同的方式报告该错误。