7 Replies - 4378 Views - Last Post: 21 March 2014 - 07:51 AM Rate Topic: -----

#1 jacob71798   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 19-March 14

Cash Register program help

Posted 20 March 2014 - 02:07 PM

Hello, my code for this program works fine, but what I was wondering was if anyone could maybe help simplify it for me? I'm not getting any errors or anything, just wanted to possibly make it simpler to understand. I would prefer it if you helped me simplify the printAmountInRegister method, which is in the CashRegister class. Thank you so much!





import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.text.*;   //Needed to format double numbers to 2 places
import java.util.*;

// Create a CashRegister class that represents the cash register and its contents.  The CashRegister class 
// will keep track of the different currency and coins in the cash register.  You need a method to 
// tell you what money is in the cash register.
//
public class CashRegister 
{
    // Create instance variables to keep track of the money (each currency/coin) in the cash register, 
    // the money (each currency/coin) received,
    // and the purchase amount  

    private ArrayList<Money> money = new ArrayList<Money>(); // This keeps track of all the money in the register
    private DecimalFormat moneyFormat = new DecimalFormat("$0.00");  // Money format: 2 decimals with $
    private DecimalFormat decFormat = new DecimalFormat("#.##");     // Decimal format: 2 decimals
    
    public CashRegister(ArrayList<Money> startMoney)
    {
        // This is the constructor.  The array list parameter is full of Money objects.  Since the money 
        // needs to be separated, You will also need to sort the money array list in reverse order.
        // This ArrayList can be sorted since Money implements Comparable and and the compareTo method is defined
        Collections.sort(startMoney);
        money = startMoney;
    }
    
    public double getTotalMoneyInRegister()
    {
        // Calculate the total amount of money in the cash register
        double amount = 0;
        for (Money tempmoney : money){ //creates a temporary variable to get the value of each unit in the array
            amount += tempmoney.getValue(); //adds each of the
        }
        return amount;
    }

    public void printAmountInRegister()
    {
        // Print out the total amount of each currency in the cash register.  There should be a separate line per currency.
        HashMap<String, Double> map = new HashMap<String, Double>();
        for (Money mon : money) {
            String type = mon.getType();
            double value = mon.getValue();
            Object get = map.get(type);
            if (get == null) {
                map.put(type, 0.0);
                get = map.get(type);
            }
            double newValue = (double) get + value;
            map.put(type, newValue);
        }
        Iterator it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pairs = (Map.Entry)it.next();
            System.out.println("There is $" + pairs.getValue() + " worth of " + pairs.getKey() + "s in the register.");
            it.remove();
        }
    }
}






public class Money implements Comparable
{
    private String type;    //type of currency
    private double value;   //value of money
    
    public Money(String type, double value)
    {
        // Initialize the instance variables
        this.type = type;
        this.value = value;
    }
    
    public int compareTo(Object obj)
    {
        // Create a compareTo() method to determine how to compare a Money object.
        // Use the value of the money to determine whether it is less than, equal, or 
        // greater than the other money
        Money other = (Money) obj;
        if (value < other.value) 
            return -1;
         else if (value == other.value) 
            return 0;
         else 
            return 1;
    }
    
    public boolean equals(Object obj)
    {
        Money other = (Money) obj;
        if (value == other.value) 
            return true;
        return false;
    }
    
    public double getValue()
    {
        // get the value of the money
        return value;
    }
    
    public String getType()
    {
        // get the type of money
        return type;
    }
    
    public String toString()
    {
        // return the value of the money
        return Double.toString(value);
    }
}



import java.util.ArrayList;
import java.text.*;   //Needed to format double numbers to 2 places

// This driver program should create a new Money object for each currency or coin
// in a cash register (from a penny to a twenty dollar bill).
// It should then initialize the cash register with some money and print out the 
// contents of the cash register.

