java:当重载方法没有抛出时,模板方法抛出异常时如何处理设计

时间:2012-07-01 03:00:40

标签: java

编码时。试着解决这个难题:

当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();

    }

}

3 个答案:

答案 0 :(得分:2)

在这种情况下,你的超类并不意味着抛出异常。

这种情况下,您的子类因此抛出了上层软件体系结构所不期望的异常。因此你可以:

  1. 更新所有子类以抛出异常。

  2. 将整个Digestor类框架包装在一个新的类系统中。

  3. (最简单)维护当前代码,并简单地将您希望抛出的任何异常包装在RuntimeException中。

  4. 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中添加了。)