0

I have this class Account

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

Now I also have this exception that I wrote

    public class NoSuchAccountException extends AccountException {

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

Now I need to throw this exception in the class account,when the searched account number does not exist.Now my question is in which method(or function I think that is the same,please correct me if I'm wrong) do I throw this exception.And after what check.How would I check if the account number exist,and if it doesnt I'll throw this exception. Thank you!

EDIT: The class banking, to complete the program

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);
  }
}
MelvinWM
  • 749
  • 4
  • 13
cody1
  • 95
  • 7
  • 1
    Where are you searching for account? – Thiyagu May 30 '20 at 13:12
  • Hey! I am not quite sure I understand what you are asking. Do you mean what part of the code is trying to find account numbers, or something else? – cody1 May 30 '20 at 13:15
  • 1
    yeah. You're showing us the account class, but it's not the account class that searches for the account. It's the method that searches for the account that should be throwing the exception – Kamil Janowski May 30 '20 at 13:16
  • the concept of "methods" and "functions" comes originally from C++ that does have both. Method = function in a class. So in Java technically everything is a method. In practise however nobody really cares whether you call them functions or methods – Kamil Janowski May 30 '20 at 13:17
  • Hmmm okay, well I have another class, a class banking that also has some methods, regarding account creation.I'll post it in my question maybe it will clear things up. – cody1 May 30 '20 at 13:18
  • 1
    If you are editing your Java code with an IDE (for instance IntelliJ), you will likely be able to automatically format the code such that it looks nice and organized and is clearer. The hotkey combination for IntelliJ might be `Ctrl+Shift+Alt+L` (see https://www.jetbrains.com/help/idea/reformat-and-rearrange-code.html# ). – MelvinWM May 30 '20 at 13:21
  • if you're new to java, there are also a few things that you can do to make your code look nicer. Import the Lombok framework. It's a compile-time tool that allows you to drop a lot of boiler-plate code. For instance instead of writing your constructor, you could just have an annotation on top of the class `RequiredArgsConstructor` to auto-generate the constructor. Also it's a bad practise to create your custom `print` method. Instead you should override the toString method (or generate it with lombok using the `@ToString` annotation) and let the consumer of the class print it wherever he wants – Kamil Janowski May 30 '20 at 13:22
  • 1
    Yea our professor is forcing us to use notepad++ exclusivly,I know that my code formatting is god awful,I'm trying to improve on that but not allowing any IDE to be used is really not helping – cody1 May 30 '20 at 13:23
  • @Kamil Janowski Lombok is not without its drawbacks. For more experienced developers, I do recommend limited usage of it, but for new developers, I don't consider it a good idea to recommend it without guidance and warnings. For instance, in some ways when using the more advanced features of Lombok, Lombok is a modification of the Java language, which has some significant drawbacks. – MelvinWM May 30 '20 at 13:25
  • @KamilJanowski It is generally good to override `toString`, but there can be cases where having a separate printing method (maybe one without side-effects that just returns a string) can be preferable, for instance if you want different output kinds in different situations for the same type. This is especially true if the type you are working with is more a data class and less a class with behaviour or a module. – MelvinWM May 30 '20 at 13:28
  • please, tell me more. What does it do and what are the drawbacks? I've been using it for the past 4 years and I haven't noticed any issues. The only thing I noticed is that a lot of its features nowadays come out of the box with java 14 hence its usefulness has dropped a bit @MelvinWM – Kamil Janowski May 30 '20 at 13:28
  • @MelvinWM that is hardly ever a good option to have your own printing method. For all you know your class might be consumed by a larger application that puts logs into 5 different streams with 5 different loggers, each using a different format. At this point having your own print method means you will never even get to see your log – Kamil Janowski May 30 '20 at 13:30
  • @KamilJanowski Reg. Lombok: For instance interaction reg. other libraries that also modify the Java language, as well as having a "non-standard" variant of the Java language that may raise the barrier to entry for developers unfamiliar with Lombok. I would assume that Lombok does it better than most, and I do like careful usage of Lombok. Reg. separate printing method: I apologize, I should have written "separate printing function/method", and I meant in addition to a `toString` implementation. – MelvinWM May 30 '20 at 13:34
  • @MelvinWM it doesn't matter if you have the printing method on top of the `toString`. When you call it, you still cannot ensure the common log formatting across the application and you cannot make sure that it ends up in the right (if any) log stream if you're using any logging solution (logback/slf4j/log4j/anything) – Kamil Janowski May 30 '20 at 13:37
  • @KamilJanowski I did not mean on top of the `toString`. And there are other use cases than logging. Yes, `toString` should be implemented (manually or (auto-)generated), but it can make sense to have separate formatting methods/functions. See for instance https://stackoverflow.com/questions/15718506/scala-how-to-print-case-classes-like-pretty-printed-tree . – MelvinWM May 30 '20 at 13:42

4 Answers4

1

It depends on the interface you create. You currently have an interface in your code where you return false if the account is not found or something other fails. That kind of error handling has benefits and drawbacks. One way that is potentially fragile is that the caller of the method(s) might forget to check the return code, which could be potentially very bad for this case (the caller first attempts to withdraw some money, which fails, and then deposits money into another account, creating money out of nowhere).

There are arguments for and against. An alternative way of doing error handling would be to throw exceptions instead of returning a boolean for error handling - that would have its own benefits and drawbacks. In Java, if you ensure it is a checked exception, the caller would be forced to catch or throw the exception as part of the type system. In any case, I don't know how I feel about mixing the two ways of handling errors, since that might be very error prone and confusing.

If you go along with the exception way of handling errors, one common refactoring might be to have a private method called checkOrThrowAccountMustExist, that takes an account ID as input and throws if it does not exist.

There is also the issue of whether to place the checks in the Banking class and/or in the Account class. My own feeling would be that it may make sense to include at least some checks in both, and that it would be a good idea to include checks in those classes that are exposed externally or to other parts of your program (and document if a class is not meant to be used outside a small part of your program). But this may or may not be outside the scope of your assignment.

MelvinWM
  • 749
  • 4
  • 13
  • 1
    Hey great answer. I'll attempt to clear a few things. In all of these methods where I return boolean value false, I need to throw an exception, and later if needed catch it. That is the goal of the assingment. Now if I should check in Banking class or Account is a question that I'm also thinking about.My I guess "logic" is if I check in the Account class (which contains all the methods the banking class also contains) I could catch those exceptions in the Banking class.Its just an idea not sure if it makes a lot of sense – cody1 May 30 '20 at 14:09
0

I'd guess you have a class Bank or the like and a customer comes to do something with his money. So he gives you an account number, a task and maybe an amount of money. This class would need an Array or List of Accounts. The methods in this class would be thew right place for your Exception. You than have methods, basically the same as in your account. They first check if the Account exists in the array / list and then call the method on the chosen account or throw the exception if it doesn't exist.

method vs function: In my understanding methods and functions are the same except for one little difference: a function is a function in global space, whereas a method is a function bound to a class or an object. Thus Java doesn't have real functions. But in my understanding, every static method is a function, but bound to the namespace of a class. But that is more a practical than a theoretical point of view.

Jochen
  • 193
  • 1
  • 8
  • Hmmm,I've posted the Banking class.My guess is that I need to throw it at the create account method.But how would I check if the account number exists? – cody1 May 30 '20 at 13:28
  • currently your account number is just a simple int and if you check a bank for account number, it's just an index - but no real account number. Your account number should be a unique ID (see for example java.Lang.Object.hashCode() how to create one). You than need to see in every method, if that number exists in your array, as you currently do it with the index. instead of returning false you'd throw the exception, if no account with that number exists. Use ID instead of simple number. EDIT: and think about storing data in a HashMap for faster access. – Jochen May 30 '20 at 13:36
  • Hello! Yes I've realized that.Basically in all all other methods except the create account the exception could be thrown (deposti,transfer,withdrawal,getbalance). Now that with HashMap I really cant do because we haven't covered that in class yet and the assingment says is only about exception handeling.Now since I've got 4 methods that such an exception can be thrown maybe creating an method that will do the checking of these 4 and throw the exception,so that I dont have to throw the exception at 4 diffrent places. something like checkAccountNumber(int)? Would something like that work. Thanks – cody1 May 30 '20 at 13:50
  • indeed that would be a nice design – Jochen May 31 '20 at 07:42
0

Extract the common place for acquiring the account

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

Kamil Janowski
  • 1,872
  • 2
  • 21
  • 43
  • Hmm okay, but what about the other methods (deposit,withdraw...etc) You are (If I'm not mistaken) using the account number to do these operations. I could be wrong I'm only a beginner. – cody1 May 30 '20 at 13:52
  • sorry. A brainfart fixed now. You can just extract this one check and exception to 1 common method and use that in all methods that require the account – Kamil Janowski May 30 '20 at 13:56
  • All cool. So if I'm getting this right this getAccount method you created checks if the account exists and if not throws the exception. And in deposit you called this method (the Account account = getAccount(accountNo) line, the method did the check, and the return and if the check is okay (the account exists) the return value will be return account.deposit(amount) and if not the program will throw the exception? – cody1 May 30 '20 at 14:05
  • That is correct. So at this point in all other methods you can assume that the account is there. No need to validate the accountNo in every method separately – Kamil Janowski May 30 '20 at 15:26
0

Create a method in account class which accepts account number and return true if account is present otherwise false. You can call this method from deposit or withdraw methods and proceed only when it returns true otherwise throw NoSuchAccountException.

Kalyani
  • 11
  • 1