Im sure there must be a much easier way java arraylist sums

I'm just starting my first real project in Java so I'm still understanding the basics so apologies for this.

I'm working out the price * quantity then giving the total amount to each individual product, this will then have to be repeated for all my products as part of the order process. So i want to find the best way so i can repeat it.

Here is the working code I have:

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {

   double priceA = 20.00;/*fixed price*/
   String strA = txtbxCaseA.getText();/*gets amount from textbox*/
   int numA = Integer.parseInt(strA);/*parse to int */
   double casetotalA = (priceA * numA);/*sum*/
   String caseAtotal = String.valueOf(casetotalA);/*to string */

   double priceB = 25.00;
   String strB = txtbxCaseB.getText();
   int numB= Integer.parseInt(strB);
   double casetotalB = (priceB * numB);
   String caseBtotal = String.valueOf(casetotalB);

   double priceC = 30.00;
   String strC = txtbxCaseC.getText();
   int numC = Integer.parseInt(strC);
   double casetotalC = (priceC * numC);
   String caseCtotal = String.valueOf(casetotalC);

    ArrayList caselist = new ArrayList();
    caselist.add("Case A Total - £" + caseAtotal);
    caselist.add("Case B Total - £" + caseBtotal);
    caselist.add("Case C Total - £" + caseCtotal);

    DefaultListModel myModel = new DefaultListModel ();

    for(int i = 0; i < caselist.size(); i++){
        jTextArea3.append((String)caselist.get(i) + ('\n'));
        myModel.addElement(caselist.get(i) + ",");

        /*
        - save arraylist to a gobal varible for cart processing
        - move to next panel (page) along
        */
    }
}                                        

My question is, is this method good practice, and also is their a better method (maybe shorter) that i can repeat for each of my 50 products as this seems a little inefficient but it works.

Any suggestions or comments would be greatly appreciated.

Answers


Some tips for improving your overall project, making it easier for yourself. Some of these tips have been posted already in other answers.

The basic principle is (like Ceiling Gecko commented): If you see yourself repeating code, make a generic way to code it once and reuse that code for each of the repetitions.

Use a Product class
public class Product {
    private String name;
    private double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }
}

This you will populate, for every product you have, at the very start of your program and store it either in an array or a List

List<Product> productList = new ArrayList<Product>();
productList.add(new Product("Milk", 10.00));
productList.add(new Product("Bread", 20.00));

The products here is hard coded for example, but you may want to read it from a file or DB. More on this later.

Use generics for your Collections

Why Use Generics?

Dynamically generate your 'TextBoxes'

If you code a JPanel with 50 JTextFields for the purpose of inputting amount, what will happen when you add another product? You will then have to go and change your code.

If you use the List of Products mentioned earlier you can dynamically generate your JTextFields If you populated your list from a file or DB you will never have to change your code if you update your product list and/or prices. You can then just update your file or DB and the changes will reflect in your code.

List<JTextField> textFields = new ArrayList<JTextField>();
for (Product p : productList) {
    textFields.add(new JTextField());
}

Then use that list along with your product list to place your Components on your JPanel

JPanel panel = new JPanel();
for (int i = 0; i < textFields.size(); i++) {
    panel.add(new JLabel(productList.get(i).getName()));
    panel.add(textFields.get(i));
}
Put your calculation code in a separate reusable method
private double calculateTotal(String amount, double cost) {
    int amnt = Integer.parseInt(amount);
    return cost * amnt;
}
Now loop through your generated 'TextBoxes' to calculate the totals
Handle the NumberFormatException that may be thrown by Integer.parseInt
private void jButton2ActionPerformed(ActionEvent evt) {
    caselist = new ArrayList<String>();
    for (int i = 0; i < textFields.size(); i++) {
        try {
            double total = calculateTotal(textFields.get(i).getText(), productList.get(i).getPrice());
            caselist.add(productList.get(i).getName() +" Total - £" +  total);
        } catch (NumberFormatException e) {
            caselist.add(productList.get(i).getName() +" invalid amount");
        }
    }
}
Here is everything rolled into one