public class CashRegisterTester
{
    public static void main( String[] args )
    {
        DecimalFormat decFormat = new DecimalFormat("$0.00");

        // Set up all possible types of money from a penny to a twenty dollar bill - here are a few examples:
        Money twentyDollars = new Money("20 dollar bill", 20.00);
        Money tenDollars = new Money("10 dollar bill", 10.00);
        Money fiveDollars = new Money("5 dollar bill", 5.00);
        Money oneDollar = new Money("1 dollar bill", 1.00);
        Money quarter = new Money("quarter", .25);
        Money dime = new Money("dime", .10);
        Money nickel = new Money("nickel", .05);
        Money penny = new Money("penny", .01);

        // Initialize the cash register by sending it an array list of money (currency/coins)
        // You can set up a loop and populate the array list that way (possibly 10 of each currency or coin)

        ArrayList<Money>  cash = new ArrayList<Money>();  //This is the array list of money that needs to be populated
        cash.add(twentyDollars);//You use this method to add how much money you want in this cash register.
        cash.add(twentyDollars);
        cash.add(twentyDollars);
        cash.add(tenDollars);
        cash.add(tenDollars);
        cash.add(tenDollars);
        cash.add(oneDollar);
        cash.add(oneDollar);
        cash.add(oneDollar);
        cash.add(oneDollar);
        cash.add(oneDollar);
        cash.add(quarter);
        cash.add(quarter);
        cash.add(quarter);
        cash.add(quarter);
        cash.add(dime);
        cash.add(nickel);
        cash.add(nickel);
        cash.add(penny);


        CashRegister register = new CashRegister(cash);  //Instantiates the cash register with money.

        // Show what is in cash register
        System.out.println("\n"+"The cash register contains $"+register.getTotalMoneyInRegister()+" :");
        register.printAmountInRegister();   //Shows the amount of each currency
    }
}


This post has been edited by baavgai: 21 March 2014 - 04:37 AM
Reason for edit:: tagged ( note, they tried: syntax was off )


Is This A Good Question/Topic? 0
  • +

Replies To: Cash Register program help

#2 CasiOo   User is offline

  • D.I.C Lover
  • member icon

Reputation: 1577
  • View blog
  • Posts: 3,551
  • Joined: 05-April 11

Re: Cash Register program help

Posted 20 March 2014 - 03:40 PM

Java 8 has the capabilities to greatly reduce the code needed for printAmountInRegister
Is the code highly readable? Well I think not
Luckly you have the resulting variable type to help you out understanding what's going on ^^
		Map<String, DoubleSummaryStatistics> grouped = money
				.stream()
				.collect(Collectors.groupingBy(
						Money::getType,
						Collectors.summarizingDouble(Money::getValue)));
		
		grouped.forEach((type, summary) -> {
			System.out.println(String.format("[%s: %.2f]", type, summary.getSum()));
		}); 


Which will print

Quote

[Dollars: 30,50]
[Pennis: 15,00]


Another example, with the same result as above, but written with more steps
		Map<String, List<Money>> grouped = money
			.stream()
			.collect(Collectors.groupingBy(Money::getType));
		
		for (Map.Entry<String, List<Money>> entry : grouped.entrySet()) {
			double sum = entry.getValue()
				.stream()
				.mapToDouble(Money::getValue)
				.sum();
			
			System.out.println(String.format("[%s: %.2f]", entry.getKey(), sum));
		}


Was This Post Helpful? 0
  • +
  • -

#3 jacob71798   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 19-March 14

Re: Cash Register program help

Posted 20 March 2014 - 05:29 PM

Thank you very much for the help, I really appreciate it!
Was This Post Helpful? 0
  • +
  • -

#4 x68zeppelin80x   User is offline

  • D.I.C Addict

Reputation: 130
  • View blog
  • Posts: 576
  • Joined: 07-March 09

Re: Cash Register program help

Posted 20 March 2014 - 05:53 PM

OK, I am going to start off by saying:

  • You are not supplying types to your generic objects: Comparable, Iterator, etc...
  • Your equals() method does not look very safe, what if I pass a non-Money object into that method? BOOM goes your code.
  • No need to add comments to every line. The is something called "self-documenting code". Write out your method and variable names as verbose as possible. For instance, if a method calculates the average rate of speed, name it calculateAverageRateOfSpeed() or simply calcAvgRateOfSpeed().


I have refactored your Money's equals() method as well as provided an overridden hash() method:

Note, that if you supply a type to Comparable, you do not need to cast your other object to a Money object.

Money.java
public class Money implements Comparable<Money> {
	private String type; // Type of currency
	private double value; // Value of money

	public Money(String type, double value) {
		// Initialize the instance variables.
		this.type = type;
		this.value = value;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}

		if (obj == this) {
			return true;
		}

		if (!(obj instanceof Money)) {
			return false;
		}

		Money other = (Money) obj;

		if (value != other.value) {
			return false;
		}

		if (!type.equals(other.type)) {
			return false;
		}

