5
\$\begingroup\$

I'm working on a class project for my intro to Java class. My background is in accounting/finance so I decided to make this simple calculator that helps the user decide what they can afford and how much they can save on interest expense over the loan term. I'm just looking for general feedback on code structure and tips/advice on better ways to clean up the code or make it more efficient.

Regarding layout, I chose to challenge myself and create the GUI without using Window builder and just start typing out the code. As such, I used gridlayout for ease of organization.

import javax.swing.JFrame;

public class Main {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    Calculator calculator = new Calculator();

    calculator.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    calculator.pack();
    calculator.setVisible(true);



}



}

import javax.swing.JFrame;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import javax.swing.JLabel;
import javax.swing.JOptionPane;

public class Calculator extends JFrame {
private JButton b1, b2, b3, b4;
private JTextField t1, t2, t3, t4, t5, t6, t7;
private JLabel l1, l1a, l2, l3, l4, l5, l6, l7, l8, l9, l10;
private JLabel l11, l12, l13, l14, l15, l16, l17, l18, l19, l20;
private JLabel l21, l22, l23, l24, l25, l26;


public Calculator()
{
    JPanel panel1 = new JPanel();
    JPanel panel2 = new JPanel();
    JPanel panel4 = new JPanel();


    panel1.setLayout(new GridLayout(6,4,10,0));
    panel1.setBorder(BorderFactory.createLineBorder(Color.GRAY));
    panel2.setLayout(new GridLayout(2,1));
    panel2.setBackground(new Color(83, 116, 246));
    panel2.setBorder(BorderFactory.createLineBorder(Color.GRAY));
    panel4.setLayout(new GridLayout(6,2,10,0));
    panel4.setBorder(BorderFactory.createLineBorder(Color.GRAY));


    add(panel1, BorderLayout.PAGE_END);
    add(panel2, BorderLayout.PAGE_START);
    add(panel4, BorderLayout.CENTER);


    //panel 1

    l2 = new JLabel("Purchase Price");
    t1 = new JTextField(10);
    l2.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    l9 = new JLabel("30 Yr Monthly Payment");
    l15 = new JLabel("0.00");
    l15.setForeground(new Color(0, 0, 153));
    l15.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    panel1.add(l2);
    panel1.add(t1);
    panel1.add(l9);
    panel1.add(l15);

    l3 = new JLabel("Down Payment (%)");
    t2 = new JTextField(10);
    l3.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    l10 = new JLabel("Total Interest Paid");
    l16 = new JLabel("0.00");
    l16.setForeground(new Color(255, 51, 0));
    l16.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    panel1.add(l3);
    panel1.add(t2);
    panel1.add(l10);
    panel1.add(l16);

    l4 = new JLabel("Interest Rate (APR%)");
    t3 = new JTextField(10);
    l4.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    l11 = new JLabel("20 Yr Monthly Payment");
    l17 = new JLabel("0.00");
    l17.setForeground(new Color(0, 0, 153));
    l17.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    panel1.add(l4);
    panel1.add(t3);
    panel1.add(l11);
    panel1.add(l17);

    l5 = new JLabel("Annual Property Tax");
    t4 = new JTextField(10);
    l5.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    l12 = new JLabel("Total Interest Paid");
    l18 = new JLabel("0.00");
    l18.setForeground(new Color(255, 51, 0));
    l18.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    panel1.add(l5);
    panel1.add(t4);
    panel1.add(l12);
    panel1.add(l18);

    l25 = new JLabel("Include Mortgage Insurance?");
    l26 = new JLabel("");
    l25.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    l13 = new JLabel("15 Yr Monthly Payment");
    l19 = new JLabel("0.00");
    l19.setForeground(new Color(0, 0, 153));
    l19.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    panel1.add(l25);
    panel1.add(l26);
    panel1.add(l13);
    panel1.add(l19);

    b1 = new JButton("Clear"); 
    b2 = new JButton("Payments & Total Interest");
    l14 = new JLabel("Total Interest Paid");
    l20 = new JLabel("0.00");
    l20.setForeground(new Color(255, 51, 0));
    l20.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    panel1.add(b1);
    panel1.add(b2);
    panel1.add(l14);
    panel1.add(l20);

    ButtonListener bl = new ButtonListener();
    b1.addActionListener(bl);
    b2.addActionListener(bl);


    //panel 2


    l1 = new JLabel("Affordability Calculator");
    l1a = new JLabel("Calculate Monthly Payments, Total Interest Expense,     and your Maximum Affordability");
    panel2.add(l1);
    panel2.add(l1a);
    l1.setFont(new Font("Helvetica", Font.BOLD,14));
    l1a.setFont(new Font("Helvetica", Font.ITALIC,12));
    l1.setForeground(new Color(255, 255, 255));
    l1a.setForeground(new Color(255, 255, 255));

    //panel 4
    l6 = new JLabel("Gross Monthly Income (From wages and other taxable income)");
    t5 = new JTextField(10);
    l6.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    panel4.add(l6);
    panel4.add(t5);

    l7 = new JLabel("Recurring Monthly Debt (Car payments, other loan payments)");
    t6 = new JTextField(10);
    l7.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    panel4.add(l7);
    panel4.add(t6);

    l8 = new JLabel("Credit Card Payments (Total minimum amount due)");
    t7 = new JTextField(10);
    l8.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    panel4.add(l8);
    panel4.add(t7);

    l21 = new JLabel("Maximum Monthly Payment @ 36% Debt-to-Income");
    l22 = new JLabel("0.00");
    l22.setForeground(new Color(0, 0, 153));
    l22.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    panel4.add(l21);
    panel4.add(l22);

    l23 = new JLabel("Maximum Monthly Payment @ 45% Debt-to-Income");
    l24 = new JLabel("0.00");
    l24.setForeground(new Color(0, 0, 153));
    l24.setFont(new Font("Arial Rounded MT Bold", Font.PLAIN, 12));
    panel4.add(l23);
    panel4.add(l24);


    b3 = new JButton("Clear"); 
    b4 = new JButton("Calculate Max Affordability");
    panel4.add(b3);
    panel4.add(b4);
    b3.addActionListener(bl);
    b4.addActionListener(bl);



}



private class ButtonListener implements ActionListener 
{

