Banking System
Part of the Object Oriented Programming section of Coddy's Java journey — lesson 85 of 87.
This challenge tasks you with building a Banking System that models real-world financial operations using OOP principles.
Your system should handle different account types like SavingsAccount and CheckingAccount, both extending a base Account class. Each account type has unique behaviors: savings accounts might earn interest, while checking accounts could have overdraft protection.
Think about how to model transactions. An interface like Transactable could define methods for deposit() and withdraw(). Consider using custom exceptions such as InsufficientFundsException to handle invalid operations gracefully.
A Bank class might manage multiple accounts and customers, demonstrating composition. You could apply the Factory pattern to create different account types, or use the Observer pattern to notify customers of account changes.
Focus on encapsulation to protect sensitive data like balances and account numbers, and use polymorphism to process different account types uniformly.
Challenge
EasyLet's build a complete Banking System that demonstrates your mastery of OOP principles! You'll create a system with different account types, transaction handling, and proper exception management—all organized across multiple files.
You'll organize your code across seven files:
Transactable.java: Create an interface that defines the contract for financial operations. It should declare methodsdeposit(double amount)andwithdraw(double amount), both returning a boolean to indicate success.InsufficientFundsException.java: Create a custom exception that extendsException. The constructor should accept the attempted withdrawal amount and current balance, creating a message in the formatInsufficient funds: attempted [amount], available [balance].Account.java: Create an abstract base class representing any bank account. Include private fields foraccountNumber(String) andbalance(double), a constructor that initializes both, appropriate getters, a protected setter for balance (so subclasses can modify it), and an abstract methodgetAccountType()that returns a String. Implement agetDetails()method that returns"[accountNumber] ([accountType]): $[balance]"with balance formatted to 2 decimal places.SavingsAccount.java: Create a class that extendsAccountand implementsTransactable. Add a private field forinterestRate(double). The constructor takes accountNumber, initial balance, and interestRate. ImplementgetAccountType()to return"Savings". Fordeposit(), add the amount to balance and return true. Forwithdraw(), if the amount exceeds balance, return false; otherwise subtract and return true. Add a methodapplyInterest()that increases the balance by the interest rate percentage.CheckingAccount.java: Create a class that extendsAccountand implementsTransactable. Add a private field foroverdraftLimit(double). The constructor takes accountNumber, initial balance, and overdraftLimit. ImplementgetAccountType()to return"Checking". Fordeposit(), add the amount and return true. Forwithdraw(), allow withdrawal if amount is less than or equal to balance plus overdraftLimit; return false if it exceeds this limit.Bank.java: Create a class that manages accounts using an ArrayList. Include methods:addAccount(Account account)- adds an account to the bankfindAccount(String accountNumber)- returns the Account or null if not foundtransfer(String fromAccount, String toAccount, double amount)- transfers money between accounts, throwingInsufficientFundsExceptionif the source account has insufficient funds. On success, return"Transferred $[amount] from [fromAccount] to [toAccount]"getTotalDeposits()- returns the sum of all account balances
Main.java: Build your banking system! You'll receive a comma-separated string of commands:SAVINGS:accountNumber:balance:interestRateCHECKING:accountNumber:balance:overdraftLimitDEPOSIT:accountNumber:amountWITHDRAW:accountNumber:amountTRANSFER:fromAccount:toAccount:amountINTEREST:accountNumber
Process each command and print:
- SAVINGS/CHECKING:
Account created: [accountNumber] - DEPOSIT:
Deposited $[amount] to [accountNumber] - WITHDRAW:
Withdrew $[amount] from [accountNumber]on success, orWithdrawal failed: [accountNumber] - TRANSFER: Print the success message or
Transfer failed: [exception message] - INTEREST:
Interest applied to [accountNumber]
After all commands, print
--- Bank Summary ---followed by each account's details (usinggetDetails()) and finallyTotal deposits: $[total]formatted to 2 decimal places.
You will receive one input: the comma-separated command string.
For example, with input SAVINGS:SAV001:1000.00:0.05,CHECKING:CHK001:500.00:200.00,DEPOSIT:SAV001:250.00,WITHDRAW:CHK001:600.00,TRANSFER:SAV001:CHK001:100.00,INTEREST:SAV001, your output would be:
Account created: SAV001
Account created: CHK001
Deposited $250.00 to SAV001
Withdrew $600.00 from CHK001
Transferred $100.00 from SAV001 to CHK001
Interest applied to SAV001
--- Bank Summary ---
SAV001 (Savings): $1207.50
CHK001 (Checking): $0.00
Total deposits: $1207.50Notice how the checking account allows the $600 withdrawal despite only having $500 balance—that's the overdraft protection in action! The savings account earns 5% interest on its balance after the transfer. This challenge combines inheritance, interfaces, polymorphism, custom exceptions, and encapsulation into a realistic banking application!
Cheat sheet
A Banking System demonstrates OOP principles through account management, transactions, and exception handling.
Interfaces for Contracts
Define common operations using interfaces:
public interface Transactable {
boolean deposit(double amount);
boolean withdraw(double amount);
}Custom Exceptions
Create custom exceptions for domain-specific errors:
public class InsufficientFundsException extends Exception {
public InsufficientFundsException(double attempted, double available) {
super("Insufficient funds: attempted " + attempted + ", available " + available);
}
}Abstract Base Classes
Use abstract classes to define common structure with abstract methods for subclass-specific behavior:
public abstract class Account {
private String accountNumber;
private double balance;
public abstract String getAccountType();
protected void setBalance(double balance) {
this.balance = balance;
}
}Inheritance and Polymorphism
Subclasses extend base classes and implement interfaces:
public class SavingsAccount extends Account implements Transactable {
private double interestRate;
@Override
public String getAccountType() {
return "Savings";
}
public void applyInterest() {
setBalance(getBalance() * (1 + interestRate));
}
}Composition
Classes can manage collections of other objects:
public class Bank {
private ArrayList<Account> accounts;
public void addAccount(Account account) {
accounts.add(account);
}
public Account findAccount(String accountNumber) {
// Search and return account or null
}
}Encapsulation
Protect sensitive data with private fields and controlled access through getters/setters. Use protected modifiers to allow subclass access while maintaining encapsulation.
Exception Handling in Transactions
Throw custom exceptions for invalid operations:
public String transfer(String from, String to, double amount) throws InsufficientFundsException {
if (!fromAccount.withdraw(amount)) {
throw new InsufficientFundsException(amount, fromAccount.getBalance());
}
toAccount.deposit(amount);
return "Transferred $" + amount;
}Try it yourself
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: Create a Bank instance
// TODO: Split input by comma to get individual commands
// TODO: Process each command:
// - SAVINGS:accountNumber:balance:interestRate -> Create SavingsAccount, print "Account created: [accountNumber]"
// - CHECKING:accountNumber:balance:overdraftLimit -> Create CheckingAccount, print "Account created: [accountNumber]"
// - DEPOSIT:accountNumber:amount -> Deposit and print "Deposited $[amount] to [accountNumber]"
// - WITHDRAW:accountNumber:amount -> Withdraw and print success or "Withdrawal failed: [accountNumber]"
// - TRANSFER:fromAccount:toAccount:amount -> Transfer and print success or "Transfer failed: [exception message]"
// - INTEREST:accountNumber -> Apply interest and print "Interest applied to [accountNumber]"
// TODO: After all commands, print "--- Bank Summary ---"
// TODO: Print each account's details using getDetails()
// TODO: Print "Total deposits: $[total]" formatted to 2 decimal places
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsFields (Attributes)Constructor MethodConstructor OverloadingRecap - Simple Calculator4Inheritance
Basic Inheritance (extends)The super KeywordMethod Overriding (@Override)Constructor ChainingThe Object ClassSingle & Multilevel InheritWhy No Multi Class InheritRecap - Employee Hierarchy7Special Methods & Object Class
toString() Methodequals() and hashCode()clone() MethodcompareTo() and ComparableComparator InterfaceRecap - Custom Sorting2Access Modifiers & Encapsulate
Access Levels OverviewGetter and Setter MethodsInformation HidingThe final KeywordRecap - Bank Account Manager5Polymorphism
Method Overloading BasicsMethod Overriding (Run-Time)Upcasting and DowncastingThe instanceof OperatorAbstract Classes and MethodsRecap - Shape Calculator8Advanced OOP Concepts
Composition vs InheritanceAggregation vs CompositionInner Nested & Anonymous ClassEnums and Enum MethodsRecords (Java 16+)Sealed Classes (Java 17+)3Class Props & Static Member
Instance vs Static VariablesStatic MethodsStatic BlocksConstants (static final)Recap - Counter & Utility6Interfaces & Abstract Classes
Introduction to InterfacesImplementing InterfacesMulti Interface ImplemenDefault & Static in InterfaceAbstract Classes vs InterfacesFunctional InterfacesRecap - Payment System