		return true;
	}

	@Override
	public int hashCode() {
		int hash = 1;
		hash = hash * 17 + Double.valueOf(value).hashCode();
		hash = hash * 31 + type.hashCode();
		return hash;
	}

	public double getValue() {
		return value;
	}

	public String getType() {
		return type;
	}

	@Override
	public String toString() {
		return Double.toString(value);
	}

	/**
	 * Create a compareTo() method to determine how to compare a Money object.
	 * Use the value of the money to determine whether it is less than, equal,
	 * or greater than the other money
	 * 
	 * @param other
	 *            Money object to compare to.
	 */
	@Override
	public int compareTo(Money other) {
		if (value < other.value) {
			return -1;
		}

		if (value > other.value) {
			return 1;
		}

		return 0;
	}
}


Next, if you noticed you Money class looks a heck of a lot like an Enumeration. So I took the liberty of converting it into an enum class. The only difference if that the compareTo() method is not available in the enum, so you must write a helper class to compare them:

Currency.java
public enum Currency {
	DOLLARS_100(100.00f, "one-hundred dollar bill"),
	DOLLARS_50(50.00f, "fifty dollar bill"),
	DOLLARS_20(20.00f, "twenty dollar bill"),
	DOLLARS_10(10.00f, "ten dollar bill"),
	DOLLARS_5(5.00f, "five dollar bill"),
	DOLLARS_1(1.00f, "one dollar bill"),
	COINS_QUARTER(0.25f, "quarter"),
	COINS_DIME(0.10f, "dime"),
	COINS_NICKEL(0.05f, "nickel"),
	COINS_PENNY(0.01f, "penny");

	private String displayName;
	private float value;

	private Currency(float value, String displayName) {
		this.value = value;
		this.displayName = displayName;
	}

	public float getValue() {
		return value;
	}

	public double getValueAsDouble() {
		return value;
	}

	public String getDisplayName() {
		return displayName;
	}
}


CurrencyComparator.java
import java.util.Comparator;

public class CurrencyComparator implements Comparator<Currency> {
	@Override
	public int compare(Currency c1, Currency c2) {
		return Double.compare(c1.getValue(), c2.getValue());
	}
}


I practically tore most of the CashRegister class apart. I changed money to cash (I am bit pedantic) and I converted your printAmountInRegister() method into a toString() because it seemed like the best thing to do. If you noticed, I also added methods to all a list of Currencies or a frequency of Currencies. They are super-helpful.

CashRegister.java
import java.util.*;

/**
 * Create a CashRegister class that represents the cash register and its
 * contents. The CashRegister class will keep track of the different currency
 * and coins in the cash register. You need a method to tell you what money is
 * in the cash register.
 */
public class CashRegister {
	private ArrayList<Currency> cash;

	public CashRegister() {
		this.cash = new ArrayList<Currency>();
	}

	public CashRegister(ArrayList<Currency> startMoney) {
		Collections.sort(startMoney);

		this.cash = startMoney;
	}

	public void addCashAsList(Currency... currencies) {
		for (Currency currency : currencies) {
			cash.add(currency);
		}
	}

	public void addCashAsFrequency(Currency currency, int frequency) {
		for (int i = 0; i < frequency; i++) {
			cash.add(currency);
		}
	}

	public double getTotalMoneyInRegister() {
		double amount = 0;

		for (Currency c : cash) {
			amount += c.getValueAsDouble();
		}

		return amount;
	}

	@Override
	public String toString() {
		StringBuffer buff = new StringBuffer();
		HashMap<String, Double> map = new LinkedHashMap<String, Double>();

		for (Currency c : cash) {
			String type = c.getDisplayName();
			double value = c.getValue();
			Object get = map.get(type);

			if (get == null) {
				map.put(type, 0.0);
				get = map.get(type);
			}

			double newValue = (double) get + value;
			map.put(type, newValue);
		}

		Iterator<Map.Entry<String, Double>> it = map.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<String, Double> pairs = it.next();
			buff.append(String.format(
					"There is $%.2f worth of %ss in the register.%n",
					pairs.getValue(), pairs.getKey()));
		}

		return buff.toString();
	}
}


Finally, I cut your driver class in half by taking advantage of the new addCashAsFrequency() method. BAM, there you have it. I am sure there are some more improvements for this code, because as they say in programming, "there is more than one way to skin a cat".

CashRegisterTester.java
/**
 * This driver program should create a new Money object for each currency or
 * coin in a cash register (from a penny to a twenty dollar bill). It should
 * then initialize the cash register with some money and print out the contents
 * of the cash register.
 */
