我们正在尝试实现某种Chess游戏,我们已经使用构造函数定义了一个抽象类Piece:
public Piece(String name) throws EmptyStringException{
if(name.length()<=0)
throw new EmptyStringException();
pieceName = name;
}
扩展类看起来像这样:
public King(boolean white) throws EmptyStringException{
super("King", white);
}
这里的'问题'是,如果我想创建一个我必须写的新王片:
try {
Piece king = new King(true);
} catch(EmptyStringException e){
e.printStackTrace();
}
而不是更简单:
Piece king = new King(true);
即使我只是不能创建一个EmptyStringException,我仍然需要尝试/捕获异常。
我怎样才能解决这个问题,所以我仍然可以在Piece中抛出EmptyStringException,但是每次我需要创建一个新的国际象棋时都不必尝试/ catch?
答案 0 :(得分:7)
使用运行时异常:
public class EmptyStringException extends RuntimeException
而不是普通Exception
。您仍然可以在方法声明中记录您的异常,但您并没有强制客户端代码处理异常。
答案 1 :(得分:1)
让EmptyStringException
延长RuntimeException
。编译不会抱怨RuntimeException
子句中缺少的方法中抛出的任何throws
。
请注意,您甚至可以在throws
子句中包含异常来记录您抛出它。除文档用途外,这不起作用。
您应该只使用已检查的异常(直接从java.lang.Exception
派生)来解决调用者应该处理的异常。你不应该将它们用于“可能发生”的事情,如:
答案 2 :(得分:1)
由于您无法从父构造函数中捕获异常,因此我将遵循其他提供的建议并使您的异常成为RuntimeException,或使用现有的异常IllegalArgumentException。
如果您遇到无法修改基类或更改抛出异常并且工厂方法可以工作的情况。
public class King {
private King() {
super("King");
}
public King createInstance() {
try {
new King();
} catch (EmptyStringException e) {
throw new RuntimeException("Unexpected expection thrown", e);
}
}
}
但是在你的情况下,只是让一个部分抛出一个RuntimeException是一个更清洁的解决方案。
如果Piece的构造函数仅由子类调用,请考虑使其受保护并使用assert语句来检测空名。
已编辑 - 删除了错误的建议
答案 3 :(得分:0)
你是什么意思?您的所以即使我根本无法创建一个EmptyStringException,我仍然需要尝试/捕获异常。
Piece
构造函数声明为throws EmptyStringException
。所以就编译器而言,可以抛出一个EmptyStringException,只是因为你已经这么说了。
答案 4 :(得分:0)
如前所述,使用RuntimeException。
但我会补充说它应该是IllegalArgumentException而不是你的自定义。当存在现有标准异常时,无需创建自己的应用程序特定异常。
答案 5 :(得分:0)
我不愿意使用RuntimeExceptions,因为这会短路内置的强制执行,以便在某处处理所有异常。是的,在你的King对象上,异常永远不会发生,这是一个内部编码错误,所以RuntimeException可以说是合适的。但是你的Piece对象显然不是这种情况。
Java令人讨厌的规则,即super()必须是第一个语句,这会阻止你在King构造函数中捕获错误。
我在一些程序中使用的替代方法是将所有构造函数代码移动到普通函数,然后让构造函数调用此函数。像:
public class Piece
{
public Piece(String name) throws EmptyStringException
{
initPiece(name);
}
// Protect so outsiders must use legal constructors
protected Piece()
{
// nop
}
protected void initPiece(String name) throws EmptyStringException
{
if (name.length()==0)
throw new EmptyStringException();
pieceName=name;
}
}
public class King extends Piece
{
public King(boolean white)
{
try
{
initPiece("King");
}
catch (EmptyStringException panic)
{
throw new RuntimeException(panic.toString()); // should never happen
}
}
}
换句话说,避免需要拨打超级电话。调用其他东西进行初始化。然后关于超级的特殊规则不适用。
另一种选择是为King而不是构造函数创建工厂方法。说:
public class Piece
{
public Piece(String name) throws EmptyStringException
{
if (name.length()==0)
throw new EmptyStringException();
pieceName=name;
}
public Piece makeKing(boolean white)
{
try
{
return new Piece("King");
}
catch (EmptyStringException e)
{
throw new RuntimeException(e.toString()); // won't ever happen
}
}
}
如果King确实需要成为自己的班级,你仍然可以做到这一点,这是相同的概念。