At the end of unit 2, we spent a little time in class on a program to do some String
operations. In this exercise, you'll end up in the same place, but instead of just writing a main program, you're going to design and implement a class that does the real work.
StringPile
classTo remind you, here's the activity from unit 2:
Imagine a program that reads an arbitrary number of
String
s in from the input (where each line of input is treated as a
String
), then outputs: the shortest
String
(if multiple
String
s have the shortest length, output the one that occurs first in the input), the longest
String
(again, if multiple
String
s have the longest length, output the first-occurring one), and print the
String
s in alphabetical order.
So the StringPile
class is going to do most of that work. In particular, here's the class "skeleton":
public class StringPile { public void load(Scanner sc) public String getShortest() public String getLongest() public void printInOrder(PrintStream ps) }
A couple notes:
load()
method takes a Scanner
reference. In particular, you can pass a Scanner
that "wraps" System.in
(but you must set that up before you call load()
, of course). Your method implementation should read from this Scanner
;printInOrder()
will print to whatever PrintStream
object its parameter refers to. In particular, you can pass in System.out
.Scanner
object by using the hasNextLine()
method.
StringPile
class. Notice that there is nothing here about implementation details. Do you need instance variables? Do you need to write any "helper" methods? What exactly should the load()
method do? Another thing to think about: must every "get" method correspond to an instance variable? StringPile
class to implement the exercise.Note you can do these in any order, or work on them simultaneously, as you wish: once you have the method signatures established, the implementation, application, and testing of them should be totally separate.
ArrayList
s are supposed to work on arbitrarily large datasets, right? So try your code on this file of nearly 500,000 words. When we get to that amount of data, the efficiency of your code really starts to make a difference. How long does each of your methods take to do its work?
Fortunately, the Java API includes some methods to help us find out. this page has a more detailed explanation, but here's the code we need to time the execution of a chunk of code:
long startTime = System.nanoTime(); // ... this is the code we want to time ... long endTime = System.nanoTime(); System.out.println("That took " + (endTime - startTime)/1000000.0 + " milliseconds);(Note that I divided by a million in floating point to get fractional milliseconds.)
Use this technique to time the calls to the four methods in your StringPile
implementation. These should be, y'know, pretty fast, though the exact timings will depend on your hardware and other factors.
As you're working on this (or when you're done), think about this: what about making a "generic" Pile
class? That is, could we, in theory, write a version of this that would work for any type of object? (We haven't talked about the actual programming techniques for doing this, but we've seen how the ArrayList
class is designed to serve as an "array" of any type of object.) If your answer is "yes," what kinds of changes would you have to make to your code? If your answer is "no," what's your problem? Do you mean this can only work for String
s, or only some kinds of objects, or what?