>>Dr. Deborah Trytten: Now that we know about using predefined objects in Java, let's create
a program for Pay Best Shoes their BOGOF Sale. Here's the problem statement: Pay Best Shoes
is having a Buy One, Get One Free Sale. The free item has to be equal or lesser value
than the purchased item. So we need to write a program that allows the user to enter their
purchases and calculate how much they'll pay. So the first thing we need to do is to create
some test data. Suppose our items cost $3, $7, $9, $5, and $1. Well you've got to think
this through carefully, because when you pay for the $9 item you're going to get the $7
item for free. When you pay for the $5 item you're going to get to get the $3 item for
free and then you're going to have to pay for the $1 item separately. So that means
that you're going to pay for the $9, the $5, and the $1 item--$15. Suppose our items cost
$12, $8, $4, $10, $6, and $2. Well we're going to pay for the $12 item, get the $10 item
free, pay for the $8 item get the $6 item free, and pay for the $4 item--so that should
be $24. Boundary cases we might want to consider well certainly if we buy zero items we want
to pay zero dollars. If we buy only one item maybe a $10 item we want to pay $10. And if
we have a $10 and a $8 item we're going to pay $10. One thing you may have noticed when
I was talking through that creating the test data is it's actually giving us some ideas
about how we might want to write the program. So I was doing was sort of sorting the data,
and thinking about "I'd pay for the first one and then not for the next one most expensive
one" so that strategy is the strategy we're going to use in the program. This is why it's
so important to work through test data first because it can actually help you figure out
how to write the program better. Let's choose our data types. We're going to need to store
and manipulate the price of many items. We really have only one possible data type that
could work for that--it would be an ArrayList of doubles. So let's go create our program
and get our ArrayList of doubles in place. [pauses] So we're starting Eclipse. I'll create
a new project. Notice that I always get rid of the code from the old project before I
create a new one. That's very important because particularly if your projects have the same
names, you can get confused and be entering the wrong project's code. That's a really
serious problem. So here's our project. There's our source file. Here's our class. Which we
will of course beautify as we always do. We know we're going to need an ArrayList of double
in our code and I'll call it "sales." Eclipse is complaining because of course I have not
imported the file for ArrayList yet. So we're going to import Java dot util dot ArrayList.
That way, Eclipse can find the ArrayList instructions and is able to create the ArrayList object.
Let's think about designing our methods first. This is different than what we did in the
last chapter because this time we actually can store our data. So our input in calculations
don't have to be done together. They can be done separately, which is actually a nice
way to do it. So if we're going to get the user purchases, the input is probably going
to be a scanner although we may want to think about that a little bit. The output the return
type will be an ArrayList of doubles. This means that our ArrayList of double will be
created inside "get user preferences" and then returned to the main program. This will
be a static method as all of our methods have been so far. We also can create a "find sale
price method" so this can be separate now. Because we have the ArrayList to store our
data. The input will be our ArrayList and the output will be double, that will be the
sale price it's getting past back. This is also a static method. So let's go and write
those methods. I'll put in stubs first. Now we're going to have to think about whether
we want a scanner here or not. So we'll deal with that problem in a minute. [typing] Okay,
so let's think about the scanner issue. Is all of our interaction with the user going
to occur in this one method? If so, the scanner can be a local variable in that method instead
of being a parameter to it. Or you can always put your scanner in the main program. It really
doesn't matter which way you do it, both ways work well. Because people get a little crazy
about parameter passing I'm going to put the scanner in the main program and then pass
it in as a parameter, just to get a little more practice. But either way would work just
fine. Of course Eclipse is complaining about our scanner once again because we haven't
done our import statement. [typing] So since we created it in the main program, we want
to pass it in now to get user data. Now Eclipse is putting a lot of little red X's around
and the reason it's doing that is because we haven't returned the types that we expect.
So if you look at these little red X's what they say. "This method must return a result
of type ArrayList of double." So one way to keep Eclipse quiet is to create that ArrayList
and return a fake one for a while. That will keep Eclipse off our backs, so I like to do
that. I'm constructing it with a constructor [pause] and then returning it. And now Eclipse
is happy once again. Now in this method, we're just returning a double. Since double is a
primitive datatype instead of an object we can just return 0.0 for now. So that will
keep Eclipse happy. The next thing we need to do is to find the sale price. Now this
one is a little bit tricky. First we need to sort the data from the smallest to the
largest. Now you might say, "Wait a minute! When you were going through the data you looked
from the largest to smallest." And that's true, that would be a really nice order to
have. Unfortunately though, the methods that we have to do sorting are always going to
sort in ascending order. That is from the smallest to the largest. So we're kind of
stuck having to deal with the decisions that are made in Java. We're going to have to buy
the most expensive item, so that one's going to be at the end of the list. The second one
will be free so that's one position in. And then we'll do every other item. So if you
think about it, we're going starting at the end and skipping alternate items. So that's
a nice little while loop we're going to have. As far as our implementation choices--well
sorting is always in ascending order. There is a method in the collections class that
reverses data, and we could use that but there's really no reason to use that when we can do
start at the far end of the array instead the near end. This is a possibility people
sometimes forget to do when they're writing code. So let's go and write the find sale
price method. So we take our ArrayList and we sort it, so that's [typing] collection
dot sort purchases. Now we want a loop, so we're going to start at the far end so...let's
call an index and that's going to be [typing] purchases dot size minus 1. Now that minus
1 is easy to forget. Remember that size is unit indexed. That is, that it counts the
number of elements that are in the ArrayList. But unfortunately the elements themselves
are zero indexed and so we always have to subtract one in order to get it started in
the right direction. So while index is greater than or equal to zero. Well we need to keep
track of how much our cost is going to be. We'll start it at zero of course, while it's
greater than or equal to zero we will add in the cost at that index so cost equals cost
plus purchases dot get of index. And the next thing we need to do is to change the index.
You may be tempted to subtract one from index 'cause we've written so many loops where that's
the correct answer but in this case, you need to skip items. So you need to subtract two,
not one. Now instead of returning zero we'll return cost. Now we could run the program
at this point but it's not going to be very interesting 'cause we haven't written our
input method yet. So probably that's the one we should do next before we try to run. So
here's our get user data method. We might want to think about how we're going to have
to have the user enter data. This can't be a counter controlled loop, because we don't
know how many purchases the user is going to make. It's really not nice to ask users
for things like, "How many purchases are you going to make before you start?" and so instead
it's better to use a sentinel. That is to have them enter some illegal value at the
end so you know that they're through. In this case because they're entering the cost of
items -1 makes a good sentinel. Because it's a sentinel controlled loop we're going to
have to prime the reads. So here we go! [typing] System out print line enter the cost of your
next purchase or -1 to stop. Then we'll have a double called "cost" and that will be [typing]
keyboard dot next double. Because this is a priming read we want to include a comment
so we'll have "While cost is greater than zero." Now this is an important point. You
may have been tempted to write, "While cost is not equal to -1", but the problem is that
cost is a double value. And we do not use equality comparisons with double values because
doubles are not stored exactly in the computer using equality comparisons with doubles will
sometimes work and sometimes not. We don't want to take risks like that with our program,
so instead we'll just look to see if the value is less than zero by using less than we get
around that problem. So now we're going to add the element to the array and we're going to get our next input. Now
we've already written our priming read input so let's copy and paste that into the loop.
Of course we have to remove the second declaration 'cause we're only allowed to declare a cost
once. And let's check what we have at the end of the loop we're returning the result
and so that's correct. So notice this was kind of a a lean, mean loop. Not a very long
one. Let's go to our main program and make sure we have the pieces together correctly.
Well we really don't have our pieces together correctly, because we haven't called any of
our methods. So we'll say "Sales equals get user data of input." So that method is returning
our ArrayList. Now we're ready to find the cost so we'll have, "Double cost equals" let's
go and look for what the name of the method was "find cost", clever name. So we're going
to "Find cost of sales and system out print line the cost of your purchases is plus cost."
Well Eclipse is happy so let's see if our program is running. So let's start with some
easy data. Let's just make one purchase of 10 bucks. That worked, that's good! Now let's
make two purchases of $10. This should be 10 bucks right? And that worked too. How about
$10 and $8? Purchase is $10. Remember the $8 item being free. Now $12, $10, $8, $6,
$4, $2. So it'll be 12 plus 8, which is 20 plus 4 so our answer here should be 24. And
it is. Things are looking good. One thing I will say about our testing strategy so far,
because I've had all the data in order, we're really not testing whether the sorting is
working correctly or not. So let's try the data in the opposite order to make sure that
our sorting algorithm is doing what it should. So $2, $4, $6, $8, $10, $12 and it's the same
$24 cost. So this time we didn't make any mistakes while we were creating our program,
more or less. One of the reasons we didn't is we had a good strategy to start with, and
that strategy came from doing the test development first. So that's an idea you definitely want
to consider when you're writing programs on your own. So we've checked our test data...and
our program is finished.