so you can copy and run it to see how it all fits together. It was put together quickly, so it is not the best way to structure your program

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class ProductCalc extends JFrame {
    public static void main(String[] args) {
        new ProductCalc();
    }

    private List<Product> productList;
    private List<JTextField> textFields;
    private List<String> caselist;

    public ProductCalc() {
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        productList = new ArrayList<Product>();
        productList.add(new Product("Milk", 10.00));
        productList.add(new Product("Bread", 20.00));
        productList.add(new Product("Eggs", 5.00));

        textFields = new ArrayList<JTextField>();
        for (Product p : productList) {
            textFields.add(new JTextField(10));
        }

        JPanel panel = new JPanel();
        for (int i = 0; i < textFields.size(); i++) {
            panel.add(new JLabel(productList.get(i).getName()));
            panel.add(textFields.get(i));
        }

        JButton button = new JButton("click");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });
        panel.add(button);

        this.setSize(500, 500);
        this.add(panel);
        this.setVisible(true);
    }

    private void jButton2ActionPerformed(ActionEvent evt) {
        caselist = new ArrayList<String>();
        for (int i = 0; i < textFields.size(); i++) {
            try {
                double total = calculateTotal(textFields.get(i).getText(), productList.get(i).getPrice());
                caselist.add(productList.get(i).getName() + " Total - £" + total);
            } catch (NumberFormatException e) {
                caselist.add(productList.get(i).getName() + " invalid amount");
            }
        }
        for (String s : caselist) {
            System.out.println(s);
        }
    }

    private double calculateTotal(String amount, double cost) {
        int amnt = Integer.parseInt(amount);
        return cost * amnt;
    }
}

class Product {
    private String name;
    private double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }
}

is their a better method (maybe shorter) that i can repeat for each of my 50 products

Why not store your products in a collection (a List) such that you can iterate through each one and total as you go ? If you have a Product object you can then assign a price to each as a member and iterate through totalling as you go.

for (Product p : listOfProducts) {
   sum = sum + p.price * quantity;
}

Note that I would pull the above out into a price calculator or similar such that you can run and test (via a unit test framework such as JUnit) separately from the GUI Swing code.


One thing that can be done is that you can use an array of TextBox and create a function that calculates the value and inserts in the Arraylist and this function is called in a loop inside the button event handler method. Also try to use ArrayList<String> instead of ArrayList. That ensures stronger type checking.


Some tips for you on best practices since you mentioned it:

double priceA = 20.00;

First of all double isn't exactly precise, you should watch out if you plan to use floating point variables to make any calculations that have to be 100% accurate (such as money calculations), use java.math.BigDecimal class instead.

Secondly you should store all constant (fixed) values at the top of your class where you define your variables, so you don't have any "magic numbers" roaming about.

Example: private static final double priceA = 20.00

This way you don't have to re-define the variables each time you access the method.

Thirdly you should always be suspicious of user input and handle it.

What would happen here Integer.parseInt(strA) if I for example would leave one of the text boxes empty?

Or even worse what if I would write some text there instead of numbers?

You should always be aware that users will not always use your program as intended and will even try to break it.

Finally you could define a calculating method outside of this method that would simplify your current method.

From your example it could look something like this:

private String calculcateTotal(double price, String amount) {
    int actualAmount = Integer.parseInt(amount);
    double totalAmount = (price * actualAmount);
    return String.valueOf(totalAmount);
}

