Help with method logic in Java, hw - java

I have a Loan class that in its printPayment method, it prints the amortization table of a loan for a hw assignment. We are also to implement a print first payment method, and a print last payment method. Since my calculation is done in the printPayment method, I didn't know how I could get the value in the first or last iteration of the loop and print that amount out.
One way I can think of is to write a new method that might return that value, but I wasn't sure if there was a better way. Here is my code:
public abstract class Loan
{
public void setClient(Person client)
{
this.client = client;
}
public Person getClient()
{
return client;
}
public void setLoanId()
{
loanId = nextId;
nextId++;
}
public int getLoanId()
{
return loanId;
}
public void setInterestRate(double interestRate)
{
this.interestRate = interestRate;
}
public double getInterestRate()
{
return interestRate;
}
public void setLoanLength(int loanLength)
{
this.loanLength = loanLength;
}
public int getLoanLength()
{
return loanLength;
}
public void setLoanAmount(double loanAmount)
{
this.loanAmount = loanAmount;
}
public double getLoanAmount()
{
return loanAmount;
}
public void printPayments()
{
double monthlyInterest;
double monthlyPrincipalPaid;
double newPrincipal;
int paymentNumber = 1;
double monthlyInterestRate = interestRate / 1200;
double monthlyPayment = loanAmount * (monthlyInterestRate) /
(1 - Math.pow((1 + monthlyInterestRate),( -1 * loanLength)));
System.out.println("Payment Number | Interest | Principal | Loan Balance");
// amortization table
while (loanAmount >= 0) {
monthlyInterest = loanAmount * monthlyInterestRate;
monthlyPrincipalPaid = monthlyPayment - monthlyInterest;
newPrincipal = loanAmount - monthlyPrincipalPaid;
loanAmount = newPrincipal;
System.out.printf("%d, %.2f, %.2f, %.2f", paymentNumber++, monthlyInterest, monthlyPrincipalPaid, loanAmount);
}
}
/*
//method to print first payment
public double getFirstPayment()
{
}
method to print last payment
public double getLastPayment()
{
}*/
private Person client;
private int loanId;
private double interestRate;
private int loanLength;
private double loanAmount;
private static int nextId = 1;
}
Thanks!

You've already identified that the printPayments(), printFirstPayment() and printLastPayment() methods have common logic. You generally want to minimize duplication of such code and the two common ways to do this are:
Implement all but one of the methods in terms of one of them; or
Implement all the methods in terms of a private method.
So, for example:
public void printPayments() {
for (Payment : getPayments()) {
printPayment(payment);
}
}
public void printFirstPayment() {
printPayment(getPayments().get(0));
}
public void printLastPayment() {
List<Payment> payments = getPayments();
printPayment(payments.get(payments.size()-1));
}
private void printPayment(Payment payment) {
...
}
private List<Payment> getPayments() {
...
}
Now this is homework so you may not have come across the syntax List<Payment> yet. If not, it's generics. There are other ways to do this: using a non-generic Collection or using arrays for example.
The points I wanted to illustrate here is that:
The logic for creating the payments and displaying them has been separated;
A single method getPayments() does the calculations and returns a List of Payment objects. Payment is a new object in this mock up;
All three methods are implemented in terms of getPayments() and printPayment().
So I hope this leads you in the right direction. The concept here I guess is functional composition, composing your functions in terms of other functions and making your internal functions granular enough to be grouped together usefully.

Your printPayments function is awfully big. It is generally better to make each function "do one thing and one thing well", and to make functions relatively short. I would recommend that you separate your computation logic from your printing logic; provide functions for computing these various payments, and have your print function merely print the result of invoking those computation functions.
If you are worried about redundancy (that is some of the later computations depend on earlier computations which you might have previously performed), then you can use dynamic programming, which basically means that you accumulate previous results in an array or matrix so that they can be reused in subsequent computations. You could compute the entire amortization table as a 2-dimensional array, in which case you could lookup the earlier payments that you computed simply by looking them up in that array.

