Is this precondition a violation of the Liskov Substitution Principle - java

I have 3 classes, Account, CappedAccount, UserAccount,
CappedAccount, and UserAccount both extend Account.
Account contains the following:
abstract class Account {
...
/**
* Attempts to add money to account.
*/
public void add(double amount) {
balance += amount;
}
}
CappedAccount overrides this behavior:
public class CappedAccount extends Account {
...
#Override
public void add(double amount) {
if (balance + amount > cap) { // New Precondition
return;
}
balance += amount;
}
}
UserAccount doesn't override any methods from Account, so it doesn't need to be stated.
My question is, does CappedAccount#add violate LSP, and if it does, how can I design it to comply with LSP.
For example, does add() in CappedAccount count as "strengthening preconditions"?

It's important to remember the LSP covers both syntax and semantics. It covers both what the method is coded to do, and what the method is documented to do. This means vague documentation can make it difficult to apply the LSP.
How do you interpret this?
Attempts to add money to account.
It's clear the add() method is not guaranteed to add money to the account; so the fact that CappedAccount.add() may not actually add money seems acceptable. But there is no documentation of what should be expected when an attempt to add money fails. Since that use case is undocumented, "do nothing" seems like an acceptable behavior, and therefore we have no LSP violation.
To be on the safe side, I would amend the documentation to define expected behavior for a failed add() i.e. explicitly define the post-condition. Since the LSP covers both syntax and semantics, you can fix a violation by modifying either one.

TLDR;
if (balance + amount > cap) {
return;
}
is not a precondition but an invariant, hence not a violation (on his own) of the Liskov Substition Principle.
Now, the actual answer.
A real precondition would be (pseudo code):
[requires] balance + amount <= cap
You should be able to enforce this precondition, that is check the condtion and raise an error if it is not met. If you do enforce the precondition, you'll see that the LSP is violated:
Account a = new Account(); // suppose it is not abstract
a.add(1000); // ok
Account a = new CappedAccount(100); // balance = 0, cap = 100
a.add(1000); // raise an error !
The subtype should behave like its supertype (see below).
The only way to "strengthen" the precondition is to strenghten the invariant. Because the invariant should be true before and after each method call. The LSP is not violated (on his own) by a strengthened invariant, because the invariant is given for free before the method call: it was true at the initialisation, hence true before the first method call. Because it's an invariant, it is true after the first method call. And step by step, is always true before the next method call (this is a mathematicual induction...).
class CappedAccount extends Account {
[invariant] balance <= cap
}
The invariant should be true before and after the method call:
#Override
public void add(double amount) {
assert balance <= cap;
// code
assert balance <= cap;
}
How would you implement that in the add method? You have some options. This one is ok:
#Override
public void add(double amount) {
assert balance <= cap;
if (balance + amount <= cap) {
balance += cap;
}
assert balance <= cap;
}
Hey, but that's exactly what you did! (There is a slight difference: this one has one exit to check the invariant.)
This one too, but the semantic is different:
#Override
public void add(double amount) {
assert balance <= cap;
if (balance + amount > cap) {
balance = cap;
} else {
balance += cap;
}
assert balance <= cap;
}
This one too but the semantic is absurd (or a closed account?):
#Override
public void add(double amount) {
assert balance <= cap;
// do nothing
assert balance <= cap;
}
Okay, you added an invariant, not a precondition, and that's why the LSP is not violated. End of the answer.
But... this is not satisfying: add "attempts to add money to account". I would like to know if it was a success!! Let's try this in the base class:
/**
* Attempts to add money to account.
* #param amount the amount of money
* #return True if the money was added.
*/
public boolean add(double amount) {
[requires] amount >= 0
[ensures] balance = (result && balance == old balance + amount) || (!result && balance == old balance)
}
And the implementation, with the invariant:
/**
* Attempts to add money to account.
* #param amount the amount of money
* #return True is the money was added.
*/
public boolean add(double amount) {
assert balance <= cap;
assert amount >= 0;
double old_balance = balance; // snapshot of the initial state
bool result;
if (balance + amount <= cap) {
balance += cap;
result = true;
} else {
result = false;
}
assert (result && balance == old balance + amount) || (!result && balance == old balance)
assert balance <= cap;
return result;
}
Of course, nobody writes code like that, unless you use Eiffel (that might be a good idea), but you see the idea. Here's a version without all the conditions:
public boolean add(double amount) {
if (balance + amount <= cap) {
balance += cap;
return true;
} else {
return false;
}
Please note the the LSP in its original version ("If for each object o_1 of type S there is an object o_2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o_1 is substituted for o_2, then S is a subtype of T") is violated. You have to define o_2 that works for each program. Choose a cap, let's say 1000. I'll write the following program:
Account a = ...
if (a.add(1001)) {
// if a = o_2, you're here
} else {
// else you might be here.
}
That's not a problem because, of course, everyone uses a weaken version of the LSP: we don't want the beahvior to be unchanged (subtype would have a limited interest, performance for instance, think of array list vs linked list)), we want to keep all "the desirable properties of that program" (see this question).