public class CashRegisterTester {
	public static void main(String[] args) {
		CashRegister register = new CashRegister();

		register.addCashAsFrequency(Currency.DOLLARS_20, 3);
		register.addCashAsFrequency(Currency.DOLLARS_10, 3);
		register.addCashAsFrequency(Currency.DOLLARS_1, 5);
		register.addCashAsFrequency(Currency.COINS_QUARTER, 4);
		register.addCashAsFrequency(Currency.COINS_DIME, 1);
		register.addCashAsFrequency(Currency.COINS_NICKEL, 2);
		register.addCashAsFrequency(Currency.COINS_PENNY, 1);

		System.out.printf("The cash register contains $%.2f:%n",
				register.getTotalMoneyInRegister());

		System.out.println(register.toString());
	}
}


I hope that, with what I have provided, you have learned something new and want to explore the Java language further. If something doesn't look right or you're confused, just shoot me a message at @x68zeppelin80x.

Thanks for listening.

This post has been edited by x68zeppelin80x: 20 March 2014 - 06:00 PM

Was This Post Helpful? 1
  • +
  • -

#5 CasiOo   User is offline

  • D.I.C Lover
  • member icon

Reputation: 1577
  • View blog
  • Posts: 3,551
  • Joined: 05-April 11

Re: Cash Register program help

Posted 21 March 2014 - 12:28 AM

I have nothing new to add x68zeppelin80x
Just some smaller changes to compareTo and the equals method in the Money class to make them look prettier imo ^^
@Override
public boolean equals(Object other) {
	if (other instanceof Money)
		return equals((Money) other);
	
	return false;
}

private boolean equals(Money other) {
	return this.value == other.value && this.type.equals(other.type);
}

@Override
public int compareTo(Money other) {
	return this.value - other.value;
}


Was This Post Helpful? 0
  • +
  • -

#6 x68zeppelin80x   User is offline

  • D.I.C Addict

Reputation: 130
  • View blog
  • Posts: 576
  • Joined: 07-March 09

Re: Cash Register program help

Posted 21 March 2014 - 03:24 AM

View PostCasiOo, on 21 March 2014 - 03:28 AM, said:

@Override
public boolean equals(Object other) {
	if (other instanceof Money)
		return equals((Money) other);
	
	return false;
}



Sorry CasiOo, but I am not too sure about that. If indeed, you are comparing the current object with itself, why not short-circuit and just turn true instead of taking the time to call another method. Sometimes, simple is not always the best approach.

The way I designed it will short-circuit at any point and stop the comparison if the other object is null, the other object is itself, the objects are incompatible, or any of the properties are not equal.

@Override
public boolean equals(Object obj) {
	// 1. Test for null.
	if (obj == null) return false;
	// 2. Test for self-reference.
	if (obj == this) return true;
	// 3. Test for compatibility.
	if (!(obj instanceof Money)) return false;
	// 3.1. Cast other to Class type.
	Money other = (Money) obj;
	// 4. Test value equality.
	if (value != other.value) return false;
	// 5. Test type equality.
	if (!type.equals(other.type)) return false;
	// 6. You made it, the objects are equal.
	return true;
}


Thanks.
Was This Post Helpful? 0
  • +
  • -

#7 CasiOo   User is offline

  • D.I.C Lover
  • member icon

Reputation: 1577
  • View blog
  • Posts: 3,551
  • Joined: 05-April 11

Re: Cash Register program help

Posted 21 March 2014 - 06:53 AM

I don't believe you are gaining anything from the short-circuit you are doing
Most often you'll be comparing two different instances, which will result in an extra if check every time
The performance gain you might (Or might not) get will be very minimal in this case
Was This Post Helpful? 0
  • +
  • -

#8 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7197
  • View blog
  • Posts: 15,004
  • Joined: 16-October 07

Re: Cash Register program help

Posted 21 March 2014 - 07:51 AM

I would agree that this is a job for enum.

However, on the compare front, note that the user implements a generic comparable, at which point you might as well isolate the logic there.

e.g.
public int compareTo(Object obj) {
    if (obj==null) { return -1; }
    if (obj==this) { return 0; }
    if ( !(obj instanceof Money) ) { return -1; }
    return ((int)(value*100.0)) - ((int)(((Money)obj).value*100.0));
}

public boolean equals(Object other) { return compareTo(other)==0; }

// obviously, this one if kind of pointless
private boolean equals(Money other) { return compareTo(other)==0; }



Note, with a compareTo you must chose value for invalid.

Also, for something like this, double is a profoundly poor way to go. However, in keeping with the OP, we allow for it.

The standard Java equals checks for null and self are considered best practice, btw. I believe Eclipse templates those checks.

However, if you're honestly concerned, hashCode() should also be implemented.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1