2
\$\begingroup\$
import java.text.DecimalFormat;
import java.util.Scanner;
class Calculations
{
    //global declarations
    private static final DecimalFormat tspaces = new DecimalFormat("0.00");
    double totalamt;
    public void DataAccept()    //method to accept data
    {   
        System.out.println("This program will determine the cash back amount of any purchases made using your visa.");
        Scanner myInput = new Scanner(System.in);
        System.out.println("Enter the amount of your purchase: ");
        totalamt = myInput.nextDouble();
        double famount = totalamt * 0.015;
        double samount = totalamt * 0.0175;
        double tamount = totalamt * 0.0225;
        double fcashamt = totalamt - famount;
        double scashamt = totalamt - samount;
        double tcashamt = totalamt - tamount;
        
        if(totalamt < 200)  //conditions and calculations are done here
        {
            System.out.println("Your total cash amount earned is $"+ tspaces.format(famount));
            String yesorno = "";
            Scanner ynInput = new Scanner(System.in);
            System.out.println("Would you like to apply the money to your purchase or save it for a future credit? (y) for purchase (n) for future credit:");
            yesorno = ynInput.nextLine();
            if(yesorno.equals("y") || yesorno.equals("Y")) //if user responses y, he gets a different output and if responses n then gets another output
            {
                System.out.println("You have decided to apply your cash credit to your current purchase of $" + tspaces.format(totalamt) + ".\nYour final bill after applying your cash credit amount of $"+ tspaces.format(famount) + " is now $"+ tspaces.format(fcashamt) + ".\nThank you for your purchase.");
            }
            else
            {
                System.out.println("You have opted to save your cash credit for future purchases. Your current purchase amount is $" + tspaces.format(totalamt) + ".\nYou have a credit of $" + tspaces.format(famount) + " that you may use for future purchases.");
            }
        }   
        else if(totalamt >= 200 && totalamt < 1000) //conditions and calculations are done here
        {
            System.out.println("Your total cash amount earned is $"+ tspaces.format(samount));
            String yesorno = "";
            Scanner ynInput = new Scanner(System.in);
            System.out.println("Would you like to apply the money to your purchase or save it for a future credit? (y) for purchase (n) for future credit:");
            yesorno = ynInput.nextLine();
            if(yesorno.equals("y") || yesorno.equals("Y")) //if user responses y, he gets a different output and if responses n then gets another output
            {
                System.out.println("You have decided to apply your cash credit to your current purchase of $" + tspaces.format(totalamt) + ".\nYour final bill after applying your cash credit amount of $"+ tspaces.format(samount) + " is now $"+ tspaces.format(scashamt) + ".\nThank you for your purchase.");
            }
            else
            {
                System.out.println("You have opted to save your cash credit for future purchases. Your current purchase amount is $" + tspaces.format(totalamt) + ".\nYou have a credit of $" + tspaces.format(samount) + " that you may use for future purchases.");
            }
        }
        else if(totalamt > 1000)    //conditions and calculations are done here
        {
            System.out.println("Your total cash amount earned is $"+ tspaces.format(tamount));
            String yesorno = "";
            Scanner ynInput = new Scanner(System.in);
            System.out.println("Would you like to apply the money to your purchase or save it for a future credit? (y) for purchase (n) for future credit:");
            yesorno = ynInput.nextLine();
            if(yesorno.equals("y") || yesorno.equals("Y")) //if user responses y, he gets a different output and if responses n then gets another output
            {
                System.out.println("You have decided to apply your cash credit to your current purchase of $" + tspaces.format(totalamt) + ".\nYour final bill after applying your cash credit amount of $"+ tspaces.format(tamount) + " is now $"+ tspaces.format(tcashamt) + ".\nThank you for your purchase.");
            }
            else
            {
                System.out.println("You have opted to save your cash credit for future purchases. Your current purchase amount is $" + tspaces.format(totalamt) + ".\nYou have a credit of $" + tspaces.format(tamount) + " that you may use for future purchases.");
            }
        }
    }
}
public class CashVisa2
{
    public static void main(String args[]) 
    {
        Calculations c = new Calculations();    //object of the class calculations
        c.DataAccept();     //calling method of that class
    }
}