    public void actionPerformed(ActionEvent event)
    {
        ButtonFunction bf = new ButtonFunction();
        NumberFormat nf = NumberFormat.getCurrencyInstance();

        if(event.getSource() == b2)
        {
            try
            {
                bf.CalcPayInt(Double.parseDouble(t1.getText()), Double.parseDouble(t2.getText()), Double.parseDouble(t3.getText()), Double.parseDouble(t4.getText()));
                l15.setText(nf.format(bf.getMonthlyPay30()));
                l16.setText(nf.format(bf.getTotalInt1()));
                l17.setText(nf.format(bf.getMonthlyPay20()));
                l18.setText(nf.format(bf.getTotalInt2()));
                l19.setText(nf.format(bf.getMonthlyPay15()));
                l20.setText(nf.format(bf.getTotalInt3()));

                if(Double.parseDouble(t2.getText()) < 20)
                {
                    l26.setText("Yes - avg $100/mo");
                }
                else 
                {
                    l26.setText("No - 20% or more down");
                }

            } catch(Exception e)
            {
                JOptionPane.showMessageDialog(null, "Please enter a valid number");
            }

        }
        if(event.getSource() == b1)
        {
            t1.setText("");
            t2.setText("");
            t3.setText("");
            t4.setText("");
            l26.setText("");
            l15.setText("0.00");
            l16.setText("0.00");
            l17.setText("0.00");
            l18.setText("0.00");
            l19.setText("0.00");
            l20.setText("0.00");
        }
        if(event.getSource() == b3)
        {
            t5.setText("");
            t6.setText("");
            t7.setText("");
            l22.setText("0.00");
            l24.setText("0.00");
        }

        if(event.getSource() == b4)
        {
            try
            {
                bf.calcDTI(Double.parseDouble(t5.getText()), Double.parseDouble(t6.getText()), Double.parseDouble(t7.getText()));
                l22.setText(nf.format(bf.getMaxPay1()));
                l24.setText(nf.format(bf.getMaxPay2()));

            }
            catch(Exception e2)
            {
                JOptionPane.showMessageDialog(null, "Please enter a valid number");
            }
        }


    }


}



}




