Попробуй поймать проблему с наследованием (Java) - PullRequest
3 голосов
/ 26 апреля 2011

Мы пытаемся реализовать какую-то игру в шахматы, и мы определили абстрактный класс 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, я все еще должен попытаться / поймать исключение.

Как я могу решить эту проблему, чтобы я все еще мог выбросить исключение EmptyStringException в Piece, но ненужно пробовать / ловить каждый раз, когда мне нужно создать новую шахматную фигуру?

Ответы [ 6 ]

7 голосов
/ 26 апреля 2011

Использовать исключение времени выполнения:

public class EmptyStringException extends RuntimeException

вместо простого Exception.Вы все еще можете document свое исключение в объявлении метода, но вы не заставляете код клиента обрабатывать исключение.

1 голос
/ 26 апреля 2011

Поскольку вы не можете перехватывать исключения из родительских конструкторов, я буду следовать другим предоставленным предложениям и делать ваше исключение RuntimeException или использовать существующее исключение IllegalArgumentException.

Если вы оказались в ситуации, когда вы не моглиt изменить базовый класс или изменить выбрасываемое исключение, и фабричный метод мог бы работать.

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

   public King createInstance() {
      try {
         new King();
      } catch (EmptyStringException e) {
         throw new RuntimeException("Unexpected expection thrown", e);
      }
   }
}

Но в вашем случае простое использование Piece - RuntimeException - более чистое решение.

Также, если Pieceконструктор будет вызываться только подклассами, рассмотрите возможность сделать его защищенным и использовать операторы assert для обнаружения пустого имени.

Отредактировано - удален неверный совет

1 голос
/ 26 апреля 2011

Сделать EmptyStringException расширить RuntimeException. Компиляция не будет жаловаться на любые RuntimeException s, добавленные в метод, которые отсутствуют в предложении throws.

Обратите внимание, что вы даже можете включить исключение в предложение throws, чтобы документ, который вы выбросили. За исключением случаев документирования, это не имеет никакого эффекта.

Вы должны использовать проверенные исключения (которые получены непосредственно из java.lang.Exception) только для исключений, которые должен обрабатывать вызывающий объект. Вы не должны использовать их для вещей, которые «могут произойти», таких как:

  • Недостаточно памяти
  • Ошибки аргумента
  • Исключения ввода-вывода (которые Java RT ошиблась и теперь служит прекрасным примером "как не сделать это")
0 голосов
/ 27 апреля 2011

Я неохотно использую 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
    }
  }
}

Другими словами, избегайте необходимости называть супер.Вызовите что-нибудь еще, чтобы выполнить инициализацию.Тогда специальные правила о супер не применяются.

Другой вариант - создать фабричный метод для Кинга, а не конструктор.Скажите:

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
    }
  }
}

Если Кингу действительно нужен собственный класс, вы все равно можете сделать это выше, это та же концепция.

0 голосов
/ 26 апреля 2011

Как уже было сказано, используйте RuntimeException.

Но я добавлю, что это должно быть IllegalArgumentException вместо вашего пользовательского. Нет необходимости создавать собственные исключения для конкретных приложений, если существуют существующие стандартные.

Java, исключения для отдельных классов и стандартные исключения

0 голосов
/ 26 апреля 2011

Так что, хотя я просто не могу создать исключение EmptyStringException, мне все равно нужно попытаться / поймать исключение.

Что вы имеете в виду?Ваш Piece конструктор объявлен как throws EmptyStringException.Таким образом, что касается компилятора, он может генерировать исключение EmptyStringException, просто потому, что вы так сказали.

...