Related

bank account program using aspectj

I want to write a java program that would keep track of a bank account
right now I have the following simple program:
public class account
{
private double balance;
private String owner;
public account(double x, String s) { balance=x; owner=s; }
public String owner() { return owner; }
public void withdraw(double a) { balance -= a; }
public void deposit(double a) { balance += a; }
public void printbalance() { System.out.println(balance); }
// main for testing:
public static void main(String[] argv)
{
account a1 = new account(2000,"you boss");
account a2 = new account(1000,"me nerd");
a1.deposit(400);
a2.withdraw(300000); // not enough money!
a2.withdraw(-500000); // trying to cheat!
a1.printbalance();
a2.printbalance();
}//main
} // account
And I want to add to this program using aspectj the following:
1- I want to prevent the account from withdraw a greater amount of the current balance and withdraw a negative numbers.
2- also I want it to prevent deposit a negative numbers.
3- I need to add a graphical interface , (buttons )
4- add secret pin or password that needs to be entered before a customer can make transaction.
5- keep track of all the transactions (withdraws and deposits) made on an account, and print out a report when asked for.
I would appreciate your help. Thank you.
privileged aspect newAccount
{
//withdraw (prevent withdraw negative numbers and number greater than the //current balance)
void around(account a, double x) : execution(void account.withdraw(double)) && target(a) && args(x){
if(x > a.balance){
System.out.println("not enough money!");
return;
}else if(x < 0){
System.out.println("trying to cheat!");
return;
}
proceed(a, x);
}
//Deposit: prevent deposit negative number
void around(double x) : execution(void account.deposit(double)) && args(x){
if(x < 0){
System.out.println("trying to deposit negtive money!");
return;
}
proceed(x);
}
after() : execution(public static void *.main(String[])){
account.a3 = new account(3000,"he nerd");
a3.deposit(-100);
a3.printbalance();
}
//To Do: pin secret password
//To Do: Transaction Record
}
I can see that you are still learning Java because you don't know the basic programming conventions such as that
class names should start with an upper case letter,
variables, parameters and fields should have understandable names not not single letters.
You are also using direct field access from a privileged aspect instead of just creating public getter methods for your class's fields and using those. A toString method is also helpful because then you can easily print the object without accessing getters and fabricating your own output.
Besides, the advice running after the main method is a nice experiment but does not make make much sense. Because the account owner has the same name as one of the account owners in your application, it looks as if you want to hack into that account. I commented the code there so as to explain why it cannot work like that.
I also refactored both your application class and the aspect to now look like this without changing the functionality:
package de.scrum_master.app;
public class Account {
private String owner;
private double balance;
public Account(String owner, double balance) {
this.owner = owner;
this.balance = balance;
}
public void withdraw(double amount) {
balance -= amount;
}
public void deposit(double amount) {
balance += amount;
}
public String getOwner() {
return owner;
}
public double getBalance() {
return balance;
}
#Override
public String toString() {
return "Account[owner=" + owner + ", balance=" + balance + "]";
}
public static void main(String[] argv) {
Account bossAccount = new Account("Boss", 2000);
Account nerdAccount = new Account("Nerd", 1000);
bossAccount.deposit(400);
nerdAccount.withdraw(200);
bossAccount.withdraw(300000); // Cannot withdraw more than account balance
nerdAccount.withdraw(-500000); // Cannot withdraw a negative amount
bossAccount.deposit(-123456); // Cannot deposit a negative amount
System.out.println(bossAccount);
System.out.println(nerdAccount);
}
}
package de.scrum_master.aspect;
import de.scrum_master.app.Account;
public aspect AccountAspect {
// Withdrawal
void around(Account account, double amount) :
execution(void Account.withdraw(double)) &&
target(account) &&
args(amount)
{
if (amount > account.getBalance()) {
System.out.println("Cannot withdraw more than account balance");
return;
}
if (amount < 0) {
System.out.println("Cannot withdraw a negative amount");
return;
}
proceed(account, amount);
}
// Deposit
void around(double amount) :
execution(void Account.deposit(double)) &&
args(amount)
{
if (amount < 0) {
System.out.println("Cannot deposit a negative amount");
return;
}
proceed(amount);
}
// This does not make any sense because
// 1. it happens after the application ends (after leaving main method)
// 2. Even though the account owner is the same as in the main method,
// it does not mean that by creating a new object with the same name
// the "Nerd" can manipulate the original account balance. You have to
// intercept the original Account object and manipulate it directly.
after() : execution(public static void *.main(String[])) {
System.out.println("--- after end of main program ---");
Account account = new Account("Nerd", 3000);
account.deposit(-100);
System.out.println(account);
}
// TODO: PIN secret password
// TODO: transaction record
}
The console log will be:
Cannot withdraw more than account balance
Cannot withdraw a negative amount
Cannot deposit a negative amount
Account[owner=Boss, balance=2400.0]
Account[owner=Nerd, balance=800.0]
--- after end of main program ---
Cannot deposit a negative amount
Account[owner=Nerd, balance=3000.0]
I will not do your homework assignment for you, but give you some hints:
PIN (secret password): The Account class needs a field pin which could be set in a constructor and should not have a public getter method in order to avoid that anyone can access the PIN. If the assignment requires you not to edit the base class but solve the problem via AOP, you can use inter-type definition (ITD) in order to add a private field and a public setter, maybe even an additional constructor to the class. Next you would add an advice which would ask the user to enter a PIN on the console if he tries to access any transactional methods such as deposit and withdraw of a certain account for the first time. After entering the PIN correctly he would be able to continue, otherwise there would be an error message and the transaction would be forbidden. The aspect itself could keep a cache (temporary storage) of all Account objects - probably you want to use a Set<Account> - which have been successfully authenticated during the running session, so as to avoid that the user has to enter the PIN for the same account again.
Transaction record per account: Again, you can use ITD in order to add something like a List<TransactionRecord> as a field to the Account, initialise it with an empty list and then add a transaction record for each deposit or withdrawal. You can also keep it simple for your proof of concept, not creating a TransactionRecord helper class but just using a List<Double> for the transactions, recording positive amounts for deposits and negative ones for withdrawals. A List<String> with elements like "deposit 123.45" or "withdrawal 67.89" is also a viable alternative. The important thing is that your teacher can see the correct aspect logic.

