您的位置:寻梦网首页编程乐园Java天地Core JavaJava Lecture Notes

Introduction

Content

Apply

Reflect

Extend

previous.gif
 (3087 bytes)

next.gif
 (2959 bytes)


Extend Index

Extend Page # 16

Listing of Loan.java

/*=======================================

Loan.java

This applet calculates the time it would take to repay a loan of money, when

interest is being charged. For example, if I borrow ? million, and I pay

back ?00,000 every year, how long will it take to pay off the whole loan?

If we can answer this question, it is very easy to answer another important

question: how much do I pay in total, including interest?

This applet calculate both these figures, from the user’s figures for

amount borrowed, interest rate and repayment amount. It doesn’t matter

what units of currency are used, as long as you are consistent (i.e.,

the repayment amount and the amount borrowed are in the same currency).

The interest rate should be entered as a percentage.

The programs’s display looks like this:

<img src=loan.gif>

<p>

(If you aren’t looking at the HTML version of this file, you won’t see

the picture)

The user should enter the appropriate figures, then click on `Calculate’

to get the results.

This is a good program for demonstrating Java’s exception handling

mechanisms, as there’s any number of things that can go wrong in this

program. For example:

1. The user may not fill all the data entry fields in

2. The user may enter values which are not numbers at all (e.g., text)

3. The user may enter values which are valid numbers, but are nonetheless

invalid in the context of this application (e.g., repayments of zero)

4. The values may all be sensible, but it is still impossible to get

a sensible result. This will happen if the amount of the repayment

is less than the interest on the loan (then the loan will never be

repayed)

A good program will deal correctly with all these problems, and produce

sensible guidance to the user in each case. It is never acceptable in

modern practice for a program to say `INVALID DATA’ and shut down!

You will notice that in this application approximately half the code

is concerned with checking and handling errors. But the good thing about the

exception throwing scheme is that the `normal’ program code and the

`error’ program code is largely separate. In this program, the exception

classes are all defined after the main part of the program

Please note that I am not an accountant, so I can’t be sure that my

repayment calculations are correct!

Kevin Boone, July 1999

==============================================================================*/

import java.applet.Applet;

import java.awt.*;

import java.awt.event.*;

/*==============================================================================

Loan class

Defines a sub-type of applet that implements a loan calculator

==============================================================================*/

public class Loan extends Applet implements ActionListener

