Title: Session 5 More on Java Strings and Files
1Session 5More on Java Strings and Files
Intro. to Inheritance
2Java File I/O
- Allows us to write and read permanent
information to and from disk - How would file I/O help improve the capabilities
of the MemoPadApp?
3Java File I/O Example Echo.java
- echoes all the words in one file to an output
file, one per line. - java Echo hamlet.txt hamlet.out
- less hamlet.out
- 1604
- the
- tragedy
- of
- hamlet
- prince
- of
- denmark
- by
- william
- shakespeare ...
4Study Echo.javas File I/O
- have constructors that allow convenient and
flexible processing - send input message readLine()
- send output messages print() and println()
- use a stereotypical loop to process a file of
lines - use of the stereotypical StringTokenizer loop as
inner loop
5import java.io. import java.util.StringTokenizer
public class Echo public static void
main( String args ) throws IOException
String delimiters " .?!()?/\\,-\'\"\t\n
\r" BufferedReader inputFile new
BufferedReader(new FileReader(args0) )
PrintWriter outputFile new PrintWriter( new
FileWriter( args1 ) ) String buffer
null while( true ) buffer
inputFile.readLine() if ( buffer
null ) break buffer
buffer.toLowerCase() StringTokenizer
tokens new StringTokenizer( buffer, delimiters
) while( tokens.hasMoreElements() )
String word
tokens.nextToken()
outputFile.println( word ) // end
while // end while(true)... //
end main // end class Echo
6wc - UNIX/Linux utility
- wc prints the number of lines, words, and
characters in a file to standard output. - For example
- wc hamlet.txt
- 4792 31957 196505 hamlet.txt
7Exercise
- Using Echo.java as your starting point, create a
WordCount.java program that does the same thing
as wc, i.e., prints the number of lines, words,
and characters in a file to standard output. For
example - java WordCount hamlet.txt
- lines 4792 words 32889 chars 130156
8import java.io. import java.util.StringTokenizer
public class WordCount public static
void main( String args ) throws IOException
String delimiters " .?!()?/\\,-\'\
"\t\n\r" BufferedReader inputFile new
BufferedReader( new FileReader( args0 ) )
String buffer null int chars
0 int words 0 int
lines 0 while( true )
buffer inputFile.readLine() if (
buffer null ) break lines
buffer buffer.toLowerCase()
StringTokenizer tokens new StringTokenizer(
buffer, delimiters ) while(
tokens.hasMoreElements() )
String word tokens.nextToken()
words chars word.length()
// end while // end while(
true )... System.out.println( "" lines
" " words " " chars ) // end
main // end class WordCount
9Why the difference in the number of words and
number of characters?
- wc hamlet.txt
- 4792 31957 196505 hamlet.txt
- java WordCount hamlet.txt
- lines4792 words32889 chars130156
10Java File I/O Example Echo.java
- echoes all the words in one file to an output
file, one per line. - java Echo hamlet.txt hamlet.out
- less hamlet.out
- 1604
- the
- tragedy
- of
- hamlet
- prince
- of
- denmark
- by
- william
- shakespeare ...
11import java.io. import java.util.StringTokenizer
public class Echo public static void
main( String args ) throws IOException
String delimiters " .?!()?/\\,-\'\"\t\n
\r" BufferedReader inputFile new
BufferedReader(new FileReader(args0) )
PrintWriter outputFile new PrintWriter( new
FileWriter( args1 ) ) String buffer
null while( true ) buffer
inputFile.readLine() if ( buffer
null ) break buffer
buffer.toLowerCase() StringTokenizer
tokens new StringTokenizer( buffer, delimiters
) while( tokens.hasMoreElements() )
String word
tokens.nextToken()
outputFile.println( word ) // end
while // end while(true)... //
end main // end class Echo
12Working with Standard Input and Output as Files
- Sometimes, we'd like to give the user an option
of providing a file name or using standard I/O. - We can call sort with its own file argument, or
we can pipe the standard output of one program
(cat hamlet.out) as the standard input to sort. - How can we make our Java programs do the same
thing?
13Streams vs. Readers and Writers
- a stream is a device for transmitting or
receiving a sequence of byte (8-bit) values - emphasis on reading/writing -- not on data itself
- network and file systems are based on byte unit
- Readers and Writers use 16-bit Unicode
- useful for I/O of textual values as opposed to
binary data such as images, colors, etc. - for example, BufferedRead has readLine method
14Working with Standard Input and Output as Files
- Standard input is an instance of the InputStream
class and does not respond to readLine(), which
is how we would like to grab lines of text as
Strings. - Standard output does respond to println()
messages, but it is a PrintStream, which cannot
be stored in a PrintWriter variable.
15What can we do?
- We could write duplicate code for the four
different cases. (file-file, file-stdout,
stdin-file, stdin-stdout) - Every case would look the same except for one or
two lines. - That doesn't seem to be the correct solution.
- Maybe we can find a way to have them talk to
objects that talk to standard input and output...
16A Solution
- Let's take advantage of an object-oriented idea
We ought to be able to substitute an object with
a common interface, even if somewhat different
behavior, in place of one another, and let the
new object fulfill the responsibilities of the
replaced one. - While BufferedReaders and PrintWriters don't know
how to talk to standard input and output,
respectively, we can use a translator to serve as
a go-between. - Java give us the classes we need
InputStreamReader and OutputStreamWriter.
17import java.io. import java.util.StringTokenizer
public class EchoStandard public static
void main( String args ) throws IOException
String delimiters " .?!()?/\\,-\'\"\
t\n\r" BufferedReader inputFile new
BufferedReader(
new InputStreamReader( System.in ) )
PrintWriter outputFile new PrintWriter(
new OutputStreamWriter(
System.out ) ) String buffer null
while( true ) buffer
inputFile.readLine() if ( buffer
null ) break buffer
buffer.toLowerCase() StringTokenizer
tokens new StringTokenizer(buffer,delimiters)
while( tokens.hasMoreElements() )
String word tokens.nextToken()
outputFile.println( word ) // end
while // end while( true )... // end
main // end class EchoStandard
18Echo
- BufferedReader inputFile new BufferedReader(
- new
FileReader( args0) ) - PrintWriter outputFile new PrintWriter(
- new
FileWriter( args1) ) - vs. EchoStandard
- BufferedReader inputFile new BufferedReader(
- new InputStreamReader(
System.in ) ) - PrintWriter outputFile new PrintWriter(
- new OutputStreamWriter(
System.out ) )
19Exercise
- Turn Echo.java into EchoV2.java, which behaves
just like Echo, except that it takes two optional
command-line arguments the names of the input
file and output file, respectively. - If the user omits the second argument, the
program writes to standard output. - If the user omits both arguments, the program
reads from standard output and writes to standard
output. For example - java EchoV2 hamlet.txt hamlet.out
- less hamlet.out
- 1604
- the
- tragedy
- of
- ...
20Exercise - More Examples
- java EchoV2 EchoV2.java
- ...
- java EchoV2 hamlet.txt less (interesting
that the pipe is not args1) - 1604
- the
- tragedy
- of
- ...
- java EchoV2
- ...
- cat hamlet.txt java EchoV2 less
- 1604
- the
- tragedy
- of
- ...
21Introduction to Inheritance
22Accumulator Example
- a simple calculator app
- classes needed
- AdderApp - contains main
- AddingFrame - GUI
- CloseableFrame - allows X button
- Accumulator - internal representation and
implementation of the accumulator
23AdderApp
- contains the main() method that serves as the
"Big Bang" for this part of the world - public class AdderApp
- public static void main( String args )
- AddingFrame f new AddingFrame()
- f.show()
- // end main
- // end class AdderApp
24AddingFrame
- Provides the graphical interaction between the
user and the actual calculator methods - AddingFrame extends CloseableFrame extends
JFrame. - AddingFrame depends on the Accumulator class do
the mathematics for the program.
25Accumulator Class
- Recall from CS I that a class contains three
things. - Data / Instance Variables
- Method(s)
- Constructor(s)
26Accumulator Class
- What Data / Instance Variables are needed?
27Accumulator Class
- Data / Instance Variables needed
- currentSum the current value accumulated by
the accumulator. - currentNumber the number that has been entered
by the user. The value that will be added or
subtracted. - displayValue the value visible on the graphical
calculator. (Needed because sometimes we display
the number the user is entering (currentNumber)
and sometimes it is the current accumulated value
(currentSum), so we will maintain a new value
which holds whatever is on display.)
28Accumulator Class
- What methods would the accumulator class need
(hint, there are five of them)?
29Accumulator Class
- Needed methods
- plus adds the last number entered to the
currentSum. - minus subtracts the last number entered from
the currentSum. - clear sets everything back to zero
- addDigit adjusts the currentNumber upon input
of an additional integer - getDisplay returns the current displayValue.
(This is necessary because our graphical class
will want to know what value to display any time
some action occurs.)
30Accumulator Class
- What would the constructor do?
31AccumulatorV1
- public class AccumulatorV1
-
- private int currentSum
- private int currentNumber
- private int displayNumber
-
- public Accumulator()
- currentSum0
- currentNumber0
- displayNumber0
-
-
- public void clear()
- currentSum0
- currentNumber0
- displayNumber0
-
-
- public void addDigit( int digit )
- public void plus()
- currentSumcurrentNumber
- currentNumber0
- displayNumbercurrentSum
-
-
- public void minus()
- currentSum-currentNumber
- currentNumber0
- displayNumbercurrentSum
-
-
- public int getDisplay()
- return displayNumber
-
- // end class AccumulatorV1
32Refactoring Accumulator
- What is refactoring?
- Changing a program in a way that does not change
its functionality. - Why do it?
- To improve the structure of your code based on
what you have learned since writing it. - What common code can we refactor?
33Refactoring Accumulator
- Using the clear() method in the constructor
- Refactoring the plus() and minus() methods to
call a private helper method.
34Refactoring Accumulator
public void plus() currentSumcurrentNu
mber prepareForNextNumber()
public void minus() currentSum-currentNumber
prepareForNextNumber()
private void prepareForNextNumber()
currentNumber0 displayNumbercurrentSum
public int getDisplay() return
displayNumber // end class AccumulatorV2
public class AccumulatorV2 private int
currentSum private int currentNumber
private int displayNumber public
Accumulator() clear()
public void clear() currentSum0
currentNumber0 displayNumber0
public void addDigit( int digit )
currentNumbercurrentNumber10digit
displayNumbercurrentNumber
35Reinforcing the refactoring
- There is an old programmers adage that states
- "There are only two numbers 1 and
many" - Once you start to repeat code, it is time to
start to think about refactoring and adding in a
helper method.
36Alternative structure of the program
- The complete calculator consists of four
classes. - AdderApp
- AddingFrame
- CloseableFrame
- Accumulator
37Alternative structure of the program
- We can think of the relationships between these
four classes as being narrow and deep - AdderApp creates an instance of AddingFrame which
creates an instance of Accumulator. - This is a good example of data hiding since
AdderApp doesnt know/care that there is an
instance of the Accumulator class.
public class AdderApp public static void
main( String args ) AddingFrame f new
AddingFrame() f.show() // end main
// end class AdderApp
public class AddingFrame extends CloseableFrame
private Accumulator myAccumulator ...
public AddingFrame( ) // create
frame and accumulator myAccumulator new
Accumulator() ...
38Alternative structure of the program
- But another way to structure this program would
be to create a relationship which is wide and
shallow - AdderApp creates an an instance of Accumulator
which it passes to an instance of AddingFrame. - public class AdderApp
- public static void main( String args
) - Accumulator a new Accumulator()
- AddingFrame f new AddingFrame(a)
- f.show()
- // end main
- // end class AdderApp
- This is a good example of composition.
- We emphasize that AddingFrame is composed of an
Accumulator - This is a good example of writing code that is
modular. - Now that we know the composition relation, we can
compose solutions using variations of Accumulator.
39CountedAccumulator Extension
- Suppose we need a new kind of object, an
Accumulator that counts how many operations it
executes. Lets call this class
CountedAccumulator. - It responds to all the same messages as a regular
Accumulator and also responds to an
operationsExecuted() message, by returning its
count. - What changes would you need to make to
Accumulator?
40Adding Behavior to a Class
- Any time that we need to add behavior to a class
we have at least three options - Add code to the class itself, keeping the
original class. - Copy all the old code into a new class and add
code to this new class. - Create a subclass that extends the original
class' behavior.
41Pros and Cons
- Add code to the class itself, keeping the
original class. - Pros Quick. Convenient. Simple.
- Cons May change the behavior of the class.
Thus, it isnt always an option.
42Pros and Cons
- Add code to the class itself, keeping the
original class. - Pros Quick. Convenient. Simple.
- Cons May change the behavior of the class.
Thus, it isnt always an option.
43Pros and Cons
- Add code to the class itself, keeping the
original class. - Pros Quick. Convenient. Simple.
- Cons May change the behavior of the class.
Thus, it isnt always an option.
44Pros and Cons
- Copy all the old code into a new class and add
code to this new class. - Pros Quick. Convenient. Simple.
- Cons Duplicated code. Error trap! Error trap!
45Pros and Cons
- Copy all the old code into a new class and add
code to this new class. - Pros Quick. Convenient. Simple.
- Cons Duplicated code. Error trap! Error trap!
46Pros and Cons
- Copy all the old code into a new class and add
code to this new class. - Pros Quick. Convenient. Simple.
- Cons Duplicated code. Error trap! Error trap!
47Pros and Cons
- Create a subclass that extends the original
class' behavior. - Pros Doesnt break existing code. Virtually
eliminates duplicate code. Provides the most
flexibility. - Cons Slightly more time consuming.
48Pros and Cons
- Create a subclass that extends the original
class' behavior. - Pros Doesnt break existing code. Virtually
eliminates duplicate code. Provides the most
flexibility. - Cons Slightly more time consuming.
49Pros and Cons
- Create a subclass that extends the original
class' behavior. - Pros Doesnt break existing code. Virtually
eliminates duplicate code. Provides the most
flexibility. - Cons Slightly more time consuming.
50Developing an Extended Class
- There are typically four steps in developing an
extended class. - declare the class
- declare the new data
- create the constructors
- adjust the methods
51Developing an Extended Class
- declare the class
- public class CountedAccumulator extends
Accumulator
52Developing an Extended Class
- declare the new data
- private int numberOfOperations
53Developing an Extended Class
- create the constructor
- public CountedAccumulator ()
- super()
- numberOfOperations0
54Developing an Extended Class
- Leave inherited methods alone
- clear() and prepareForNextNumber() are both
inherited from Accumulator and there is no need
to change them.
55Developing an Extended Class
- Modify/Override inherited methods
- plus() and minus() are inherited, but they don't
do what we want them to. - We can make them do more without completely
replacing the code however. - public void plus()
- super.plus()
- numberOfOperations
56Developing an Extended Class
- Add completely new methods
- We need an accessor method for numberOfOperations
- public void operationsExecuted()
- return numberOfOperations
57CountedAccumulator Solution
- public class CountedAccumulator extends
Accumulator - private int numberOfOperations
-
- public CountedAccumulator()
- super() // calls the superclass
constructor - numberOfOperations0
-
- public void plus()
- super.plus()
- numberOfOperations
-
-
- public void minus()
- super.minus()
- numberOfOperations
-
-
- public int getOperations()
58CountedAccumulator Solution
- Now, before we can really work with this we need
to modify other files in our application. - We need to set up the AddingFrame so that it
works with a CountedAccumulator rather than a
regular Accumulator. We do this in the AdderApp
class for simplicity. - Accumulator a new CountedAccumulator()
- AddingFrame f new AddingFrame(a)
59A solution
- Why do we do this in the AdderApp rather than
leave it alone and modify the AddingFrame? - Because in the end this makes our AddingFrame
slightly more versatile. - Think about it...AddingFrame works with an
Accumulator (or CountedAccumulator). If one is
provided, it uses it. If one is not provided, it
creates it. - THAT, is more versatile than telling an
AddingFrame to now always create a
CountedAccumulator.
60A solution
- Now we can run this...
- Notice that we have basically returned to having
a Accumulator. Why? - Notice that even though I have private data and
methods in Accumulator, I didn't have to change
this here. Why?
61A solution that USES the counting functionality
- If we want to actually use the functionality of
this new class, then something needs to call the
new method in CountedAccumulator. - Without discussing the details of exception
handling, we could do this by writing - try Thread.sleep(10000)
catch(Exception e) System.out.println("Perfo
rmed a.getOperations()"operations")
62Another Exercise
- Create a class named EvenOddAccumulator that
subclasses Accumulator to implement this
behavior. - EvenOddAccumulators respond to all the same
messages as regular Accumulators. But, in
response to plus() and minus() messages, an
EvenOddAccumulator both computes the new sum and
writes a congratulatory message if the sum is
even.
63Toward a Solution
- Here is the critical new piece of the
EvenOddAccumulator class - if ( currentSum 2 0 )
- System.out.println( "Hurray! You made an even
number." ) -
- The big question is, what else is a part of the
class?
64Toward a Solution
- Lets look at one version of this
65A Problem Accessing Inherited Data
- javac EvenOddAccumulator.java
- EvenOddAccumulator.java17 currentSum
- has private access in Accumulator
- if ( currentSum 2 0 )
-
- EvenOddAccumulator.java24 currentSum
- has private access in Accumulator
- if ( currentSum 2 0 )
-
- 2 errors
- Oops!
- currentSum is declared as a private instance
variable in class Accumulator. - private means private no code outside the
Accumulator class can access that variable.
66A Possible Solution for Accessing Inherited Data
- Change currentSum to be public or protected.
- public class Accumulator
- protected int currentSum
- ...
-
67A Better Solutionfor Accessing Inherited Data
- (2) Add a protected accessor method to the
- Accumulator class. Use that method to access the
- currentSum instance variable in the subclass.
- public class Accumulator
- ...
- protected int currentSum()
- return currentSum
-
-
- Then use currentSum() in EvenOddAccumulator.
68Programming with Inheritance
- Inheritance is an object-oriented programming
construct that enables us to add behavior to an
existing system without modifying the existing
classes.
69Programming with Inheritance
- Our new EvenOddAccumulator class adds behavior to
a program that uses Accumulators without
modifying - the behavior of the existing Accumulator class or
- the existing AddingFrame class!
- That means...
- No chance of introducing an unnecessary,
unexpected errors into the working Accumulator
class. - No need to modify programs that use instances of
Accumulator but which dont need instances of
EvenOddAccumulator. - The ability to use EvenOddAccumulators in
programs that expect to use Accumulators.
70Programming with Inheritance
- We could have achieved some of these results
without using inheritance by creating a new class
named EvenOddAccumulator that simply duplicated
the behavior of existing Accumulator class. - Using inheritance means that...
- No need to reimplement existing methods.
- No need to duplicate code.
- One of the most important features of
object-oriented programming is that it encourages
us to create new classes that reuse existing code
as much as possible. Without inheritance, you
have only one tool for doing that, composition.
With inheritance, you have two tools.