Генерация собственных исключений

У меня есть этот класс Аккаунт

    import java.io.IllegalArgumentException;

    class Account {
        final int accountNo;
        final Customer owner;
        final double overdraft;

        double balance = 0;

        private Account(int accountNo, Customer owner, double overdraft) {
            this.accountNo = accountNo;
            this.owner = owner;
            this.overdraft = overdraft;
        }

        void print() {
            Out.println("Kontonummer: " + accountNo);
            owner.print();
            Out.format("Kontostand: %.2f%nÜberziehungsrahmen: %.2f%n", balance, overdraft);
        }

        public boolean deposit(double amount) throws IllegalArgumentException {
            if (amount <= 0) {
                throws new IllegalArgumentException("Cannot deposit negative amounts!");
                break;
            } else {
                balance += amount;
                return true;
            }

            public boolean withdraw(double amount) throws OverdraftLimitReachedException {
                if (amount <= 0 || !isCovered(amount)) {
                    throw new OverdraftLimitReachedException("Overdraft limit has been reached", accountNo);
                    break;
                } else {
                    balance -= amount;
                    return true;
                }

                boolean isCovered(double amount) {
                    return amount - overdraft <= balance;
                }

                boolean transfer(Account target, double amount) {
                    boolean success = withdraw(amount);
                    if (!success) return false;

                    target.deposit(amount);
                    return true;
                }
            }
        }
    }

Теперь у меня также есть это исключение, которое я написал

    public class NoSuchAccountException extends AccountException {

        public NoSuchAccountException(int accountNo) {
            super(message, accountNo);
        }
    }

Теперь мне нужно сгенерировать это исключение в учетной записи класса, когда искомый номер учетной записи не существует. Теперь мой вопрос заключается в том, в каком методе (или функции, я думаю, это то же самое, пожалуйста, поправьте меня, если я ошибаюсь) я бросаю это исключение. И после чего проверить. Как мне проверить, существует ли номер счета, и если нет, я выдам это исключение. Спасибо!

РЕДАКТИРОВАТЬ: Банковское дело класса, чтобы завершить программу

class Banking {
  static final int CAPACITY = 100;

  final Account[] accounts = new Account[CAPACITY];
  int nOfAccounts = 0;

  int createAccount(String firstName, String lastName, String phone, double overdraft) {
    if (nOfAccounts == CAPACITY) return -1;

    // use nOfAccounts as accountNo and index to array
    Customer owner = new Customer(firstName, lastName, phone);
    Account account = new Account(nOfAccounts, owner, overdraft);
    accounts[nOfAccounts] = account;
    nOfAccounts++;

    return account.accountNo;
  }

  boolean deposit(int accountNo, double amount) {
    if (accountNo < 0 || accountNo >= nOfAccounts) return false;

    Account account = accounts[accountNo];
    return account.deposit(amount);
  }

  boolean withdraw(int accountNo, double amount) {
    if (accountNo < 0 || accountNo >= nOfAccounts) return false;

    Account account = accounts[accountNo];
    return account.withdraw(amount);
  }

  boolean transfer(int fromNo, int toNo, double amount) {
    if (fromNo < 0 || toNo < 0 ||
        fromNo >= nOfAccounts || toNo >= nOfAccounts) return false;

    Account from = accounts[fromNo];
    Account to = accounts[toNo];
    return from.transfer(to, amount);
  }

  double getBalance(int accountNo) {
    if (accountNo < 0 || accountNo >= nOfAccounts) return 0;

    Account account = accounts[accountNo];
    return account.balance;
  }

  double getBalance() {
    double sum = 0;

    for (int i = 0; i < nOfAccounts; i++) {
      sum += accounts[i].balance;
    }
    return sum;
  }

  void print() {
    Out.println("---------- Bankauszug ----------");

    for (int i = 0; i < nOfAccounts; i++) {
      accounts[i].print();
      Out.println("--------------------------------");
    }
    Out.format("Bilanzsumme: %.2f%n", getBalance());
    Out.println("--------------------------------");
  }

  // --------------------- Optionaler Teil ---------------------