This program has discount calculations on customer purchases. If it's less than 200$ then they get 1.5%, for more than 200$ they get 1.75% and for more than 1000$ they get 2.25%. I used basic if/else to get the output, but even the simplest code took 87 lines. And there is a 'yes'/'no' option to credit their discounted money or use it in the current bill, so I had to write different SOP statements in each loop so different output will be showed.

Is there any other way of doing it that will make the program smaller? (Less in size and lines)

\$\endgroup\$

3 Answers 3

2
\$\begingroup\$

NOTE: this is pseudo-code, not necessarily valid Java


Put your if conditions in this order:

if(totalamt > 1000) 
   // $1001+ bonus

else if(totalamt > 200)
   // $201 - $1000 range bonus
   // we just tested for > $1000, so
   // totalamt must be <= $1000 AND, now,  > $200 otherwise
   // this block is skipped

else
  // totalamt must be <= $200, because we already tested for
  // all other possibilities

//endif

Set the bonus Percentage in the specific if clause. Calculate everything AFTER the if so it is done only once and in one place.

double bonusPercent;
double bonus;
double discountedTotal; 

if(totalamt > 1000) // $1001+ bonus
   bonusPercent = 0.225;
  
else if(totalamt > 200)  // $201 - $1000 range bonus
   bonusPercent = 0.0175;

else
   bonusPercent =  0.015;

//endif

bonus = totalamt * bonusPercent;
discountedTotal = totalamt - bonus; // in case user wants to apply at checkout

Now you can delete all the tamount, samount, etc. variables.


The user interaction is all redundant. Refactor that to a single method.

Good call not putting calculations here. Note some basic formatting: space above & below if; break up very, very, long output string.

TalkToMe() {
        System.out.println("Your total cash amount earned is $"+ tspaces.format(bonus));
        String yesorno = "";
        Scanner ynInput = new Scanner(System.in);
        System.out.println("Would you like to apply the money to your purchase or save it for a future credit? (y) for purchase (n) for future credit:");
        yesorno = ynInput.nextLine();

        if(yesorno.equals("y") || yesorno.equals("Y")) 
        { 
            System.out.println("You have decided to apply your cash credit to your current purchase of $" +
            tspaces.format(totalamt) + 
            ".\nYour final bill after applying your cash credit amount of $"+ tspaces.format(bonus) + 
            " is now $"+ tspaces.format(discountedTotal) +
            ".\nThank you for your purchase.");
        }
        else
        {
            System.out.println("You have opted to save your cash credit for future purchases. Your current purchase amount is $" +
            tspaces.format(totalamt) + 
            ".\nYou have a credit of $" + 
            tspaces.format(bonus) + " that you may use for future purchases.");
        }

} // TalkToMe
\$\endgroup\$
1
\$\begingroup\$

I don't find the DecimalFormat to be necessary - it's simpler to just call printf.

You make two Scanners when you only need one.

Reduce the repetition you have between your three cases that only vary based on the percent return on the purchase.

Separate your console user interface from the business logic that calculates the payment.

You can replace your double-equals with one equals following a toLowerCase call.

Suggested

Purchase.java

package com.stackexchange.discounts;

class Purchase
{
    public final double purchase, creditPortion, credit, finalBill;

    public Purchase(double purchase)
    {
        this.purchase = purchase;

        if (purchase < 200)
            creditPortion = 1.50e-2;
        else if (purchase < 1000)
            creditPortion = 1.75e-2;
        else
            creditPortion = 2.25e-2;

        credit = purchase * creditPortion;
        finalBill = purchase - credit;
    }
}

CashVisa2.java

package com.stackexchange.discounts;

import java.util.Scanner;
import static java.lang.System.out;