{

/*==============================================================================

Attributes of Loan class

==============================================================================*/

// We store the objects that correspond to data entry fields as attributes,

// as when the user starts a calculation we will need to refer to them

// to get the data out

TextField amountBorrowedField;

TextField interestRateField;

TextField repaymentField;

// The result label is that part of the display where the result will be

// displayed

Label resultLabel;

/*==============================================================================

Loan constructor

This method (as with all constructors) is executed when the new object

is created.

The applet’s display area has three main parts; from top to bottom these

are: the result display, the data entry area, and the `calculate’

button. The data entry area has three text areas and the corresponding

labels. This part is organized as a grid of 3 rows and 2 columns.

The main display is organized as a BorderLayout. The data entry area

will go in the centre of this area, the result area at the top

(`North’) and the calculate button at the bottom (`South’).

==============================================================================*/

public Loan()

{

super();

Panel entryPanel = new Panel();

entryPanel.setLayout (new GridLayout(3, 2));

Label l = new Label ("Amount borrowed:");

l.setAlignment (Label.RIGHT);

entryPanel.add(l);

amountBorrowedField = new TextField();

entryPanel.add(amountBorrowedField);

l = new Label ("Interest rate (%):");

l.setAlignment (Label.RIGHT);

entryPanel.add(l);

interestRateField = new TextField();

entryPanel.add(interestRateField);

l = new Label ("Repayment:");

l.setAlignment (Label.RIGHT);

entryPanel.add(l);

repaymentField = new TextField();

entryPanel.add(repaymentField);

setLayout(new BorderLayout());

add(entryPanel, "Center");

resultLabel = new Label("?");

resultLabel.setAlignment(Label.CENTER);

add(resultLabel, "North");

Button calculateButton = new Button("Calculate");

calculateButton.addActionListener(this);

add(calculateButton , "South");

}

/*==============================================================================

getFieldValue

This method attempts to get a numerical value from a specified data entry

field. If this cannot be accomplished, for any reason, it throws an exception

to indicate the reason. The caller of this method is responsible for

dealing with the exception if one arrives.

This method has three arguments. The first, `field’ is the data entry

field itself. This will have been created in the constructor with a

call to `new TextField()’. The second is the name of the field. This name will

be saved in the exception if anything goes wrong, so that the exception can

display an error message indicating where the error occured. Finally

`zeroAllowed’ is `true’ if it is meaningful for the data entry field to have

`zero’ as its value. In this application, the interest rate can meaningfully

be zero, but none of the other fields can

==============================================================================*/

double getFieldValue (TextField field, String fieldName, boolean zeroAllowed)

throws EmptyNumberFieldException,

NotANumberException,

NegativeNotAllowedException,

ZeroNotAllowedException

{

// First get the text value out of the data entry fieinto a

// String.

String stringValue = field.getText();

// Is the data entry field empty? If so, throw an

// EmptyNumberFieldExceptino. Note that the name of the field is

// passed to the exception’s constructor, so that it can be stored

// and used in error messages

if (stringValue.equals(""))

throw (new EmptyNumberFieldException(fieldName));

try

{

// Now try to convert the string to a double value.

// If this fails (e.g., if the data is not a number), then

// a NumberFormatException will be thown. We will catch

// that exception, and convert it to a NotANumberException.

// The main reason for doing this is that the built-in

// NumberFormatException displays a very ugly and unhelpful

// error messages, which we can improve upon easily.

double value = Double.parseDouble(stringValue);

// If the value is negative, throw and NegativeNotAllowedException

 

/// QUESTION: if we do throw a NegativeNotAllowedException, what is

/// the _next_ line of program that will be executed?

if (value < 0) throw (new NegativeNotAllowedException(fieldName));

// If the value is zero, and it is not allowed to be, throw a

// zeroNotAllowedException.

if (value == 0.0 && !zeroAllowed) throw (new ZeroNotAllowedException(fieldName));

return value;

}

catch(NumberFormatException e)

{

 

/// QUESTION: what line of program was executed immediately

/// before this one?

throw (new NotANumberException(fieldName, stringValue));

}

}

/*==============================================================================

calculateNumberOfRepayments

This method calculates the number of repayments, given the specified

amount, repayment and interest rate. Note that the final repayment may

not be of the full amount, as by this point there may be less money owing than

the size of the repayment.

This method can throw a `NeverRepayException’ if it detects that the

amount of the repayment is not large enough to pay the loan at all

==============================================================================*/

public int calculateNumberOfRepayments (double amountBorrowed, double interestRate,

double repayment)

throws NeverRepayException

{

int repayments = 0;

double sumOutstanding = amountBorrowed;

while (sumOutstanding > 0)

{

// Add the interest to the remaining balance

double newSumOutstanding = sumOutstanding +

sumOutstanding * interestRate / 100.0;

// Now subtract the repayment

newSumOutstanding = newSumOutstanding - repayment;

// See if the amount has gone down; if not, the

// loan will never be repayed

if (newSumOutstanding >= sumOutstanding)

throw (new NeverRepayException());

// For each repayment, add one to the number of repayments

repayments++;

// So the new balance becomes the input to the next cycle, and

// so on, until the whole sum is repayed.

sumOutstanding = newSumOutstanding;

}

return repayments;

}

/*==============================================================================

actionPerformed

This method is called whenever the user clicks a button. Since there is

only one button, and no menus, we can assume that when this method is

called, it is because the user has clicked `calculate’ and wants to calculate

a result

==============================================================================*/

public void actionPerformed (ActionEvent actionEvent)

{

//RepaymentCalculator = new RepaymentCalculator();

try

{

double amountBorrowed = getFieldValue (amountBorrowedField, "Amount", false);

double interestRate = getFieldValue (interestRateField, "Interest rate", true);

double repayment = getFieldValue (repaymentField, "Repayment", false);

// If we get this far, the values for amount borrowed, interest rate,

// and repayment amount have been entered, and they are basically

// sensible. So now we can try to calculate the repayment time

// and repayment amount. Of course, this can still go wrong,

// as the amount of repayment may not be sufficient to pay

// the loan however long it is repayed over

int numberOfRepayments = calculateNumberOfRepayments

(amountBorrowed, interestRate, repayment);

double totalRepayment = numberOfRepayments * repayment;

resultLabel.setText ("" + numberOfRepayments + " repayments, repaying "

+ totalRepayment + " in total");

}

catch (Exception e)

{

 

/// QUESTION: there are four lines of prgram that could have been

/// executed before this one. What are they?

resultLabel.setText(e.toString());

 

/// QUESTION: this program can generate two `type’ of exception:

/// NeverRepayedException, and all the sub-classes of

/// BadValueEnteredException. As these are all subclasses of

/// Exception, the line of program above will `catch’ all of

/// them. However, I may want to treat these two `types’ of

/// exception differently. How could I change this piece of

/// the program slightly to make that possible (hint: we

/// only need to add a few lines)

}

}

} // class