Maybe you should have a method that returns an array/set/list/resultset/datacontainer (add more buzzwords to confuse you - its your homework after all ;)) which you can use in the other methods.

if when you describe what a method does, you use the word 'and', chances are the method is doing too much. each method should do one thing, so printing is one thing, and calculating is another .. so two methods.

Related

Make the variable not overwrite to null and check if the codes are correct

I'm new to Java and I have created a class which is based on the question from this exercise.
I've tried my best to follow it and I think the reason why my variables are 0 or null is that I didn't write anything in the constructor. The question didn't say anything about what to write in the constructor.
I'm printing everything out because I want to see the result, but all I get from getCardNumber is null, getBalance is 0, coffee is 0. redeemFreeCoffee and isFreeCoffeeAvailable does work, simply because there are no variables that override them.
Here's the full question:
a. Each loyalty card stores the card number, current balance (the number of points) and the number of coffees on the card. Implement a
constructor with the card number (of type String) as its argument and
method getCardNumber() and getBalance().
b. Implement a method collectRewards(double amount, int coffees) that takes the amount spent (in pounds) and the number of coffees
bought and increases the balance (by one point for every pound spent)
as well as the number of coffees on the card.
c. Implement a method isFreeCoffeeAvailable() that checks whether a free coffee is available, that is, whether the number of coffees on
the card is greater than or equal to 9.
d. Implement a method redeemFreeCoffee() that first checks whether a free coffee is available. If this is the case then it reduces the
number of coffees by 9 and returns true, otherwise false.
I've tried changing the variables from private to public but I still get the same result.
I've even tried putting my main in a different class but the result is still the same.
public String cardNumber;
public int balance;
public int coffee;
public double amount;
public String getCardNumber () {
return cardNumber;
}
public int getBalance () {
return balance;
}
public double collectRewards(double amount, int coffees) {
if (amount > 0) {
coffee++;
balance++;
}
return amount;
}
public int isFreeCoffeeAvailable(){
if (coffee >= 9) {
return coffee;
}
return coffee;
}
public boolean redeemFreeCoffee() {
if (coffee > 9) {
coffee-=9;
return true;
}
else {
return false;
}
}
public LoyaltyCard (String cardNumber){
}
public static void main (String[] args) {
String cardNumber = "0987654321";
LoyaltyCard LoyaltyCardOne = new LoyaltyCard(cardNumber);
System.out.printf("%s%n%s%n%s%n%s%n%s",LoyaltyCardOne.getCardNumber(),LoyaltyCardOne.getBalance(),LoyaltyCardOne.collectRewards(6.0,5),LoyaltyCardOne.redeemFreeCoffee(),LoyaltyCardOne.isFreeCoffeeAvailable());
}
I'd like to see the result for getCardNumber(), getBalance() and the amount of coffee.
all I get from getCardNumber is null
You never initialized it
public LoyaltyCard (String cardNumber){
this.cardNumber = cardNumber;
}
because there are no variables that override them.
I think you might be confused about what "override" means, but that isn't the problem.
getBalance is 0, coffee is 0
You're calling those before you ever "collect rewards"
You will need to collect before printing the invidiual values, and read the logic again - increase by one point for every pound spent. So, focus on changing this block to fix that.
if (amount > 0) {
coffee++;
balance++;
}
Note that the instructions don't say the collectRewards returns anything. Also coffee should be increased by the input parameter, maybe than just 1.
Otherwise, you would need to call collectRewards at least 9 times before the redeem and isAvailable methods would work.
And once those are, you could do this, rather than rewrite coffee > 9
if (this.isFreeCoffeeAvailable()) {
} else {
}
Note: isFreeCoffeeAvailable should probably return coffee > 9; rather than return the amount
In Java all non-local variables are initialized to 0, or null. So far in the code you don't set variables to your desired values. You can either create a constructor which takes values, e,g:
LoyaltyCard(int balance, int coffee, double amount) {
this.balance = balance;
this.coffee = coffee;
// ... and other fields
or create setters for each field:
public setBalance(int balance) {
this.balance = balance;
}

Java - How can I make a variable, that is assigned a value in on object, accessible to all objects?

I am trying to assign the variable gross a value in the default constructor and then have the other methods be able to access it (the calc... methods).
public class CO2FromWaste
{
CO2FromWaste(int numPeople, boolean paper, boolean plastic, boolean glass, boolean cans)
{
public double ogGrosss = numPeople*1018;
public double grosss = ogGrosss;
if(paper = true)
gross -= 184*numPeople;
if(plastic = true)
gross -= 25.6*numPeople;
if(glass = true)
gross -= 46.6*numPeople;
if(cans = true)
gross -= 165.8*numPeople;
}
private double gross = ogGrosss;
private double ogGross = Grosss;
public void calcGrossWasteEmission()
{
System.out.printf("%20.2f", gross);
}
public void calcWasteReduction()
{
System.out.printf("%20.2f", ogGross - gross);
}
public void calcNetWasteReduction()
{
System.out.printf("%20.2f", gross);
}
}
What you want is for those variables to be members of the class — as you have it now they are declared locally to the constructor.
public class CO2FromWaste
{
// Moved your variables to here, outside of any method.
// They should be declared at/near the top of the class,
// *before* the constructor (by convention)
// I also made them `private` because you don't want code
// that is *outside* of this class to access them.
private double ogGrosss;
private double grosss;
CO2FromWaste(int numPeople, boolean paper, boolean plastic, boolean glass, boolean cans)
{
// Now assign them their values.
// You can optionally use `this`
this.ogGrosss = numPeople*1018;
if(paper == true)
gross -= 184*numPeople;
if(plastic == true)
gross -= 25.6*numPeople;
if(glass == true)
gross -= 46.6*numPeople;
if(cans == true)
gross -= 165.8*numPeople;
}
// removed the declarations from here - these were now duplicates.
public void calcGrossWasteEmission()
{
System.out.printf("%20.2f", gross);
}
public void calcWasteReduction()
{
System.out.printf("%20.2f", ogGross - gross);
}
public void calcNetWasteReduction()
{
System.out.printf("%20.2f", gross);
}
}
Note the = operator in if(paper = true) is assignment — you want to compare these variables, which is done with the == operator.
(untested. I didn't even try to compile this, just modified your code)
Also note that when you subtract a floating-point value from the variable gross, it will round down the result.
I'm going to add some tips you can use to improve upon Stephen P's answer.
First of all, there is never any reason to compare against a boolean. Instead of paper == true you can simply write paper. All an if statement needs is a boolean value. If the value is already boolean, you do not need to perform a comparison. Therefore, your if statements can be made more readable by changing them to:
if(paper)
gross -= 184*numPeople;
if(plastic)
gross -= 25.6*numPeople;
if(glass)
gross -= 46.6*numPeople;
if(cans)
gross -= 165.8*numPeople;
I am assuming that based on what your code does that only one of the four boolean variables you use in your constructor should be true at a time, any the rest should be false. If this is the case, I would recommend using an enum to denote the options, otherwise you leave your class vulnerable to logic errors when used incorrectly. You would add the following file to your project:
WasteMaterial.java
public enum WasteMaterial {
PAPER, PLASTIC, GLASS, CANS
}
And modify the constructor for your class like so:
CO2FromWaste (int numPeople, WasteMaterial material)
{
// Now assign them their values.
// You can optionally use `this`
this.ogGrosss = numPeople*1018;
switch (material) {
case PAPER:
gross -= 184*numPeople;
break;
case PLASTIC:
gross -= 25.6*numPeople;
break;
case GLASS:
gross -= 46.6*numPeople;
break;
case CANS:
gross -= 165.8*numPeople;
break;
}
}
This prevents the class from being constructed incorrectly by setting multiple values to true (if, of course, your specification only allows one of those four values to be true at a time).

ArrayList<Object> how to differentiate objects added

the question is the same as in the title. i have arraylist to which i add incomes or expenses both in form of a object. will this loop sum up all elements, and is there a better way of doing this :?
public void sumOfAllExpAndIn(){
int tmp = 0;
for (Iterator<Object> it = database.iterator(); it.hasNext();){
if (it.next() instanceof Expenses){
Expenses excalc = new Expenses();
excalc = (Expenses) it.next();
tmp -= excalc.value;
}
else {
incomes incalc =new incomes();
incalc = (incomes) it.next();
tmp += incalc.value;
}
}
System.out.format("the overall balance is %d",tmp);
}
Yes there are several better ways of doing it.
Firstly, I don't suggest you declare it as an Object list. Better is to declare an interface and then implement the interface in each of your classes:
interface BudgetValue {
double getValue();
}
class Expense implements BudgetValue {
public double getValue() {
return -value;
}
}
class Income implements BudgetValue {
public double getValue() {
return +value;
}
}
Then you can declare list of BudgetValues rather than Objects as the input to your method:
double sumBudgetValues(List<BudgetValues> budgetValues) {
}
There are two easy ways of summing them:
double total = 0.0;
for (BudgetValue value: budgetValues) {
total += value.getValue();
}
return total;
or using Java 8:
return budgetValues.stream()
.mapToDouble(BudgetValue::getValue)
.sum().orElse(0.0);
The streams method makes a lot more sense to me and allows it to be easily multithreaded if you have a lot of values to sum by turning it into a parallel stream.
There are some rare occassions where instanceof is justified but, as a rule of thumb, if you find yourself using it then start by asking yourself whether there's an interface missing.
I suggest making your Expenses and Incomes classes implement a common interface, for example LineItem. Now if you use signed values (positive for incomes and negatives for expenses), you only have to call getValue() on any implementation of LineItem and add it to your running total... no if/else needed, no collection of Object needed.
public void sumOfAllExpAndIn(){
int tmp = 0;
for (Iterator<LineItem> it = database.iterator(); it.hasNext();){
tmp += it.next().getValue();
}
}
System.out.format("the overall balance is %d",tmp);
}

How to create the Withdraw and Deposit in my work

public class Account {
//===============Properties===================
protected double Balance;
protected String Owner;
protected double AcctNo;
//================Behaviors===============
public void setBalance(double bal) {Balance = bal;}
public double getBalance() {return Balance;}
public void setOwner(String own) {Owner = own;}
public String getOwner() {return Owner;}
public void setAcctNo(double an) {AcctNo = an;}
public double getAcctNo() {return AcctNo;}
//==============Constructors==============
public Account() {
super();
Balance=0;
Owner="";
AcctNo=0;
}
public Account(double bal, String own, double an) {
super();
Balance=bal;
Owner=own;
AcctNo=an;
}
public void deposit() {
0=deposit+Balance;
}
public void withdraw() {
0=withdraw-Balance;
}
public void display() {
System.out.println("Owner = " + getOwner());
System.out.println("Balance = " + getBalance());
System.out.println("Account Number = " + getAcctNo());
}
public static void main (String args []) {
Account a1;
a1 = new Account();
a1.setOwner("Frank");
a1.setBalance(1000);
a1.setAcctNo(2222);
a1.deposit(100.00);
a1.display();
}
}
The withdraw and deposit has became tricky for me, I thought that, that would be the answer to solving the problem, but it was not. I believe everything else is finished except for the those 2 problems
Can I be guided towards the way to understanding the Deposit and Withdrawal concept please? Thanks in advance!
Your problems are here:
0=deposit+Balance;
and here:
0=withdraw-Balance;
When assigning values to variables in Java, the right hand side is evaluated and the result is stored in the left hand side, e.g.
result = things+to+add;
But your code attempts to calculate something and store the result in 0, a literal number, this cannot work, it needs to be a variable.
Also, you functions to withdraw and deposit - how much are you withdrawing or depositing? The deposit function needs to know how much to deposit, and the withdraw function needs to know how much to withdraw. You need to add an argument to each to provide this information:
Here's a possible deposit function:
public void deposit(double amount) {
balance = balance+amount;
}
Heres some things you should all the time with your code
Use consistent formatting and make sure things are indented to the correct location. This means that if you have code inside brackets ({}) that they are are indented 1 and only 1 tab in (tab or 4 space w/e...).
in Java classes are always started with an uppercase and non static final variables are started with lower case variables, the variables Balance, Owner and AcctNo would be more suitable to start with lower case characters.
If you follow those formatting steps it will be much easier to debug and read your code.
Now your problem is your withdraw and deposit methods for 1 dont have a variable in the arguments. You need to add a variable to the method signature.
public void deposit(double ammount) {....
Then you have the statement 0=deposit+Balance; which I dont know what your intending to do there but it is invalid Java. It probably should read: Balance=Balance+deposit.

How can I improve this block of code?

public class OrderProcessor {
public Double calculateTotalPriceWithDiscountCode(Order order,
char discountCode) {
Double itemTotal = order.getItemTotal();
Double discountAmount = 0.0;
switch (discountCode) {
case 'A':
discountAmount = 0.95 * itemTotal;
break;
case 'B':
discountAmount = 0.15 * itemTotal;
break;
}
return itemTotal - discountAmount;
}
Current implementation in order processor is closed for extension and open for modification for adding new discount codes, how can i improve the design to get rid of this limitation
In general, the presence of a switch is a pretty good giveaway as to what should be a class instead. So, a first stab at it would be something like this:
public interface Discounter {
public double applyDiscount(double itemTotal);
}
public class OrderProcessor {
private Map<Char, Discounter> discounts = new HashMap<Char, Discounter>();
public void addDiscounter(Char discountCode, Discounter discounter) {
discounts.put(discountCode, discounter);
}
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
double itemTotal = order.getItemTotal();
double discountAmount = 0.0;
if (discounts.hasKey(discountCode))
discountAmount = discounter.applyDiscount(itemTotal);
return itemTotal - discountAmount;
}
}
This would then be extended through something like this:
processor.addDiscounter('A', new Discounter() {
public double applyDiscount(double itemTotal) {
return 0.95 * itemTotal;
}
});
You could make a remove method as well, and then your discounters can become more complex, consulting external data, etc. You may want to open up the interface a bit and pass in the whole order for more examination.
Note: If this is something you're going to be doing in production I have two pieces of unsolicited advice:
Consider using something like JBoss Drools to handle your business logic instead of this; it's a lot more powerful and flexible.
Please don't use double for actual financial calculations. :)
As you have pointed out that the discount code needs to be changeable, it is best to separate out the actual discount codes from the code. Maintain the discount codes in an xml or settings file and lazy load the values into a dictionary/hashset before using them.
For example your xml could look like this,
<Discounts>
<Discount code="A" value="0.05"/>
<Discount code="B" value="0.10"/>
<Discount code="C" value="0.15"/>
</Discounts>
In your calculateTotalPriceWithDiscountCode, populate a dictionary with the values read from this xml.
if(discountsDictionary == null)
{
discountsDictionary = LoadValuesFromXml(xmlFilePath);
}
In case your discounts xml is likely to change during program execution then perform the Load operation when you want the discount value (as compared to loading once in the above code fragment).
Then access the code (key) to retrieve the discount (value),
if(discountsDictionary.ContainsKey(discountCode))
{
discount = discountsDictionary[discountCode];
discountedItemPrice = itemPrice * ( 1 - discount);
}
else
{
// Invalid discount code...
}
Pull the logic for calculating totals based on an order into its own class/interface:
class OrderProcessor {
// Probably inject this or load it some other way than a static factory
private Collection<TotalCalculator> calculators = TotalCalculatorFactory.getTotalCalculators();
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
for (TotalCalculator calculator : calculators) {
if (calculator.supports(discountCode)) {
return calculator.calculateTotal(order);
}
}
return order.getItemTotal();
}
}
class TotalCalculator {
private char discountCode;
private double discountRatio;
public TotalCalculator(char discountCode, double discountRatio) {
this.discountCode = discountCode;
this.discountRatio = discountRatio;
}
public boolean supports(char discountCode) {
return this.discountCode == discountCode;
}
public Double calculateTotal(Order order) {
return order.getItemTotal() - order.getItemTotal() * discountRatio;
}
}
class TotalCalculatorFactory {
public static Collection<TotalCalculator> getTotalCalculators() {
return Arrays.asList(
new TotalCalculator('A', 0.95),
new TotalCalculator('B', 0.15)
);
}
}
In a real system, I'd make the TotalCalculator an interface, which would have the additional advantage of being able to calculate order totals in other ways than just a percentage discount reduction.
This solution is also very flexible in allowing you to create your TotalCalculators (or implementations if an interface) using other mechanisms than manually coding them into a factory. You can use an IoC container to create and inject them or use a ServiceLoader to find and load them, for example.
My idea is maintain discounts separately.
public class OrderProcessor {
public Double calculateTotalPriceWithDiscountCode(Order order,
char discountCode) {
Double itemTotal = order.getItemTotal();
return itemTotal - (itemTotal* Discounts.GetDiscounts(discountCode));
}
}
////////////////
class Discounts
{
public static double GetDiscounts(char discountCode)
{
switch (discountCode) {
case 'A':
return 0.95d;
case 'B':
return 0.15d;
default:
return 0.00d;
}
}
}
In this calculateTotalPriceWithDiscountCode function, it is not a good idea to pass a discount code as parameter. Well, 3rd person , who review your code , would not understand would not understand what does it mean except you, a kind of code smell.
One of a suggestion is that you need to create another class called Discount, and you pass the Discount object as a parameter, and you get the internal value from its public method.
i.e.
public class Discount {
//Use a hash map to store your Code associate with your discountAmount
public Discount(char discountCode){
this.discountCode = discountCode
}
public int getDiscountAmount(){
....
....
}
}
Right now, what you actually need to modify will be the Discount Class only, and your calculateTotalPriceWithDiscountCode will not need to care.
You could use a separate xml file for storing codes as well as their calculation mechanishms.
This will remove the limitation of inablility to add new discount code.
XML File: discounts.xml
<discount-codes>
<discount-code>
<code>A</code>
<val>0.15</val>
</discount-code>
<discount-code>
<code>B</code>
<val>0.95</val>
</discount-code>
</discount-codes>
Note: Operation code (What am I intended to do with the values?) is not currently implemented. You can implement the same at your end.
Use an XML parser class:
Class: DiscountModel.java (This class is the model to store the discount codes)
public class DiscountModel {
char code;
Double val;
// Implement getters and setters
}
Class: DiscountParser.java (This will parse the discounts.xml file and store the codes in a list)
public class DiscountParser {
List<DiscountModel> discountsList;
// Getters and Setters for discountsList
// Parser Code
public void parseDiscounts() {
// Code here
}
// Add new discount
public void addDiscount() {
// Code
}
// Remove discount
public void removeDiscount () {
// Code
}
}
Class: OrderProcessor.java (This will bring out the discounted value after calculation)
/**
* Call this class when calculations need to be done.
*/
public class OrderProcessor {
// Declare instance of DocumentParser
DocumentParser dc1;
// Getter and setter for dc1
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
// Find the corresponding discountcode and
// value from the list of values in the
// Class DocumentParser
// Use the corresponding values to calculate
// the discount and return the value
}
}
Whenever a new code is to be added, you can insert the same to the xml file. The same applies if the discount code needs to be removed.
Hope the above helps.

Categories

Resources