  public static void main(String[] args) {
    Banking banking = new Banking();
    char op;

    do {
      printMenu();
      op = readOperation();

      switch (op) {
        case 'a': {
          printTitle("Konto anlegen");
          String firstName = getString("Vorname");
          String lastName = getString("Nachname");
          String phone = getString("Telefonnummer");
          double overdraft = getDouble("Überziehungsrahmen");

          int accountNo = banking.createAccount(
            firstName, lastName, phone, overdraft);
          printMessage("Anlegen von Konto " + accountNo, accountNo != -1);
          break;
        }
        case 'e': {
          printTitle("Einzahlen");
          int accountNo = getInt("Kontonummer");
          double amount = getDouble("Einzahlungsbetrag");

          boolean success = banking.deposit(accountNo, amount);
          printMessage("Einzahlen", success);
          break;
        }
        case 'b': {
          printTitle("Abheben");
          int accountNo = getInt("Kontonummer");
          double amount = getDouble("Abhebungsbetrag");

          boolean success = banking.withdraw(accountNo, amount);
          printMessage("Abheben", success);
          break;
        }
        case 't': {
          printTitle("Überweisen");
          int fromNo = getInt("Von Kontonummer");
          int toNo = getInt("Auf Kontonummer");
          double amount = getDouble("Betrag");

          boolean success = banking.transfer(fromNo, toNo, amount);
          printMessage("Überweisen", success);
          break;
        }
        case 'd':
          banking.print();
          break;
        case 'q':
          Out.println("Beenden");
          break;
        default:
          Out.println("Ungültige Operation");
          break;
      }
    } while(op != 'q');
  }

  static void printMenu() {
    Out.println();
    Out.println("*********** Bankverwaltung ********");
    Out.println("Konto anlegen ................... a");
    Out.println("Einzahlen ....................... e");
    Out.println("Beheben ......................... b");
    Out.println("Überweisen ...................... t");
    Out.println("Übersicht drucken ............... d");
    Out.println("Beenden ......................... q");
    Out.print("Welche Menuoption? [a|e|b|t|d|q]: ");
  }

  static char readOperation() {
    char ch = Character.toLowerCase(In.readChar());
    In.readLine();
    return ch;
  }

  static void printTitle(String text) {
    Out.println("*** " + text + " ***");
  }

  static String getString(String text) {
    Out.print(text + ": ");
    return In.readLine();
  }

  static double getDouble(String text) {
    Out.print(text + ": ");
    return In.readDouble();
  }

  static int getInt(String text) {
    Out.print(text + ": ");
    return In.readInt();
  }

  static void printMessage(String operation, boolean success) {
    String message = success ?
      operation + " erfolgreich durchgeführt" :
      "Ungültige Operation";
    Out.println(message);
  }
}