/*==============================================================================

This is the end of the `Loan’ class. We now define all the classes that

are used for exception handling

In general each of these classes only has two methods: a constructor and

a method `toString’. By convention the `toString’ method is used to

supply an error message. So when the program catches an exception, it calls

the exception’s toString() method to generate an error message. The

constructor is used to set values for any of the data that will be stored in

the exception, usually for inclusion in the error message.

==============================================================================*/

/*==============================================================================

NeverRepayException

This exception is thrown by calculateNumberOfRepayments when it detects that

the amount of the repayment is not large enought to pay off the loan in

any length of time

==============================================================================*/

class NeverRepayException extends Exception

{

// constructor

NeverRepayException()

{

super("NeverRepayException");

}

// toString

// Displays the error message appropriate for this exception

public String toString()

{

return new String("Repayment is not large enough; loan never repayed");

}

} // class

 

/*==============================================================================

BadValueEnteredException

This is the base class for all the exceptions that are concerned with the

user entering invalid data values. Note that this is an abstract class; this

exception can never be thrown. The program must created one of the subclasses

of this class and throw that instead. This class is used for grouping the

sub-classes in a coherent way

==============================================================================*/

 

/// QUESTION: why does this class have two constructors?

abstract class BadValueEnteredException extends Exception

{

String fieldName;

String fieldValue;

// constructor

BadValueEnteredException(String _fieldName)

{

super("Bad number value entered");

fieldName = _fieldName;

}

// constructor

BadValueEnteredException(String _fieldName, String _fieldValue)

{

super("Bad number value entered");

fieldName = _fieldName;

fieldValue = _fieldValue;

}

} // class

/*==============================================================================

EmptyNumberFieldException

This exception is thrown if the user leaves a data entry field blank.

==============================================================================*/

class EmptyNumberFieldException extends BadValueEnteredException

{

// constructor

EmptyNumberFieldException(String fieldName)

{

super(fieldName);

}

// toString

// Displays the error message appropriate for this exception

public String toString()

{

return new String("No value entered for `" + fieldName + "‘");

}

} // class

 

/*==============================================================================

ZeroNotAllowedException

This exception is thrown when the user enters a value that is zero, and zero

is not a meaningful entry. For example, is meaningless to make a repayment

of `0’, or to borrow `0’. Note, however, that `0’ is a credible value for the

interest rate

==============================================================================*/

class ZeroNotAllowedException extends BadValueEnteredException

{

// constructor

ZeroNotAllowedException(String fieldName)

{

super(fieldName);

}

// toString

// Displays the error message appropriate for this exception

public String toString()

{

return new String("`" + fieldName + "‘ cannot be zero");

}

} // class

 

/*==============================================================================

NegativeNotAllowedException

This exception is thrown when the user enters a value that is negative

In this program, it is not meaningful for any field to have a negative value

==============================================================================*/

class NegativeNotAllowedException extends BadValueEnteredException

{

// constructor

NegativeNotAllowedException(String fieldName)

{

super(fieldName);

}

// toString

// Displays the error message appropriate for this exception

public String toString()

{

return new String("`" + fieldName + "‘ cannot be negative");

}

} // class

 

/*==============================================================================

NotANumberException

==============================================================================*/

class NotANumberException extends BadValueEnteredException

{

// constructor

NotANumberException(String fieldName, String fieldValue)

{

super(fieldName, fieldValue);

}

// toString

// Displays the error message appropriate for this exception

public String toString()

{

return new String("Value entered for `"

+ fieldName + "‘ (" + fieldValue + ") is not a number");

}

} // class

Back to top

 basicline.gif (169 bytes)

RITSEC - Global Campus
Copyright ?1999 RITSEC- Middlesex University. All rights reserved.
webmaster@globalcampus.com.eg