0

我想编写一个可用于不同类和特定行为的异常类。它适用于更改对象 - 比如

a.setWeight(500)

- 但它在我的构造函数中不起作用 - 比如

Cheese b = new Cheese(500);

因为没有生成对象,并且在我的 WeightException 中插入了 null。

public class WeightException extends Exception {
        private int attribute;
        private Object object;

        public WeightException(Object o, int a) throws WeightException {
            object = o;
            attribute = a;
        }

        public String getMessage() {
            if(object instanceof Cheese)
            return "Cheese is overweight.";

            if(object instanceof Baggage)
                return "Baggage is "+String.valueOf(attribute)+" kilos overweight.";
        }
    }

    public class Cheese {
    private int weight;

    public Cheese(int weight) {
    setWeight(weight);
    }

    public void setWeight(int weight) throws WeightException {
    if(weight<200)
    this.weight = weight;
    else
    throw new WeightException(this, weight);
    }
    }

有没有人知道比在我的异常类参数中插入带有类名的字符串更好的方法来解决这个问题?

4

4 回答 4

2
  • 在要使用此异常的类中实现接口。
  • 该接口有一个方法来定义一个消息,可能另一个来提供一个属性。
  • 或者,提供一组属性并用于String.format构建消息。
  • 使用该接口来定义传递给异常 ctor 的对象参数。
  • 在异常中调用该方法以获取消息。

就个人而言,我发现这是一种反模式,除非您要使用的异常类非常紧密相关。否则,您将放弃具有语义意义的异常属性名称。

我宁愿看到一个特定于应用程序的超类,其子类具有语义意义。

于 2013-06-14T20:18:43.713 回答
0

你真的试过运行这段代码吗?该this变量在构造函数中有效(非空)。即使构造函数抛出异常,也已经创建了一个新对象并且可以被引用。请参阅JLS

于 2013-06-14T20:24:08.913 回答
0

这是一个解决方案,需要您使用我的“玩具”项目(好吧,我已经在其他项目中使用它):

像这样创建一个基本抽象类:

public abstract class WeightedItem
{
    protected static final MessageBundle BUNDLE;

    static {
        // The day when you get serious, replace with a properties bundle
        final MessageSource source = MapMessageSource.newBuilder()
            .put(Cheese.class.getCanonicalName(), "cheese is overweight")
            .put(Baggage.class.getCanonicalName(), "baggage is %d kilos overweight")
            .build();

        BUNDLE = MessageBundle.newBuilder().appendSource(source).freeze();
    }

    protected int weight;

    protected final WeightException doException(final Object... params)
    {
        return new WeightException(BUNDLE.printf(getClass().getCanonicalName(),
            params));
    }
}

的实现Baggage然后会做:

public class Baggage
    extends WeightedItem
{
    // ....

    public void setWeight(int weight)
        throws WeightException
    {
        if (overweight)
            throw doException(weight);
    }
}

由于该实现既是抗键(如果丢失则返回键)和抗格式(如果格式参数不匹配则返回格式字符串本身),您可以保证有参数化消息或快速查看您的消息在哪里出错......

于 2013-06-14T20:56:17.427 回答
0

如果您使用消息所需的一切参数化异常,则可以摆脱 using instanceof,并使异常可被任何类使用:

此外,持有对导致异常的对象的引用不是一个好主意 - 这是不必要的,是内存泄漏的一种形式,但重要的是,如果从构造函数中抛出异常,将允许this从构造函数“逃脱”(总是坏的)。

public class WeightException extends Exception {
    private final int attribute;
    private final String className;
    private final String units;

    public WeightException(Object o, int a) {
        this(o, a, null);
    }

    public WeightException(Object o, int a, String u) {
        classname = o.getClass().getSimpleName(); // eg "Cheese"
        attribute = a;
        units = u == null ? "" : u + " ";
    }

    public String getMessage() {
        return className " is " + attribute + " " + units + "overweight.";
    }
}

您现在可以将此异常与任何类一起使用,而无需进一步修改异常或客户端类,除了提供可选单元:

来自Cheese

throw new WeightException(this, weight);

来自Baggage

throw new WeightException(this, weight, "kilos");
于 2013-06-14T22:08:38.880 回答