public class ButtonFunction {
private double purchasePrice;
private double loanAmount;
private double monthlyIntRate;
private double downPayment;
private double monthlyTax;
private double monthlyPay1;
private double monthlyPay2;
private double monthlyPay3;
private double totalInt1;
private double totalInt2;
private double totalInt3;
private double termMonths1 = 360.0; //30 year term
private double termMonths2 = 240.0; //20 year term
private double termMonths3 = 180.0; //15 year term
private final double PMI = 100.0; //average mortgage insurance monthly cost
private double totalDebt;
private double grossIncome;
private double maxPay1;
private double maxPay2;
private final double DTI1 = .36;
private final double DTI2 = .45;


public void CalcPayInt(double purchasePrice, double downPayment, double intRate, double tax)
{
    this.purchasePrice = purchasePrice;
    this.downPayment = purchasePrice * (downPayment/100);
    this.loanAmount = purchasePrice - this.downPayment; 
    this.monthlyIntRate = (intRate/100)/12; 
    this.monthlyTax = tax/12;

    //M = P [ i(1 + i)^n ] / [ ((1 + i)^n) - 1]

    monthlyPay1 = (loanAmount * ((monthlyIntRate * Math.pow((1 + monthlyIntRate),termMonths1)) / 
    (Math.pow((1 + monthlyIntRate), termMonths1) - 1))) + monthlyTax;
    totalInt1 = ((monthlyPay1 - monthlyTax) * termMonths1) - loanAmount;

    monthlyPay2 = (loanAmount * ((monthlyIntRate * Math.pow((1 + monthlyIntRate),termMonths2)) / 
    (Math.pow((1 + monthlyIntRate), termMonths2) - 1))) + monthlyTax;
    totalInt2 = ((monthlyPay2 - monthlyTax) * termMonths2) - loanAmount;

    monthlyPay3 = (loanAmount * ((monthlyIntRate * Math.pow((1 + monthlyIntRate),termMonths3)) / 
    (Math.pow((1 + monthlyIntRate), termMonths3) - 1))) + monthlyTax;
    totalInt3 = ((monthlyPay3 - monthlyTax) * termMonths3) - loanAmount;
}

public void calcDTI(double grossIncome, double debt, double creditCards)
{
    this.grossIncome = grossIncome;
    this.totalDebt = debt + creditCards;

    maxPay1 = (grossIncome * DTI1) - totalDebt;
    maxPay2 = (grossIncome * DTI2) - totalDebt;
}

public double getMonthlyPay30()
{
    if(downPayment < (purchasePrice * 0.20))
    {
        return monthlyPay1 + PMI;
    } else
    {
        return monthlyPay1;
    }

}

public double getMonthlyPay20()
{
    if(downPayment < (purchasePrice * 0.20))
    {
        return monthlyPay2 + PMI;
    } else
    {
        return monthlyPay2;
    }
}

public double getMonthlyPay15()
{
    if(downPayment < (purchasePrice * 0.20))
    {
        return monthlyPay3 + PMI;
    } else
    {
        return monthlyPay3;
    }
}
public double getTotalInt1()
{
    return totalInt1;
}

public double getTotalInt2()
{
    return totalInt2;
}

public double getTotalInt3()
{
    return totalInt3;
}

public double getMaxPay1()
{
    return maxPay1;
}

public double getMaxPay2()
{
    return maxPay2;
}

}

enter image description here

\$\endgroup\$
5
\$\begingroup\$

Avoiding code repetition

new Font("Arial Rounded MT Bold", Font.PLAIN, 12)

Your font specification is repeated throughout, you can set this as a static final variable so that your UI elements need to only reference one of it:

// inside Calculator
private static final Font DEFAULT_FONT = new Font("Arial Rounded MT Bold", Font.PLAIN, 12);

// usage
purchasePriceLabel = new JLabel("Purchase Price");
purchasePriceLabel.setFont(DEFAULT_FONT);

Variables naming

l1, t2, b3 are poor names for variables, as they give no context as to what they are. It is easier to read them as purchasePriceLabel, interestRateText and clearButton. Sometimes, if you do not need to refer to a UI element beyond the initial assignment, e.g. for those labels, you can even combine the usage of a utility method and method-call-inlining to simplify the declaration. For example:

private static JLabel createLabel(String text) {
    return createLabel(text, DEFAULT_FONT, DEFAULT_COLOR);
}

private static JLabel createLabel(String text, Font font, Color color) {
    JLabel label = new JLabel(text);
    label.setFont(font);
    label.setColor(color);
    return label;
}

// usage
panel.add(createLabel("Purchase Price"));
panel.add(createLabel("Some special text", LARGE_FONT, Color.RED));

In these cases, you don't need temporary variables outside of the utility method to add them to the JPanel.

Method and variable names should also be in camelCase, so that they are not confused with PascalCase class names. This means ButtonFunction.CalcPayInt() can be better renamed as ButtonFunction.getPaymentInterest(), and the PMI/DTI1/DTI2 class variables can be renamed as pmi/dti1/dti2 as well. Again, if you feel not using the short forms lend the variables more context, then you should use their long forms too.

Miscellaneous

I think there is room for improvement for your code formatting inside the CalcPayInt() method. For example, having indented lines makes it easier to understand that they follow the preceding line:

// original
monthlyPay1 = (loanAmount * ((monthlyIntRate * Math.pow((1 + monthlyIntRate),termMonths1))/
(Math.pow((1 + monthlyIntRate), termMonths1) - 1))) + monthlyTax;
totalInt1 = ((monthlyPay1 - monthlyTax) * termMonths1) - loanAmount;

// suggested improvement
monthlyPay1 = (loanAmount * ((monthlyIntRate * Math.pow((1 + monthlyIntRate),termMonths1))/
                    (Math.pow((1 + monthlyIntRate), termMonths1) - 1))) + monthlyTax;
totalInt1 = ((monthlyPay1 - monthlyTax) * termMonths1) - loanAmount;
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Thank you very much for your feedback! Just what I needed \$\endgroup\$ – Sulaiman Syed Oct 29 '15 at 1:28
  • \$\begingroup\$ @SulaimanSyed Glad to help! \$\endgroup\$ – h.j.k. Oct 29 '15 at 1:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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