继承的Try-catch问题(Java)

继承的Try-catch问题(Java),java,inheritance,try-catch,Java,Inheritance,Try Catch,我们正在尝试实现某种国际象棋游戏,并使用构造函数定义了一个抽象类: public Piece(String name) throws EmptyStringException{ if(name.length()<=0) throw new EmptyStringException(); pieceName = name; } 这里的“问题”是,如果我想创作一部新的王牌作品,我必须写: try { Piece king = new King(true

我们正在尝试实现某种国际象棋游戏,并使用构造函数定义了一个抽象类:

public Piece(String name) throws EmptyStringException{
    if(name.length()<=0)
        throw new EmptyStringException();
    pieceName = name;
}
这里的“问题”是,如果我想创作一部新的王牌作品,我必须写:

try {
    Piece king = new King(true);
} catch(EmptyStringException e){
    e.printStackTrace();
}
而不是简单得多的:

Piece king = new King(true);
因此,即使我无法创建EmptyStringException,我仍然必须尝试/捕获异常

如何解决这一问题,使我仍然可以抛出EmptyStringException,但不必在每次需要创建新棋子时都尝试/捕获?

使用运行时异常:

public class EmptyStringException extends RuntimeException
而不是普通的
异常
。您仍然可以在方法声明中记录您的异常,但您并没有强制客户机代码处理该异常

因此,即使我无法创建EmptyStringException,我仍然必须尝试/捕获该异常


你什么意思?您的
片段
构造函数被声明为
抛出EmptyStringException
。因此,就编译器而言,它可以抛出EmptyStringException,这仅仅是因为您告诉了它。

Make
EmptyStringException
extend
RuntimeException
。编译不会抱怨方法中抛出的
RuntimeException
s在
throws
子句中丢失

请注意,您甚至可以在
throws
子句中包含异常,以记录您抛出的异常。除用于文档编制外,此操作无效

对于调用方应该处理的异常,您应该只使用选中的异常(直接从
java.lang.Exception
派生)。您不应将其用于“可能发生”的事情,例如:

  • 内存不足
  • 参数错误
  • IO异常(JavaRT出错了,现在可以作为一个完美的“how not do it”示例)

由于您无法捕获父构造函数中的异常,因此我将遵循提供的其他建议,将您的异常设置为RuntimeException,或者使用现有的异常IllegalArgumentException

如果您处于无法修改基类或更改抛出的异常的情况下,那么factory方法可以工作

public class King {
   private King() {
      super("King");
   }

   public King createInstance() {
      try {
         new King();
      } catch (EmptyStringException e) {
         throw new RuntimeException("Unexpected expection thrown", e);
      }
   }
}
但在您的情况下,只需要抛出一个RuntimeException是一个更干净的解决方案

如果子构造函数只由子类调用,请考虑使其受到保护,并使用AsScript语句检测空名称。< /P>


已编辑-删除不正确的建议

如前所述,请使用RuntimeException

但我要补充的是,它应该是非法的argumentexception,而不是您自定义的。当存在现有的标准异常时,不需要创建您自己的特定于应用程序的异常


我不愿意使用RuntimeException,因为这会使内置的强制功能短路,所有的异常都会在某个地方处理。是的,在King对象上,异常永远不会发生,这是一个内部编码错误,因此RuntimeException可以说是合适的。但这显然不是你的工件对象的情况

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
    }
  }
}
换句话说,避免打电话给super。调用其他对象来执行初始化。那么关于超级的特殊规则就不适用了

另一个选项是为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真的需要自己的类,您仍然可以在上面这样做,这是相同的概念。

可以而且应该记录<如果JavaDoc中的{@code name}为空,code>@会抛出EmptyStringException。我试图修改King的构造函数,但这实际上给了我一个错误,即
超级
应该是构造函数中必须做的第一件事。也许我还是做错了什么。。。另外,感谢您提到保护它。在这种情况下,我只会使用assert或IllegalArguementException.Edited post来处理无法从super捕获异常的事实()感谢您详细说明我应该何时使用选中的异常,这部分异常需要一些刷新:)。
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
    }
  }
}