public class CashVisa2 {
    private final Scanner in = new Scanner(System.in);

    public static void main(String[] args) {
        CashVisa2 c = new CashVisa2();
        c.acceptInput();
    }

    public void acceptInput()
    {
        out.println("This program will determine the cash back amount of any purchases made using your visa.");
        out.println("Enter the amount of your purchase: ");
        Purchase purchase = new Purchase(in.nextDouble());
        in.nextLine();

        out.printf(
            "Your total cash amount earned is $%.2f"
            + "%nWould you like to apply the money to your purchase or save it for a future credit?"
            + "%n(y) for purchase (n) for future credit: ",
            purchase.credit
        );

        String yesorno = in.nextLine().toLowerCase();
        if (yesorno.equals("y"))
        {
            out.printf(
                "You have decided to apply your cash credit to your current purchase of $%.2f"
                + "%nYour final bill after applying your cash credit amount of $%.2f "
                + "is now $%.2f."
                + "%nThank you for your purchase."
                + "%n",
                purchase.purchase,
                purchase.credit,
                purchase.finalBill);
        }
        else
        {
            out.printf(
                "You have opted to save your cash credit for future purchases. "
                + "Your current purchase amount is $%.2f."
                + "%nYou have a credit of $%.2f that you may use for future purchases."
                + "%n",
                purchase.purchase,
                purchase.credit);
        }
    }
}

Output

This program will determine the cash back amount of any purchases made using your visa.
Enter the amount of your purchase: 
100
Your total cash amount earned is $1.50
Would you like to apply the money to your purchase or save it for a future credit?
(y) for purchase (n) for future credit: n
You have opted to save your cash credit for future purchases. Your current purchase amount is $100.00.
You have a credit of $1.50 that you may use for future purchases.
\$\endgroup\$
1
\$\begingroup\$

The dialog is ugly - taking a yes/no answer to a question which isn't actually written as a yes/no choice isn't clear - at least in my opinion. How about asking something like this?

Would you like to (a)pply the discount to your purchase or (s)ave it for a future credit?

As already pointed out, you don't need nearly so much duplication.

However, I would suggest that you reconsider how you approach this, asking how easy it would be to amend the code to have different values for the spends and discounts, or what it would take to introduce further levels - such as 2.5% above $10000.

Data-driven design are usually clearer and easier to maintain. You simply need to look up discounts from an ordered list of spend values and discount percents.

Leaving aside the scanner-based dialog, the sketch below shows how I might do the first steps of this. I'd probably then look to abstract the data in the lookup table to some external form - a properties file, a JSON file, or a database table, perhaps - so that changes to the discounts didn't require a change to the code.

import java.util.Arrays;
import java.util.List;

public class Discount {

  private static class DiscountLevel {

    private int maxSpend;
    private double discountPercent;

    private DiscountLevel(int maxSpend, double discountPercent) {
      this.maxSpend = maxSpend;
      this.discountPercent = discountPercent;
    }

    public int getMaxSpend() {
      return maxSpend;
    }

    public double getDiscountPercent() {
      return discountPercent;
    }
  }

  // Must be maintained in ascending spend value order
  private static List<DiscountLevel> allDiscounts = Arrays.asList(
      new DiscountLevel(200, 1.5),
      new DiscountLevel(1000, 1.75),
      new DiscountLevel(Integer.MAX_VALUE, 2.25));

  public static void main(String[] args) {
    for (int spend : Arrays.asList(10, 150, 200, 250, 999, 1000, 10_000, 100_000)) {
      double discountPercent = findDiscount(spend);
      System.out.format("Spend $%d discount %f%% $%f %n", spend, discountPercent, (spend * discountPercent) / 100);
    }
  }

  private static double findDiscount(int spend) {
    for (DiscountLevel discountLevel : allDiscounts) {
      if (discountLevel.getMaxSpend() >= spend) {
        return discountLevel.getDiscountPercent();
      }
    }
    throw new RuntimeException("Discount table corrupt!");
  }

}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.