I have a program nearly complete - it creates a bank object which creates within it customers and accounts of multiple types and can successfully load this information to display on the screen. The problem is that I am now trying to deposit or withdraw a given balance which has already been created, but I am unable to because "Non-Static Method Cannot be referenced from static context." which I know generally means that the instance has not been created yet, but in this case it has. It's just that I can't seem to do anything with it and I don't know why.
Here's what I have so far. It compiles and it runs. It's just the processTransactionsInFile() method in the Main.java class which is incomplete. (see line 247 of Main.ajava - I commented out the portions giving me trouble) oh, and the withdraw/deposit methods are in Account.java. I have been wracking my head on this for a few days and could really use some direction at least. Since I am not sure where my problem is I am posting the entire intact program code below:
Main.java class:
package mp04;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main
{
private final static String INPUT_ACCOUNT_FILE = "accountInfo.txt";
private final static String INPUT_TRANSACTIONS_FILE = "transactions.txt";
// If I don't initialize the bank object at the class level it won't be accessible by the other methods.
protected static Bank bank = new Bank();
public static void main(String[] args)
{
// I used the following to trouble shoot file names and location.
// File file = new File(".");
// for(String fileNames : file.list()) System.out.println(fileNames);
// Open file
try
{
loadAccountInformationFromFile();
}
catch (Exception e)
{
System.err.println("error: " + e.getMessage());
System.exit(1);
}
try
{
processTransactionsInFile();
}
catch (Exception e)
{
System.err.println("error: " + e.getMessage());
System.exit(1);
}
displayBankRecords();
// System.out.printf("%s\n%s\n%s", "Customer list:","--------------", bank.customerList());
// System.out.println("");
// System.out.printf("%s\n%s\n%s", "Account list:","-------------", bank.accountList());
// System.out.printf("\n%s\n%s\n%s", "Bank record:","------------", bank);
// System.out.println("");
}
protected static void loadAccountInformationFromFile() throws Exception
{
// These correspond with the positions of the contents of the text file.
// This is based on the knowledge that each line has only 5 values,
// but in practice I could easily add an additional variable with an
// additional number value and it would definately work.
// They may be the same, but setting them differently allows me some
// versatility in future edits.
final int ACCOUNT_NUMBER = 0;
final int FIRST_NAME = 1;
final int LAST_NAME = 2;
final int BALANCE = 3;
final int LAST_VARIABLE = 4;
final int ACCOUNT_NUMBER_COUNT = 0;
final int FIRST_NAME_COUNT = 1;
final int LAST_NAME_COUNT = 2;
final int BALANCE_COUNT = 3;
final int LAST_VARIABLE_COUNT = 4;
List<String> accountNumbers = new ArrayList<>();
List<String> firstNames = new ArrayList<>();
List<String> lastNames = new ArrayList<>();
List<String> balances = new ArrayList<>();
List<String> lastVariables = new ArrayList<>();
try (Scanner account = new Scanner(new File(INPUT_ACCOUNT_FILE)))
{
do {
String[] temp1 = account.next().split(",");
if (ACCOUNT_NUMBER_COUNT == ACCOUNT_NUMBER)
{
accountNumbers.add(temp1[ACCOUNT_NUMBER]);
}
if (FIRST_NAME_COUNT == FIRST_NAME)
{
firstNames.add(temp1[FIRST_NAME]);
}
if (LAST_NAME_COUNT == LAST_NAME)
{
lastNames.add(temp1[LAST_NAME]);
}
if (BALANCE_COUNT == BALANCE)
{
balances.add(temp1[BALANCE]);
}
if (LAST_VARIABLE_COUNT == LAST_VARIABLE)
{
lastVariables.add(temp1[LAST_VARIABLE]);
}
} while (account.hasNext());
}
// Given the above logic, each ArrayList would have to be the same size.
int arraySize = lastVariables.size();
// Given that the Checking Account class has a definate boolean value
// whereas the Savings Account class requires a double which can be
// anything I can use the boolean to sort the data being sent to bank.
for (int i=0; i < arraySize; i++)
{
// Alternatively, I could have focused on the fact that a 1
// seems to prefix a checking account while a 2 is for savings.
if (("N".equals(lastVariables.get(i))) || ("Y".equals(lastVariables.get(i))))
{
// convert the String ArrayLists to the correct variable types to be
// accepted by the Bank class without changing it.
String accountNumberString = accountNumbers.get(i);
int accountNumberInt = Integer.parseInt(accountNumberString);
String firstNameString = firstNames.get(i);
String lastNameString = lastNames.get(i);
String balanceString = balances.get(i);
double balanceDouble = Double.parseDouble(balanceString);
String lastVariableString = lastVariables.get(i);
// Initialize boolean as anything to avoid compiler error
boolean freeChecks = true;
if (lastVariableString == "N")
{
freeChecks = Boolean.parseBoolean("false");
}
else
{
freeChecks = Boolean.parseBoolean("true");
}
bank.openAccount(new CheckingAccount(accountNumberInt, new Customer(firstNameString, lastNameString),balanceDouble,freeChecks));
}
else
{
// convert the String ArrayLists to the correct variable types to be
// accepted by the Bank class without changing it.
String accountNumberString = accountNumbers.get(i);
int accountNumberInt = Integer.parseInt(accountNumberString);
String firstNameString = firstNames.get(i);
String lastNameString = lastNames.get(i);
String balanceString = balances.get(i);
double balanceDouble = Double.parseDouble(balanceString);
String lastVariableString = lastVariables.get(i);
double interestDouble = Double.parseDouble(lastVariableString);
bank.openAccount(new SavingsAccount(accountNumberInt, new Customer(firstNameString, lastNameString),balanceDouble,interestDouble));
}
}
// Used the following to test to make sure that the ArrayLists work:
// System.out.println(accountNumbers.get(0));
// System.out.println(firstNames.get(4));
}
// Add the method void processTransactionsInFile(). This void method declares that it
//throws an Exception object, which the caller (main()) will handle. This method will open the
//input file, transactions.txt, and process each transaction.
protected static void processTransactionsInFile() throws Exception
{
final int ACCOUNT_NUMBER_COUNT = 1;
final int TRANSACTION_COUNT = 0;
final int ACCOUNT_NUMBER = 1;
final int TRANSACTION = 0;
List<String> transactionList = new ArrayList<>();
List<String> accountNumberList = new ArrayList<>();
try (Scanner transactions = new Scanner(new File(INPUT_TRANSACTIONS_FILE)))
{
do {
String[] temp1 = transactions.next().split(",");
if (ACCOUNT_NUMBER_COUNT == ACCOUNT_NUMBER)
{
transactionList.add(temp1[ACCOUNT_NUMBER]);
}
if (TRANSACTION_COUNT == TRANSACTION)
{
accountNumberList.add(temp1[TRANSACTION]);
}
} while (transactions.hasNext());
}
// test:
System.out.println(accountNumberList.get(1));
System.out.println(accountNumberList.get(2));
int arraySize = transactionList.size();
for (int i=0; i < arraySize; i++)
{
String transactionString = transactionList.get(i);
double transactionDouble = Double.parseDouble(transactionString);
String accountNumberString = accountNumberList.get(i);
int accountNumberInt = Integer.parseInt(accountNumberString);
// bank.getAccountWithNumber(accountNumberInt);
System.out.println(transactionDouble);
if (transactionDouble < 0)
{
// This doesn't work
//Account.withdraw(transactionDouble);
}
else
{
//Account.deposit(transactionDouble);
}
}
// Used the following to test to make sure that the ArrayLists work:
// System.out.println(transactionList.get(1));
}
private static void displayBankRecords()
{
System.out.printf("%s\n%s\n%s\n%s", "Bank Record:","--------------", "Customers:(" + bank.getCustomerSize() + ") " , bank.customerList());
System.out.println("");
System.out.printf("%s\n%s\n%s\n%s", "Account list:","-------------", "Accounts:(" + bank.getAccountSize() + ") " , bank.accountList());
}
}
Bank.java class:
package mp04;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Bank
{
private List<Customer> customers = new ArrayList<>();
private List<Account> accounts = new ArrayList<>();
public int getCustomerSize()
{
return customers.size();
}
public int getAccountSize()
{
return accounts.size();
}
public Customer getCustomerAtIndex(int index)
{
return customers.get(index);
}
public Account getAccountAtIndex(int index)
{
return accounts.get(index);
}
public Account getAccountWithNumber(int accountNumber)
{
return accounts.get(accountNumber);
}
public void addCustomer(Customer o)
{
//Each time this method is called it will add to the array
customers.add(o);
}
// Added the addAccount() method when dynamic arrays are used.
// Need to remove addAccount() for the new UML
private void addAccount(Account o)
{
//Each time this method is called it will add to the array
accounts.add(o);
}
public void openAccount(Account o)
{
addAccount(o);
// I needed an extra boolean in order to make use of the .equals() method.
// there were too many errors as it was and not enough example in the book.
boolean compare = true;
for(int i = 0; i < customers.size(); i++)
{
if (o.getOwner().equals(getCustomerAtIndex(i)) == true)
{
compare = false;
}
}
if (compare == true)
{
addCustomer(o.getOwner());
}
}
public String customerList()
{
String list = Arrays.toString(customers.toArray()).replace(", O", "O").replace(", O", "O");
return list.substring(1,list.length()-1);
// Using just the following causes brackets to appear
// return list;
// The following approach removed the brackets, but there were still extra commas
// return list.substring(1,list.length()-1);
// The following approach removed the extra commas, but also removed the commas I wanted so I couldn't use it
// String list = Arrays.toString(customers.toArray()).replace(",", "").replace(",", "");
// In order to make it work without using StringBuilder I focused on the fact that each line starts with N and made it work that way.
// However, I consider this to be a poor approach. If the toString() class in Customer.java is changed the code will break so I am notating there
}
public String accountList()
{
String account = Arrays.toString(accounts.toArray()).replace(", [", "[").replace(", [", "[");
return account.substring(1,account.length()-1);
}
@Override
public String toString()
{
return "Customers(" + customers.size() + ")\n" + customerList() + "\n" +
"Accounts(" + accounts.size() + ")\n" + accountList();
}
}
Customer.Java class:
package mp04;
import java.util.Objects;
public class Customer
{
private String first;
private String last;
public Customer(String first, String last)
{
setFirst(first);
setLast(last);
}
public final String getFirst() { return first; }
public final String getLast() { return last; }
public String getName()
{
return getLast() + ", " + getFirst();
}
public final void setFirst(String first)
{
this.first = first;
}
public final void setLast(String last) { this.last = last; }
@Override
public int hashCode()
{
int hash = 7;
hash = 37 * hash + Objects.hashCode(this.first);
hash = 37 * hash + Objects.hashCode(this.last);
return hash;
}
@Override
public boolean equals(Object name)
{
if (name == null) {
return false;
}
if (getClass() != name.getClass()) {
return false;
}
final Customer other = (Customer) name;
if (!Objects.equals(this.first, other.first)) {
return false;
}
if (!Objects.equals(this.last, other.last)) {
return false;
}
return true;
}
@Override
public String toString()
{
// CAUTION: The Bank.java class depends on this return starting with O amd emdomg with "\n"
// If this changes be sure to change the customerList() method in Bank.java class accordingly.
return "Owner: " + getName() + "\n";
}
}
Account.java class:
package mp04;
// Note: The Account class is a super class. I don't need getters and setters
// in any account type for this reason.
import java.text.DateFormat;
import java.util.Date;
public class Account
{
private int accountNumber;
private Date dateOpened;
private Customer owner;
private double currentBalance;
// For my own future reference: # in UML means protected
protected Account(int accountNumber, Customer owner, double currentBalance)
{
setDateOpened(new Date());
setAccountNumber(accountNumber);
setOwner(owner);
setCurrentBalance(currentBalance);
}
public int getAccountNumber() { return accountNumber; }
public Customer getOwner() { return owner; }
public double getCurrentBalance() { return currentBalance; }
private void setAccountNumber(int accountNumber) { this.accountNumber = accountNumber; }
private void setOwner(Customer owner) { this.owner = owner; }
private void setCurrentBalance(double currentBalance) { this.currentBalance = currentBalance; }
//Note to self: The UML for this line was
//
// +withdraw(amount: double): double
//
public double withdraw(double amount)
{
setCurrentBalance(currentBalance - amount);
return currentBalance;
}
public double deposit(double amount)
{
setCurrentBalance(currentBalance + amount);
return currentBalance;
}
public Date getDateOpened() { return dateOpened; }
private void setDateOpened(Date dateOpened) { this.dateOpened = dateOpened; }
@Override
public String toString()
{
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);
// CAUTION: The Bank.java class depends on this return starting with [ amd emdomg with "\n"
// If this changes be sure to change the accountList() method in Bank.java class accordingly.
return "[" + getAccountNumber() + "], " +
"Opened: " + df.format(getDateOpened()) +
", " + owner +
"Balance: $" + currentBalance;
}
}
CheckingAccoung.java class:
package mp04;
public class CheckingAccount extends Account
{
private boolean freeChecks;
private String freeChecksValue = "";
public CheckingAccount(int accountNumber, Customer owner, double currentBalance, boolean freeChecks)
{
super(accountNumber, owner, currentBalance);
// This is the accessor
this.freeChecks = freeChecks;
}
@Override
public String toString()
{
if (freeChecks == true)
{
freeChecksValue = "Yes";
}
else
{
freeChecksValue = "No";
}
return super.toString() + ", " + "Free Checks: " + freeChecksValue + "\n\n";
}
}
SavingsAccount.java class:
package mp04;
public class SavingsAccount extends Account
{
private double interestRate;
public SavingsAccount(int accountNumber, Customer owner, double currentBalance, double interestRate)
{
super(accountNumber, owner, currentBalance);
// This is the accessor:
this.interestRate = interestRate;
}
private void setInterestRate(double interestRate)
{
this.interestRate = interestRate;
}
public double getInterestRate()
{
return interestRate;
}
@Override
public String toString()
{
return super.toString() + ", " + "Interest Rate: " + interestRate + "%\n\n";
}
}
accountInfo.txt :
10100,Adam,Apple,500.00,N
10101,Breatrice,Bagel,2000.00,Y
20100,Chris,Cucumber,5000.00,0.02
20101,David,Dakon,3500.00,0.02
10102,Ethel,Endame,1000.00,Y
20103,Adam,Apple,6000.00,0.02
transactions.txt :
10100,500.00
10101,-250.00
20100,450.00
20101,-100.00
10102,-300.00
20103,1000.00
The above runs and shows the following output (where everything before the Bank Account label in the text is just tests to verify I am collecting the data from the transactions file properly) :
run:
10101
20100
500.0
-250.0
450.0
-100.0
-300.0
1000.0
Bank Record:
--------------
Customers:(5)
Owner: Apple, Adam
Owner: Bagel, Breatrice
Owner: Cucumber, Chris
Owner: Dakon, David
Owner: Endame, Ethel
Account list:
-------------
Accounts:(6)
[10100], Opened: Oct 2, 2015 12:26 PM, Owner: Apple, Adam
Balance: $500.0, Free Checks: Yes
[10101], Opened: Oct 2, 2015 12:26 PM, Owner: Bagel, Breatrice
Balance: $2000.0, Free Checks: Yes
[20100], Opened: Oct 2, 2015 12:26 PM, Owner: Cucumber, Chris
Balance: $5000.0, Interest Rate: 0.02%
[20101], Opened: Oct 2, 2015 12:26 PM, Owner: Dakon, David
Balance: $3500.0, Interest Rate: 0.02%
[10102], Opened: Oct 2, 2015 12:26 PM, Owner: Endame, Ethel
Balance: $1000.0, Free Checks: Yes
[20103], Opened: Oct 2, 2015 12:26 PM, Owner: Apple, Adam
Balance: $6000.0, Interest Rate: 0.02%
However, the desired expected output after properly withdrawing/depositing transactions shows a different balance.