Make the variable not overwrite to null and check if the codes are correct

I'm new to Java and I have created a class which is based on the question from this exercise.
I've tried my best to follow it and I think the reason why my variables are 0 or null is that I didn't write anything in the constructor. The question didn't say anything about what to write in the constructor.
I'm printing everything out because I want to see the result, but all I get from getCardNumber is null, getBalance is 0, coffee is 0. redeemFreeCoffee and isFreeCoffeeAvailable does work, simply because there are no variables that override them.
Here's the full question:
a. Each loyalty card stores the card number, current balance (the number of points) and the number of coffees on the card. Implement a
constructor with the card number (of type String) as its argument and
method getCardNumber() and getBalance().
b. Implement a method collectRewards(double amount, int coffees) that takes the amount spent (in pounds) and the number of coffees
bought and increases the balance (by one point for every pound spent)
as well as the number of coffees on the card.
c. Implement a method isFreeCoffeeAvailable() that checks whether a free coffee is available, that is, whether the number of coffees on
the card is greater than or equal to 9.
d. Implement a method redeemFreeCoffee() that first checks whether a free coffee is available. If this is the case then it reduces the
number of coffees by 9 and returns true, otherwise false.
I've tried changing the variables from private to public but I still get the same result.
I've even tried putting my main in a different class but the result is still the same.
public String cardNumber;
public int balance;
public int coffee;
public double amount;
public String getCardNumber () {
return cardNumber;
}
public int getBalance () {
return balance;
}
public double collectRewards(double amount, int coffees) {
if (amount > 0) {
coffee++;
balance++;
}
return amount;
}
public int isFreeCoffeeAvailable(){
if (coffee >= 9) {
return coffee;
}
return coffee;
}
public boolean redeemFreeCoffee() {
if (coffee > 9) {
coffee-=9;
return true;
}
else {
return false;
}
}
public LoyaltyCard (String cardNumber){
}
public static void main (String[] args) {
String cardNumber = "0987654321";
LoyaltyCard LoyaltyCardOne = new LoyaltyCard(cardNumber);
System.out.printf("%s%n%s%n%s%n%s%n%s",LoyaltyCardOne.getCardNumber(),LoyaltyCardOne.getBalance(),LoyaltyCardOne.collectRewards(6.0,5),LoyaltyCardOne.redeemFreeCoffee(),LoyaltyCardOne.isFreeCoffeeAvailable());
}
I'd like to see the result for getCardNumber(), getBalance() and the amount of coffee.
all I get from getCardNumber is null
You never initialized it
public LoyaltyCard (String cardNumber){
this.cardNumber = cardNumber;
}
because there are no variables that override them.
I think you might be confused about what "override" means, but that isn't the problem.
getBalance is 0, coffee is 0
You're calling those before you ever "collect rewards"
You will need to collect before printing the invidiual values, and read the logic again - increase by one point for every pound spent. So, focus on changing this block to fix that.
if (amount > 0) {
coffee++;
balance++;
}
Note that the instructions don't say the collectRewards returns anything. Also coffee should be increased by the input parameter, maybe than just 1.
Otherwise, you would need to call collectRewards at least 9 times before the redeem and isAvailable methods would work.
And once those are, you could do this, rather than rewrite coffee > 9
if (this.isFreeCoffeeAvailable()) {
} else {
}
Note: isFreeCoffeeAvailable should probably return coffee > 9; rather than return the amount
In Java all non-local variables are initialized to 0, or null. So far in the code you don't set variables to your desired values. You can either create a constructor which takes values, e,g:
LoyaltyCard(int balance, int coffee, double amount) {
this.balance = balance;
this.coffee = coffee;
// ... and other fields
or create setters for each field:
public setBalance(int balance) {
this.balance = balance;
}

Java - How can I make a variable, that is assigned a value in on object, accessible to all objects?

I am trying to assign the variable gross a value in the default constructor and then have the other methods be able to access it (the calc... methods).
public class CO2FromWaste
{
CO2FromWaste(int numPeople, boolean paper, boolean plastic, boolean glass, boolean cans)
{
public double ogGrosss = numPeople*1018;
public double grosss = ogGrosss;
if(paper = true)
gross -= 184*numPeople;
if(plastic = true)
gross -= 25.6*numPeople;
if(glass = true)
gross -= 46.6*numPeople;
if(cans = true)
gross -= 165.8*numPeople;
}
private double gross = ogGrosss;
private double ogGross = Grosss;
public void calcGrossWasteEmission()
{
System.out.printf("%20.2f", gross);
}
public void calcWasteReduction()
{
System.out.printf("%20.2f", ogGross - gross);
}
public void calcNetWasteReduction()
{
System.out.printf("%20.2f", gross);
}
}
What you want is for those variables to be members of the class — as you have it now they are declared locally to the constructor.
public class CO2FromWaste
{
// Moved your variables to here, outside of any method.
// They should be declared at/near the top of the class,
// *before* the constructor (by convention)
// I also made them `private` because you don't want code
// that is *outside* of this class to access them.
private double ogGrosss;
private double grosss;
CO2FromWaste(int numPeople, boolean paper, boolean plastic, boolean glass, boolean cans)
{
// Now assign them their values.
// You can optionally use `this`
this.ogGrosss = numPeople*1018;
if(paper == true)
gross -= 184*numPeople;
if(plastic == true)
gross -= 25.6*numPeople;
if(glass == true)
gross -= 46.6*numPeople;
if(cans == true)
gross -= 165.8*numPeople;
}
// removed the declarations from here - these were now duplicates.
public void calcGrossWasteEmission()
{
System.out.printf("%20.2f", gross);
}
public void calcWasteReduction()
{
System.out.printf("%20.2f", ogGross - gross);
}
public void calcNetWasteReduction()
{
System.out.printf("%20.2f", gross);
}
}
Note the = operator in if(paper = true) is assignment — you want to compare these variables, which is done with the == operator.
(untested. I didn't even try to compile this, just modified your code)
Also note that when you subtract a floating-point value from the variable gross, it will round down the result.
I'm going to add some tips you can use to improve upon Stephen P's answer.
First of all, there is never any reason to compare against a boolean. Instead of paper == true you can simply write paper. All an if statement needs is a boolean value. If the value is already boolean, you do not need to perform a comparison. Therefore, your if statements can be made more readable by changing them to:
if(paper)
gross -= 184*numPeople;
if(plastic)
gross -= 25.6*numPeople;
if(glass)
gross -= 46.6*numPeople;
if(cans)
gross -= 165.8*numPeople;
I am assuming that based on what your code does that only one of the four boolean variables you use in your constructor should be true at a time, any the rest should be false. If this is the case, I would recommend using an enum to denote the options, otherwise you leave your class vulnerable to logic errors when used incorrectly. You would add the following file to your project:
WasteMaterial.java
public enum WasteMaterial {
PAPER, PLASTIC, GLASS, CANS
}
And modify the constructor for your class like so:
CO2FromWaste (int numPeople, WasteMaterial material)
{
// Now assign them their values.
// You can optionally use `this`
this.ogGrosss = numPeople*1018;
switch (material) {
case PAPER:
gross -= 184*numPeople;
break;
case PLASTIC:
gross -= 25.6*numPeople;
break;
case GLASS:
gross -= 46.6*numPeople;
break;
case CANS:
gross -= 165.8*numPeople;
break;
}
}
This prevents the class from being constructed incorrectly by setting multiple values to true (if, of course, your specification only allows one of those four values to be true at a time).

How to use a user defined exceptions in java inside another method

I want to create a set method to insert maximum temperature for a specific place and I want that temperature to be of type Double,the method will check if the entered number is >= to 100 or <= to 100
if yes then it will be inserted in the maximum temperature field..
else I have to throw a user defined exception that will tell me that the number I entered is out of the supposed limits!
I wrote the Exception and the method this way:
public class OutOfSensibleLimits extends Exception
{
private Double max;
public OutOfSensibleLimits(Double max)
{
this.max = max;
}
public Double getMax()
{
return max;
}
public String toString()
{
return "The maximum Tempreture you entered: '" + maxTemp +
"' is out of sensible limits.";
}
}
public void setMaxTemp(Double max){
if ( max >= -100 || max <= 100)
{
maxTemp = max;
}
else throw new OutOfSensibleLimits();
}
and it gives me an error, what am I doing wrong?
Problems:
This is not how exceptions work -- you need to call the appropriate super constructor with the appropriate String if you want it to show a String, and
You're not calling your own exception's constructor properly. You've written it to accept a Double, and you're not passing in a Double (you're passing in nothing).
the toString method is unnecessary and confusing since it will never be called and the String will never be seen.
You state, "and it gives me an error,...", but don't show us any error message. I'm guessing that the compiler is complaining that you're not calling your class's constructor correctly, but please don't leave us guessing -- show the complete unabridged error message.
Your setMaxTemp uses the wrong boolean operator: if ( max >= -100 || max <= 100). This is always true. You want to use && instead.
Suggestions:
Yes, pass in a double the constructor
And then use that double to create an appropriate error/exception message that is passed into the super's constructor.
Get rid of your exception class's fields and toString() method.
Most important, I urge you to first read the Exception tutorial before trying anything else.
Also simplify as you're making things overly complex. Your Exception class could easily be nothing more than a constructor and that's it.
Make sure that the method that might throw the exception declares that it throws this exception.
For example:
public class TestSensibleLimits {
private Double maxTemp;
public void setMaxTemp(double max) throws OutOfSensibleLimits {
if (max >= -100 && max <= 100) { // use && not ||
maxTemp = max;
} else
throw new OutOfSensibleLimits(max);
}
public Double getMaxTemp() {
return maxTemp;
}
public static void main(String[] args) {
TestSensibleLimits test = new TestSensibleLimits();
try {
test.setMaxTemp(200);
} catch (OutOfSensibleLimits e) {
e.printStackTrace();
}
}
}
#SuppressWarnings("serial")
public class OutOfSensibleLimits extends Exception {
private static final String FORMAT = "The maximum Temperature you "
+ "entered: %.2f is out of sensible limits.";
public OutOfSensibleLimits(Double max) {
super(String.format(FORMAT, max));
}
}

Help with method logic in Java, hw

I have a Loan class that in its printPayment method, it prints the amortization table of a loan for a hw assignment. We are also to implement a print first payment method, and a print last payment method. Since my calculation is done in the printPayment method, I didn't know how I could get the value in the first or last iteration of the loop and print that amount out.
One way I can think of is to write a new method that might return that value, but I wasn't sure if there was a better way. Here is my code:
public abstract class Loan
{
public void setClient(Person client)
{
this.client = client;
}
public Person getClient()
{
return client;
}
public void setLoanId()
{
loanId = nextId;
nextId++;
}
public int getLoanId()
{
return loanId;
}
public void setInterestRate(double interestRate)
{
this.interestRate = interestRate;
}
public double getInterestRate()
{
return interestRate;
}
public void setLoanLength(int loanLength)
{
this.loanLength = loanLength;
}
public int getLoanLength()
{
return loanLength;
}
public void setLoanAmount(double loanAmount)
{
this.loanAmount = loanAmount;
}
public double getLoanAmount()
{
return loanAmount;
}
public void printPayments()
{
double monthlyInterest;
double monthlyPrincipalPaid;
double newPrincipal;
int paymentNumber = 1;
double monthlyInterestRate = interestRate / 1200;
double monthlyPayment = loanAmount * (monthlyInterestRate) /
(1 - Math.pow((1 + monthlyInterestRate),( -1 * loanLength)));
System.out.println("Payment Number | Interest | Principal | Loan Balance");
// amortization table
while (loanAmount >= 0) {
monthlyInterest = loanAmount * monthlyInterestRate;
monthlyPrincipalPaid = monthlyPayment - monthlyInterest;
newPrincipal = loanAmount - monthlyPrincipalPaid;
loanAmount = newPrincipal;
System.out.printf("%d, %.2f, %.2f, %.2f", paymentNumber++, monthlyInterest, monthlyPrincipalPaid, loanAmount);
}
}
/*
//method to print first payment
public double getFirstPayment()
{
}
method to print last payment
public double getLastPayment()
{
}*/
private Person client;
private int loanId;
private double interestRate;
private int loanLength;
private double loanAmount;
private static int nextId = 1;
}
Thanks!
You've already identified that the printPayments(), printFirstPayment() and printLastPayment() methods have common logic. You generally want to minimize duplication of such code and the two common ways to do this are:
Implement all but one of the methods in terms of one of them; or
Implement all the methods in terms of a private method.
So, for example:
public void printPayments() {
for (Payment : getPayments()) {
printPayment(payment);
}
}
public void printFirstPayment() {
printPayment(getPayments().get(0));
}
public void printLastPayment() {
List<Payment> payments = getPayments();
printPayment(payments.get(payments.size()-1));
}
private void printPayment(Payment payment) {
...
}
private List<Payment> getPayments() {
...
}
Now this is homework so you may not have come across the syntax List<Payment> yet. If not, it's generics. There are other ways to do this: using a non-generic Collection or using arrays for example.
The points I wanted to illustrate here is that:
The logic for creating the payments and displaying them has been separated;
A single method getPayments() does the calculations and returns a List of Payment objects. Payment is a new object in this mock up;
All three methods are implemented in terms of getPayments() and printPayment().
So I hope this leads you in the right direction. The concept here I guess is functional composition, composing your functions in terms of other functions and making your internal functions granular enough to be grouped together usefully.
Your printPayments function is awfully big. It is generally better to make each function "do one thing and one thing well", and to make functions relatively short. I would recommend that you separate your computation logic from your printing logic; provide functions for computing these various payments, and have your print function merely print the result of invoking those computation functions.
If you are worried about redundancy (that is some of the later computations depend on earlier computations which you might have previously performed), then you can use dynamic programming, which basically means that you accumulate previous results in an array or matrix so that they can be reused in subsequent computations. You could compute the entire amortization table as a 2-dimensional array, in which case you could lookup the earlier payments that you computed simply by looking them up in that array.
Maybe you should have a method that returns an array/set/list/resultset/datacontainer (add more buzzwords to confuse you - its your homework after all ;)) which you can use in the other methods.
if when you describe what a method does, you use the word 'and', chances are the method is doing too much. each method should do one thing, so printing is one thing, and calculating is another .. so two methods.

Categories

Resources