Which would reduce your original method down to:

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {

   double priceA = 20.00;
   double priceB = 25.00;
   double priceC = 30.00;

    ArrayList caselist = new ArrayList();
    caselist.add("Case A Total - £" + calculateTotal(priceA, txtbxCaseA.getText()));
    caselist.add("Case B Total - £" + calculateTotal(priceB, txtbxCaseB.getText()));
    caselist.add("Case C Total - £" + calculateTotal(priceC, txtbxCaseC.getText()));

    DefaultListModel myModel = new DefaultListModel ();

    for(int i = 0; i < caselist.size(); i++){
        jTextArea3.append((String)caselist.get(i) + ('\n'));
        myModel.addElement(caselist.get(i) + ",");

        /*
        - save arraylist to a gobal varible for cart processing
        - move to next panel (page) along
        */
    }
}

See how it looks neater now?

And you could even omit the

double priceA = 20.00;
double priceB = 25.00;
double priceC = 30.00;

if you had defined them at the top of your class like I mentioned before.


My advice would be to separate the business logic from the presentation logic and you'll end up with something like this:

/**
 * Represents the concept of getting a `Integer` quantity from some source.
 */
public inteface Quantity
{
  public Integer getValue();
}

/**
 * Represents the combination of a price and quantity to produce a total.
 */    
public class Total
{
  private double price;
  private Quantity quantity;

  public Total(double price, Quantity quantity)
  {
    this.price = price;
    this.quantity = quantity;
  }

  public Double getValue()
  {
    Integer quantity = quantity.getValue();
    return quantity != null ? quantity * price : null; 
  }
}

Then you can use this inteface and class in your Swing code like this (which is only intended to show the interaction with Swing, not how to layout the controls):

public class MyFrame extends JFrame
{
  private static final List<Double> PRICES = Arrays.asList(20.0, 25.0, 30.0);      

  public MyFrame()
  {
    List<Total> totals = new ArrayList<Total>();

    JList totalsList = new JList(new TotalListModel(totals));
    addComponent(totalsList);

    for (Double price : PRICES)
    {
      JTextField quantityTextField = new JTextField();
      quantityTextField.addActionListener(new RepaintComponentActionListener(totalsList));
      addComponent(quantityTextField);

      totals.add(new Total(price, new TextFieldQuantity(quantityTextField)));
    }
  }

  private class TotalListModel extends AbstractListModel
  {
    private List<Total> totals;

    public TotalListModel(List<Total> totals)
    {
      this.totals = totals;  
    }

    public Object getElementAt(int index) 
    {
      Double value = totals.get(index).getValue();
      return value != null ? value.toString() : "NO VALUE";
    }

    public int getSize() 
    {
      return totals.size();
    }
  }

  private class TextFieldQuantity implements Quantity
  {
    private JTextField textField;

    public TextFieldQuantitySource(JTextField textField)
    {
      this.textField = textField;
    }

    public Integer getQuantity()
    {
      try
      {
        return Integer.parseInt(textField.getText()); 
      }
      catch (NumberFormatException e)
      {
        return null; 
      } 
    }
  }

  private class RepaintComponentActionListener implements ActionListener
  {
    private Component component;

    public RefreshControlActionListener(Component component)
    {
      this.component = component;
    }

    public void actionPerformed(ActionEvent actionEvent) 
    {
      component.repaint();
    }
  }
}    

In case it's not immediately clear how this code is working, it uses:

  • a custom ListModel to wrap the totals meaning that the JList simply needs repainting and the current totals will be displayed.
  • a loop over the PRICES to dynamically create the JTextField controls (I'll leave it for you to work out the layout).
  • a custom ActionListener that repaints the JList when any of the JTextFields change.
  • a custom Quantity that reads the value from the JTextField.

Need Your Help

Rewrite iOS app from scratch "Could not change executable permissions on the application."

ios xcode

I have an app on the store for which I want to start rewriting the entire application "from scratch". When I try to build and execute the new app on my device (iPhone 4) which already contains the ...

Should I use PHP or JSP for a chat website?

java php javascript ajax jsp

I want to develop a website web chat application like yahoo. Only difference is that I want to make it web based not desktop.