person cody1    schedule 30.05.2020    source источник
comment
Где вы ищете учетную запись?   -  person user7    schedule 30.05.2020
comment
Привет! Я не совсем уверен, что понимаю, о чем вы спрашиваете. Вы имеете в виду, какая часть кода пытается найти номера счетов или что-то еще?   -  person cody1    schedule 30.05.2020
comment
Да. Вы показываете нам класс учетной записи, но это не класс учетной записи, который ищет учетную запись. Это метод, который ищет учетную запись, которая должна вызывать исключение   -  person Kamil Janowski    schedule 30.05.2020
comment
концепция методов и функций исходит из C++, в котором есть и то, и другое. Метод = функция в классе. Итак, в Java технически все является методом. Однако на практике никого не волнует, называете ли вы их функциями или методами.   -  person Kamil Janowski    schedule 30.05.2020
comment
Хм, хорошо, у меня есть еще один класс, банковский класс, в котором также есть некоторые методы, касающиеся создания учетной записи. Я опубликую это в своем вопросе, возможно, это прояснит ситуацию.   -  person cody1    schedule 30.05.2020
comment
Если вы редактируете свой Java-код с помощью IDE (например, IntelliJ), вы, вероятно, сможете автоматически отформатировать код, чтобы он выглядел красиво, организованно и понятнее. Комбинация горячих клавиш для IntelliJ может быть Ctrl+Shift+Alt+L (см. jetbrains.com /help/idea/reformat-and-rearrange-code.html# ).   -  person MelvinWM    schedule 30.05.2020
comment
если вы новичок в java, есть несколько вещей, которые вы можете сделать, чтобы ваш код выглядел лучше. Импортируйте фреймворк Lombok. Это инструмент времени компиляции, который позволяет вам отказаться от большого количества шаблонного кода. Например, вместо того, чтобы писать свой конструктор, вы можете просто добавить аннотацию поверх класса RequiredArgsConstructor для автоматического создания конструктора. Также не рекомендуется создавать собственный метод print. Вместо этого вы должны переопределить метод toString (или сгенерировать его с помощью ломбока, используя аннотацию @ToString) и позволить потребителю класса распечатать его там, где он хочет.   -  person Kamil Janowski    schedule 30.05.2020
comment
Да, наш профессор заставляет нас использовать блокнот ++ исключительно, я знаю, что форматирование моего кода ужасно, я пытаюсь улучшить это, но запрет на использование какой-либо IDE действительно не помогает.   -  person cody1    schedule 30.05.2020
comment
@Kamil Janowski Ломбок не лишен недостатков. Для более опытных разработчиков я рекомендую ограниченное использование, но для новых разработчиков я не считаю хорошей идеей рекомендовать его без рекомендаций и предупреждений. Например, в некотором смысле, при использовании более продвинутых функций Lombok, Lombok является модификацией языка Java, которая имеет некоторые существенные недостатки.   -  person MelvinWM    schedule 30.05.2020
comment
@KamilJanowski Обычно хорошо переопределять toString, но могут быть случаи, когда предпочтительнее иметь отдельный метод печати (возможно, без побочных эффектов, который просто возвращает строку), например, если вам нужны разные типы вывода в разных ситуациях для того же типа. Это особенно верно, если тип, с которым вы работаете, является скорее классом данных, а не классом с поведением или модулем.   -  person MelvinWM    schedule 30.05.2020
comment
пожалуйста, расскажи мне больше. Что он делает и каковы недостатки? Пользуюсь уже 4 года и проблем не заметил. Единственное, что я заметил, это то, что многие его функции в настоящее время поставляются из коробки с java 14, поэтому его полезность немного снизилась @MelvinWM   -  person Kamil Janowski    schedule 30.05.2020
comment
@MelvinWM вряд ли когда-либо будет хорошим вариантом для собственного метода печати. Насколько вы знаете, ваш класс может использоваться более крупным приложением, которое помещает журналы в 5 разных потоков с 5 разными регистраторами, каждый из которых использует свой формат. На данный момент наличие собственного метода печати означает, что вы никогда даже не увидите свой журнал.   -  person Kamil Janowski    schedule 30.05.2020
comment
@КамильЯновски Рег. Ломбок: Например, взаимодействие reg. другие библиотеки, которые также модифицируют язык Java, а также имеют нестандартный вариант языка Java, что может поднять входной барьер для разработчиков, незнакомых с Lombok. Я бы предположил, что Ломбок делает это лучше, чем большинство, и мне нравится осторожное использование Ломбока. Рег. отдельный метод печати: прошу прощения, я должен был написать отдельную функцию/метод печати, и я имел в виду в дополнение к реализации toString.   -  person MelvinWM    schedule 30.05.2020
comment
@MelvinWM не имеет значения, есть ли у вас метод печати поверх toString. Когда вы вызываете его, вы по-прежнему не можете обеспечить общее форматирование журнала для всего приложения и не можете быть уверены, что он окажется в правильном (если есть) потоке журнала, если вы используете какое-либо решение для ведения журнала (logback/slf4j/log4j/anything )   -  person Kamil Janowski    schedule 30.05.2020
comment
@KamilJanowski Я не имел в виду поверх toString. И есть другие варианты использования, кроме ведения журнала. Да, toString должен быть реализован (вручную или (авто) сгенерирован), но может иметь смысл иметь отдельные методы/функции форматирования. См., например, stackoverflow.com/questions/15718506/ .   -  person MelvinWM    schedule 30.05.2020


Ответы (4)


Извлечь общее место для получения учетной записи

private Acount getAccount(accountNo) {
  if (accountNo >= accounts.length || accounts[accountNo] == null) {
   throw new NoSuchAccountException();
  }
  return account;
}


  boolean deposit(int accountNo, double amount) {
    Account account = getAccount(accountNo);
    return account.deposit(amount);
  }

person Kamil Janowski    schedule 30.05.2020
comment
Хм, хорошо, а как насчет других методов (депозит, снятие средств и т. д.) Вы (если я не ошибаюсь) используете номер счета для выполнения этих операций. Я могу ошибаться, я только новичок. - person cody1; 30.05.2020
comment
Прости. Исправлен мозговой удар. Вы можете просто извлечь эту одну проверку и исключение из 1 общего метода и использовать его во всех методах, для которых требуется учетная запись. - person Kamil Janowski; 30.05.2020
comment
Все круто. Итак, если я правильно понимаю, этот созданный вами метод getAccount проверяет, существует ли учетная запись, и если нет, выдает исключение. И в депозите вы вызвали этот метод (строка Account account = getAccount(accountNo), метод сделал проверку и возврат, и если проверка в порядке (учетная запись существует), возвращаемое значение будет return account.deposit(amount) а если нет программа выкинет исключение? - person cody1; 30.05.2020
comment
Это верно. Таким образом, на этом этапе во всех других методах вы можете считать, что учетная запись существует. Нет необходимости валидировать учетную записьНет в каждом методе отдельно - person Kamil Janowski; 30.05.2020

Это зависит от интерфейса, который вы создаете. В настоящее время в вашем коде есть интерфейс, в котором вы возвращаете false, если учетная запись не найдена или что-то другое не работает. Такая обработка ошибок имеет свои преимущества и недостатки. Один из потенциально ненадежных способов заключается в том, что вызывающий метод(ы) может забыть проверить код возврата, что потенциально может быть очень плохо в этом случае (вызывающий сначала пытается снять деньги, что терпит неудачу, а затем вносит деньги). на другой счет, создавая деньги из ниоткуда).

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

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

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

person MelvinWM    schedule 30.05.2020
comment
Эй, отличный ответ. Я попытаюсь прояснить несколько вещей. Во всех этих методах, где я возвращаю логическое значение false, мне нужно создать исключение, а затем, при необходимости, перехватить его. Это цель задания. Теперь, если я должен проверить в банковском классе или учетной записи, это вопрос, о котором я также думаю. Моя логика заключается в том, что если я проверяю класс учетной записи (который содержит все методы, которые также содержит банковский класс), я мог бы поймать эти исключения в банковском классе. Это просто идея, не уверен, что она имеет смысл - person cody1; 30.05.2020

Я предполагаю, что у вас есть классный банк или что-то в этом роде, и клиент приходит, чтобы сделать что-то со своими деньгами. Итак, он дает вам номер счета, задание и, возможно, сумму денег. Этому классу потребуется массив или список учетных записей. Методы в этом классе были бы правильным местом для вашего исключения. У вас есть методы, в основном такие же, как и в вашей учетной записи. Сначала они проверяют, существует ли учетная запись в массиве/списке, а затем вызывают метод для выбранной учетной записи или выдают исключение, если она не существует.

метод против функции: в моем понимании методы и функции одинаковы, за исключением одной небольшой разницы: функция — это функция в глобальном пространстве, тогда как метод — это функция, привязанная к классу или объекту. Таким образом, в Java нет реальных функций. Но в моем понимании каждый статический метод — это функция, но привязанная к пространству имен класса. Но это больше практическая, чем теоретическая точка зрения.

person Jochen    schedule 30.05.2020
comment
Хм, я опубликовал класс банковского дела. Думаю, мне нужно добавить его в метод создания учетной записи. Но как мне проверить, существует ли номер учетной записи? - person cody1; 30.05.2020
comment
в настоящее время номер вашего счета представляет собой простое целое число, и если вы проверите номер счета в банке, это будет просто индекс, но не реальный номер счета. Номер вашей учетной записи должен быть уникальным идентификатором (см., например, java.Lang.Object.hashCode(), как его создать). Затем вам нужно увидеть в каждом методе, существует ли это число в вашем массиве, как вы сейчас делаете это с индексом. вместо возврата false вы бы выдали исключение, если учетная запись с таким номером не существует. Используйте ID вместо простого номера. РЕДАКТИРОВАТЬ: и подумайте о хранении данных в HashMap для более быстрого доступа. - person Jochen; 30.05.2020
comment
Привет! Да, я понял это. В основном во всех других методах, кроме создания учетной записи, может быть выдано исключение (депости, перевод, снятие средств, получение баланса). Теперь, когда с HashMap я действительно не могу этого сделать, потому что мы еще не рассмотрели это в классе, и в задании говорится только об обработке исключений. Теперь, поскольку у меня есть 4 метода, такое исключение может быть выброшено, возможно, создание метода, который будет делать проверка этих 4 и исключение, так что мне не нужно создавать исключение в 4 разных местах. что-то вроде checkAccountNumber (int)? Будет ли что-то подобное работать. Спасибо - person cody1; 30.05.2020
comment
действительно, это был бы хороший дизайн - person Jochen; 31.05.2020

Создайте метод в классе учетной записи, который принимает номер учетной записи и возвращает true, если учетная запись присутствует, в противном случае — false. Вы можете вызывать этот метод из методов депозита или вывода средств и продолжать работу только тогда, когда он возвращает значение true, в противном случае генерируется исключение NoSuchAccountException.

person Kalyani    schedule 30.05.2020