The question :
Input file: customer’s account number, account balance at beginning of month, transaction type (withdrawal, deposit, in
This is how I would proceed:
You might not know how to use your debugger yet, and while some might not agree, I think it's never too early. There are some excellent video tutorials on how to use the debugger here. Good luck!
I don't particularly like the design, all in one, as it goes against the strengths of Java, a bit of object orientation. So I rewrote the program along the lines I think.
I also figured out that interpreting doubles is locale dependent, on my machine a double (in a string) should have a comma (12,12) and not a point (12.12), so that may be your problem.
And as said by polygenelubricants, member and method names are lower cased in Java, only types use Capitalization.
I added my own implementation not because yours didn't work, but to show how you could delegate responsibilities to classes which reflect the problem domain, making the code a bit more readable (though considerably longer with boilerplate getters and setters).
My implementation of your program would be something like:
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.Scanner;
public class Ex7 {
/**
* One transaction record in the file Should be format "int double\n"
* Note that interpreting a double is locale dependent, on my machine
* I need "12,24" whereas a US locale might require "12.24"
*/
public static class Transaction {
double amount;
int type; // Prefer an enum here...
public void read(Scanner scanner) {
setAmount(scanner.nextDouble());
setType(scanner.nextInt());
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
@Override
public String toString() {
return String.format("Transaction(type=%d, amount=%.2f)", type, amount);
}
}
/**
* Account information and processing Account file format: Line 1
* "int double\n" account number start balance Line 2-... "double int\n"
* transaction amount transaction type.
* Type 1=deposit, 2=interest
* 3=withdrawal
*/
public static class Account {
int accountNum;
double startBalance;
double currentBalance;
double totalDeposited;
double totalWithdrawn;
double totalInterestPaid;
int numberOfDeposits;
int numberOfWithdrawals;
int numberOfInterestPayments;
public Account(Scanner scanner) {
read(scanner);
}
private void read(Scanner scanner) {
setAccountNum(scanner.nextInt());
setStartBalance(scanner.nextDouble());
setCurrentBalance(getStartBalance());
}
public int getAccountNum() {
return accountNum;
}
public void setAccountNum(int accountNum) {
this.accountNum = accountNum;
}
public double getStartBalance() {
return startBalance;
}
public void setStartBalance(double startBalance) {
this.startBalance = startBalance;
}
public double getCurrentBalance() {
return currentBalance;
}
public void setCurrentBalance(double currentBalance) {
this.currentBalance = currentBalance;
}
public void processTransaction(Transaction transaction) {
switch (transaction.getType()) {
case 1:
handleDeposit(transaction.getAmount());
break;
case 2: // Isn't this just a deposit?
handleInterest(transaction.getAmount());
break;
case 3:
handleWithdraw(transaction.getAmount());
break;
default:
throw new RuntimeException("Can not process transaction " + transaction + ", transaction type unknown.");
}
}
private void handleDeposit(double deposit) {
numberOfDeposits++;
currentBalance += deposit;
totalDeposited += deposit;
}
private void handleInterest(double interestPaid) {
numberOfInterestPayments++;
currentBalance += interestPaid;
totalInterestPaid += interestPaid;
}
private void handleWithdraw(double amountWithdrawn) {
numberOfWithdrawals++;
currentBalance -= amountWithdrawn;
totalWithdrawn += amountWithdrawn;
}
public String getOverview() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Total Deposited : " + totalDeposited).append("\n");
stringBuilder.append("Total Withdrawn : " + totalWithdrawn).append("\n");
stringBuilder.append("Total Interest : " + totalInterestPaid).append("\n");
stringBuilder.append("Current Balance : " + currentBalance).append("\n").append("\n");
return stringBuilder.toString();
}
}
/**
* @param args
* the command line arguments
*/
public static void main(String[] args) throws FileNotFoundException {
Scanner inFile = null;
PrintWriter outFile= null;
try {
inFile = new Scanner(new FileReader("Account.in"));
outFile = new PrintWriter("Account.out");
Account account;
try {
account = new Account(inFile);
} catch (RuntimeException e) {
// Catch exception for error message display
System.err.println("Could not read account information from file. Quitting");
System.exit(1);
return; // Otherwise compiler error :)
}
int lineNumber = 1; // Start with 1 because first line has account info
while (inFile.hasNext()) {
Transaction transaction = new Transaction();
try {
transaction.read(inFile);
} catch (RuntimeException e) {
System.err.println("An error ocurred while processing a transaction on line " + lineNumber + ". Transaction " + transaction + " incomplete and failed");
throw e; // rethrow and let the stack trace shine!
}
lineNumber++;
outFile.printf("Account Number: %d%n", account.getAccountNum());
outFile.printf("Beginning Balance: $%.2f %n", account.getStartBalance());
outFile.printf("Current Balance: $%.2f %n", account.getCurrentBalance());
outFile.println();
account.processTransaction(transaction);
outFile.print(account.getOverview());
}
} finally {
if (inFile != null) {
inFile.close(); // This can also yield an exception, but I just don't care anymore :)
}
if (outFile != null) {
outFile.close();
}
}
}
}
You may want to include the content of Account.in
to provide more information, but here are some comments:
Variables: Except for variables, all instance, class, and class constants are in mixed case with a lowercase first letter.
This means that by convention, the variable names should be upper/lower-cased like accountNum
, beginningBalance
, numberOfDeposits
, etc.
It should also be mentioned that the way you're placing your curly braces are highly unconventional. It may be a good idea for you to learn good coding style.
This part is also highly inconsistent:
int TransactionType; // declared as int
//...
TransactionType=inFile.nextInt(); // read as int
//...
switch (TransactionType)
case '1': // used as ... char? ASCII '1' = 49
I'm 99% certain that you really need to switch
on case 1:
, case 2:
, case 3:
instead.
You may also want to print the ending balance AFTER you processed the transaction. Right now, you'll always print the same numbers for beginning and ending balance.
It may also benefit you to know that Java has "compound assignment" operators that would make your code a lot more readable. You probably need not concern yourself with the exact semantics right now, but basically instead of this:
BeginningBalance = BeginningBalance
+ TransactionAmount;
BeginningBalance = BeginningBalance
- TransactionAmount;
You can instead write:
beginningBalance += transactionAmount;
beginningBalance -= transactionAmount;
Finally, one last comment about the InputMismatchException
: others have already explained to you what this means. My best guess right now is that your problem is caused by this:
Input file: customer’s account number, account balance at beginning of month, transaction type (withdrawal, deposit, interest), transaction amount
vs:
TransactionAmount=inFile.nextDouble();
TransactionType=inFile.nextInt();
I need to see Account.in
to confirm, but I suspect that the int
transaction type appears before the double
transaction amount, just like the problem statement says. Your code reads them in the opposite order.
This would attempt to read the int
as nextDouble()
, which is okay, but the double
as nextInt()
would throw InputMismatchException
.
I guess it is a little too late to answer this question, but I recently stumbled upon the same problem, and my googling led me here.
I think the most common case for InputMismatchException
thrown by Scanner.nextDouble()
is that your default locale used by your Scanner
expects doubles in different format (for example, 10,5
, not 10.5
). If that is the case, you should use Scanner.useLocale
method like this
Scanner s = new Scanner(System.in);
s.useLocale(Locale.US);
If you read the Exception
messages, it's an InputMismatchException
. This is highly likely caused by the nextDouble()
or nextInt()
function, when it's not reading the correct type. Make sure your data is aligned correctly, and you're not reading doubles with readInt()
.