编码时。试着解决这个难题:
当InputStreamDigestComputor抛出IOException时如何设计类/方法?
似乎我们不能使用这个degisn结构,因为模板方法抛出异常但是覆盖方法不抛出它。但如果更改覆盖的方法抛出它,将导致其他子类都抛出它。 那么这个案子有什么好的建议吗?
abstract class DigestComputor{
String compute(DigestAlgorithm algorithm){
MessageDigest instance;
try {
instance = MessageDigest.getInstance(algorithm.toString());
updateMessageDigest(instance);
return hex(instance.digest());
} catch (NoSuchAlgorithmException e) {
LOG.error(e.getMessage(), e);
throw new UnsupportedOperationException(e.getMessage(), e);
}
}
abstract void updateMessageDigest(MessageDigest instance);
}
class ByteBufferDigestComputor extends DigestComputor{
private final ByteBuffer byteBuffer;
public ByteBufferDigestComputor(ByteBuffer byteBuffer) {
super();
this.byteBuffer = byteBuffer;
}
@Override
void updateMessageDigest(MessageDigest instance) {
instance.update(byteBuffer);
}
}
class InputStreamDigestComputor extends DigestComputor{
// this place has error. due to exception. if I change the overrided method to throw it. evey caller will handle the exception. but
@Override
void updateMessageDigest(MessageDigest instance) {
throw new IOException();
}
}
答案 0 :(得分:2)
在这种情况下,你的超类并不意味着抛出异常。
这种情况下,您的子类因此抛出了上层软件体系结构所不期望的异常。因此你可以:
更新所有子类以抛出异常。
将整个Digestor类框架包装在一个新的类系统中。
(最简单)维护当前代码,并简单地将您希望抛出的任何异常包装在RuntimeException中。
RuntimeExceptions是在java中抛出异常的惯用方法,这些方法没有被编译器或方法签名检查,这有点出乎意料地发生。
答案 1 :(得分:1)
正如其他人所建议的那样,最简单的方法是在运行时异常中简单地包装真正的异常。因此,您不必在throws子句中声明异常。如果你有足够的雄心,你可以创建自己的RuntimeException子类并在更高级别捕获它(这是hibernate所做的,它捕获所有抛出的SQLExceptions并将它们包装在DataAccessException的某个子类中,这是一个运行时异常)。 p>
答案 2 :(得分:1)
您的要求是精神分裂症。
您必须决定DigestComputor.updateMessageDigest
方法是否可以抛出IOException
。如果您希望这样做,则必须将其添加到基类中的签名。这是迫使调用者对IOException
采取行动的唯一方法。但缺点是您还强制其他子类的调用者处理IOException
...这不会发生。
您无法创建一个方法覆盖,该方法覆盖会抛出被覆盖的方法所没有的已检查异常。这会破坏子类型的可替代性,Java也不允许这样做。
它就像路上的叉子。你必须决定走一条路。你不能同时走两条路。但是有一种妥协(有点):
public abstract class Base {
public abstract void method() throws IOException;
}
public class A extends Base {
public void method() throws IOException {
//
}
}
public class B extends Base {
public void method() { // Doesn't throw!!!
//
}
}
现在,如果调用者知道它有B
的实例,它可以执行以下操作:
Base base = ...
B b = (B) base;
b.method(); // No need to catch or propagate IOException
(IIRC,能够做到这一点......即减少在重写方法中抛出的异常......在Java 1.5中添加了。)