Session 5 More on Java Strings and Files

  • Slides: 70
Download presentation
Session 5 More on Java Strings and Files & Intro. to Inheritance

Session 5 More on Java Strings and Files & Intro. to Inheritance

Java File I/O • Allows us to write and read “permanent” information to and

Java 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 Memo. Pad. App?

Java File I/O Example: Echo. java • echoes all the words in one file

Java 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. . .

Study Echo. java’s File I/O • have constructors that allow convenient and flexible processing

Study Echo. java’s File I/O • have constructors that allow convenient and flexible processing • send input message: read. Line() • send output messages: print() and println() • use a stereotypical loop to process a file of lines • use of the stereotypical String. Tokenizer loop as inner loop

import java. io. *; import java. util. String. Tokenizer; public class Echo { public

import java. io. *; import java. util. String. Tokenizer; public class Echo { public static void main( String[] args ) throws IOException { String delimiters = ". ? !()[]{}|? /&\, ; : -'"tnr"; Buffered. Reader input. File = new Buffered. Reader(new File. Reader(args[0]) ); Print. Writer output. File = new Print. Writer( new File. Writer( args[1] ) ); String buffer = null; while( true ) { buffer = input. File. read. Line(); if ( buffer == null ) break; buffer = buffer. to. Lower. Case(); String. Tokenizer tokens = new String. Tokenizer( buffer, delimiters ); while( tokens. has. More. Elements() ) { String word = tokens. next. Token(); output. File. println( word ); } // end while(true). . . } // end main } // end class Echo

wc - UNIX/Linux utility • wc prints the number of lines, words, and characters

wc - 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

Exercise • Using Echo. java as your starting point, create a Word. Count. java

Exercise • Using Echo. java as your starting point, create a Word. Count. 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 Word. Count hamlet. txt lines = 4792 words = 32889 chars = 130156

import java. io. *; import java. util. String. Tokenizer; public class Word. Count {

import java. io. *; import java. util. String. Tokenizer; public class Word. Count { public static void main( String[] args ) throws IOException { String delimiters = ". ? !()[]{}|? /&\, ; : -'"tnr"; Buffered. Reader input. File = new Buffered. Reader( new File. Reader( args[0] ) ); String buffer = null; int chars = 0; int words = 0; int lines = 0; while( true ) { buffer = input. File. read. Line(); if ( buffer == null ) break; lines++; buffer = buffer. to. Lower. Case(); String. Tokenizer tokens = new String. Tokenizer( buffer, delimiters ); while( tokens. has. More. Elements() ) { String word = tokens. next. Token(); words++; chars += word. length(); } // end while( true ). . . System. out. println( "" + lines + " " + words + " " + chars ); } // end main } // end class Word. Count

Why the difference in the number of words and number of characters? $ wc

Why the difference in the number of words and number of characters? $ wc hamlet. txt 4792 31957 196505 hamlet. txt $ java Word. Count hamlet. txt lines=4792 words=32889 chars=130156

Java File I/O Example: Echo. java • echoes all the words in one file

Java 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. . .

import java. io. *; import java. util. String. Tokenizer; public class Echo { public

import java. io. *; import java. util. String. Tokenizer; public class Echo { public static void main( String[] args ) throws IOException { String delimiters = ". ? !()[]{}|? /&\, ; : -'"tnr"; Buffered. Reader input. File = new Buffered. Reader(new File. Reader(args[0]) ); Print. Writer output. File = new Print. Writer( new File. Writer( args[1] ) ); String buffer = null; while( true ) { buffer = input. File. read. Line(); if ( buffer == null ) break; buffer = buffer. to. Lower. Case(); String. Tokenizer tokens = new String. Tokenizer( buffer, delimiters ); while( tokens. has. More. Elements() ) { String word = tokens. next. Token(); output. File. println( word ); } // end while(true). . . } // end main } // end class Echo

Working with Standard Input and Output as Files • Sometimes, we'd like to give

Working 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?

Streams vs. Readers and Writers • a stream is a device for transmitting or

Streams 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, Buffered. Read has read. Line method

Working with Standard Input and Output as Files • Standard input is an instance

Working with Standard Input and Output as Files • Standard input is an instance of the Input. Stream class and does not respond to read. Line(), which is how we would like to grab lines of text as Strings. • Standard output does respond to println() messages, but it is a Print. Stream, which cannot be stored in a Print. Writer variable.

What can we do? • We could write duplicate code for the four different

What 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. . .

A Solution • Let's take advantage of an object-oriented idea: We ought to be

A 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 Buffered. Readers and Print. Writers 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: Input. Stream. Reader and Output. Stream. Writer.

import java. io. *; import java. util. String. Tokenizer; public class Echo. Standard {

import java. io. *; import java. util. String. Tokenizer; public class Echo. Standard { public static void main( String[] args ) throws IOException { String delimiters = ". ? !()[]{}|? /&\, ; : -'"tnr"; Buffered. Reader input. File = new Buffered. Reader( new Input. Stream. Reader( System. in ) ); Print. Writer output. File = new Print. Writer( new Output. Stream. Writer( System. out ) ); String buffer = null; while( true ) { buffer = input. File. read. Line(); if ( buffer == null ) break; buffer = buffer. to. Lower. Case(); String. Tokenizer tokens = new String. Tokenizer(buffer, delimiters); while( tokens. has. More. Elements() ) { String word = tokens. next. Token(); output. File. println( word ); } // end while( true ). . . } // end main } // end class Echo. Standard

Echo Buffered. Reader input. File = new Buffered. Reader( new File. Reader( args[0]) );

Echo Buffered. Reader input. File = new Buffered. Reader( new File. Reader( args[0]) ); Print. Writer output. File = new Print. Writer( new File. Writer( args[1]) ); vs. Echo. Standard Buffered. Reader input. File = new Buffered. Reader( new Input. Stream. Reader( System. in ) ); Print. Writer output. File = new Print. Writer( new Output. Stream. Writer( System. out ) );

Exercise • Turn Echo. java into Echo. V 2. java, which behaves just like

Exercise • Turn Echo. java into Echo. V 2. 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 Echo. V 2 hamlet. txt hamlet. out $ less hamlet. out 1604 the tragedy of . . .

Exercise - More Examples $ java Echo. V 2. java . . . $

Exercise - More Examples $ java Echo. V 2. java . . . $ java Echo. V 2 hamlet. txt | less (interesting that the pipe “|” is not args[1]) 1604 the tragedy of. . . $ java Echo. V 2. . . $ cat hamlet. txt | java Echo. V 2 | less 1604 the tragedy of. . .

Introduction to Inheritance

Introduction to Inheritance

Accumulator Example • a simple calculator app • classes needed: – Adder. App -

Accumulator Example • a simple calculator app • classes needed: – Adder. App - contains main – Adding. Frame - GUI – Closeable. Frame - allows X button – Accumulator - internal representation and implementation of the accumulator

Adder. App • contains the main() method that serves as the "Big Bang" for

Adder. App • contains the main() method that serves as the "Big Bang" for this part of the world public class Adder. App { public static void main( String[] args ) { Adding. Frame f = new Adding. Frame(); f. show(); } // end main } // end class Adder. App

Adding. Frame • Provides the graphical interaction between the user and the actual calculator

Adding. Frame • Provides the graphical interaction between the user and the actual calculator methods • Adding. Frame extends Closeable. Frame extends JFrame. • Adding. Frame depends on the Accumulator class do the mathematics for the program.

Accumulator Class • Recall from CS I that a class contains three things. –

Accumulator Class • Recall from CS I that a class contains three things. – Data / Instance Variables – Method(s) – Constructor(s)

Accumulator Class • What Data / Instance Variables are needed?

Accumulator Class • What Data / Instance Variables are needed?

Accumulator Class • Data / Instance Variables needed: – current. Sum – the current

Accumulator Class • Data / Instance Variables needed: – current. Sum – the current value “accumulated” by the accumulator. – current. Number – the number that has been entered by the user. The value that will be added or subtracted. – display. Value – the value visible on the graphical calculator. (Needed because sometimes we display the number the user is entering (current. Number) and sometimes it is the current accumulated value (current. Sum), so we will maintain a new value which holds whatever is on display. )

Accumulator Class • What methods would the accumulator class need (hint, there are five

Accumulator Class • What methods would the accumulator class need (hint, there are five of them)?

Accumulator Class • Needed methods: – plus – adds the last number entered to

Accumulator Class • Needed methods: – plus – adds the last number entered to the current. Sum. – minus – subtracts the last number entered from the current. Sum. – clear – sets everything back to zero – add. Digit – adjusts the current. Number upon input of an additional integer – get. Display – returns the current display. Value. (This is necessary because our graphical class will want to know what value to display any time some action occurs. )

Accumulator Class • What would the constructor do?

Accumulator Class • What would the constructor do?

Accumulator. V 1 public class Accumulator. V 1 { private int current. Sum; private

Accumulator. V 1 public class Accumulator. V 1 { private int current. Sum; private int current. Number; private int display. Number; public Accumulator() { current. Sum=0; current. Number=0; display. Number=0; } public void clear() { current. Sum=0; current. Number=0; display. Number=0; } public void add. Digit( int digit ) { current. Number=current. Number*10+digit; display. Number=current. Number; } public void plus() { current. Sum+=current. Number; current. Number=0; display. Number=current. Sum; } public void minus() { current. Sum-=current. Number; current. Number=0; display. Number=current. Sum; } public int get. Display() { return display. Number; } } // end class Accumulator. V 1

Refactoring Accumulator • What is refactoring? – Changing a program in a way that

Refactoring 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?

Refactoring Accumulator • Using the clear() method in the constructor • Refactoring the plus()

Refactoring Accumulator • Using the clear() method in the constructor • Refactoring the plus() and minus() methods to call a private helper method.

Refactoring Accumulator public class Accumulator. V 2 { private int current. Sum; private int

Refactoring Accumulator public class Accumulator. V 2 { private int current. Sum; private int current. Number; private int display. Number; public Accumulator() { clear(); } public void clear() { current. Sum=0; current. Number=0; display. Number=0; } public void add. Digit( int digit ) { current. Number=current. Number*10+digit; display. Number=current. Number; } public void plus() { current. Sum+=current. Number; prepare. For. Next. Number(); } public void minus() { current. Sum-=current. Number; prepare. For. Next. Number(); } private void prepare. For. Next. Number() { current. Number=0; display. Number=current. Sum; } public int get. Display() { return display. Number; } } // end class Accumulator. V 2

Reinforcing the refactoring • There is an old programmers adage that states "There are

Reinforcing 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.

Alternative structure of the program • The complete “calculator” consists of four classes. –

Alternative structure of the program • The complete “calculator” consists of four classes. – Adder. App – Adding. Frame – Closeable. Frame – Accumulator

Alternative structure of the program • We can think of the relationships between these

Alternative structure of the program • We can think of the relationships between these four classes as being “narrow and deep” – Adder. App creates an instance of Adding. Frame which creates an instance of Accumulator. – This is a good example of data hiding since Adder. App doesn’t know/care that there is an instance of the Accumulator class. public class Adder. App { public static void main( String[] args ) { Adding. Frame f = new Adding. Frame(); f. show(); } // end main } // end class Adder. App public class Adding. Frame extends Closeable. Frame { private Accumulator my. Accumulator; . . . public Adding. Frame( ) { // create frame and accumulator my. Accumulator = new Accumulator(); . . .

Alternative structure of the program • But another way to structure this program would

Alternative structure of the program • But another way to structure this program would be to create a relationship which is “wide and shallow” – Adder. App creates an an instance of Accumulator which it passes to an instance of Adding. Frame. public class Adder. App { public static void main( String[] args ) { Accumulator a = new Accumulator(); Adding. Frame f = new Adding. Frame(a); f. show(); } // end main } // end class Adder. App – This is a good example of composition. • We emphasize that Adding. Frame 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.

Counted. Accumulator Extension • Suppose we need a new kind of object, an Accumulator

Counted. Accumulator Extension • Suppose we need a new kind of object, an Accumulator that counts how many operations it executes. Let’s call this class Counted. Accumulator. • It responds to all the same messages as a regular Accumulator and also responds to an operations. Executed() message, by returning its count. • What changes would you need to make to Accumulator?

Adding Behavior to a Class • Any time that we need to add behavior

Adding 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.

Pros and Cons “Add code to the class itself, keeping the original class. “

Pros 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 isn’t always an option.

Pros and Cons “Add code to the class itself, keeping the original class. “

Pros 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 isn’t always an option.

Pros and Cons “Add code to the class itself, keeping the original class. “

Pros 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 isn’t always an option.

Pros and Cons “Copy all the old code into a new class and add

Pros 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!

Pros and Cons “Copy all the old code into a new class and add

Pros 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!

Pros and Cons “Copy all the old code into a new class and add

Pros 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!

Pros and Cons “Create a subclass that extends the original class' behavior. “ –

Pros and Cons “Create a subclass that extends the original class' behavior. “ – Pros: Doesn’t break existing code. Virtually eliminates duplicate code. Provides the most flexibility. – Cons: Slightly more time consuming.

Pros and Cons “Create a subclass that extends the original class' behavior. “ –

Pros and Cons “Create a subclass that extends the original class' behavior. “ – Pros: Doesn’t break existing code. Virtually eliminates duplicate code. Provides the most flexibility. – Cons: Slightly more time consuming.

Pros and Cons “Create a subclass that extends the original class' behavior. “ –

Pros and Cons “Create a subclass that extends the original class' behavior. “ – Pros: Doesn’t break existing code. Virtually eliminates duplicate code. Provides the most flexibility. – Cons: Slightly more time consuming.

Developing an Extended Class • There are typically four steps in developing an extended

Developing 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

Developing an Extended Class • declare the class public class Counted. Accumulator extends Accumulator

Developing an Extended Class • declare the class public class Counted. Accumulator extends Accumulator {

Developing an Extended Class • declare the new data private int number. Of. Operations;

Developing an Extended Class • declare the new data private int number. Of. Operations;

Developing an Extended Class • create the constructor public Counted. Accumulator () { super();

Developing an Extended Class • create the constructor public Counted. Accumulator () { super(); number. Of. Operations=0; }

Developing an Extended Class • Leave inherited methods alone – clear() and prepare. For.

Developing an Extended Class • Leave inherited methods alone – clear() and prepare. For. Next. Number() are both inherited from Accumulator and there is no need to change them.

Developing an Extended Class • Modify/Override inherited methods – plus() and minus() are inherited,

Developing 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(); number. Of. Operations++; }

Developing an Extended Class • Add completely new methods – We need an accessor

Developing an Extended Class • Add completely new methods – We need an accessor method for number. Of. Operations public void operations. Executed() { return number. Of. Operations; }

Counted. Accumulator Solution public class Counted. Accumulator extends Accumulator { private int number. Of.

Counted. Accumulator Solution public class Counted. Accumulator extends Accumulator { private int number. Of. Operations; public Counted. Accumulator() { super(); // calls the superclass’ constructor number. Of. Operations=0; } public void plus() { super. plus(); number. Of. Operations++; } public void minus() { super. minus(); number. Of. Operations++; } public int get. Operations() { return number. Of. Operations; } } // end class Counted. Accumulator

Counted. Accumulator Solution • Now, before we can really work with this we need

Counted. Accumulator Solution • Now, before we can really work with this we need to modify other files in our application. • We need to set up the Adding. Frame so that it works with a Counted. Accumulator rather than a regular Accumulator. We do this in the Adder. App class for simplicity. Accumulator a = new Counted. Accumulator(); Adding. Frame f = new Adding. Frame(a);

A solution • Why do we do this in the Adder. App rather than

A solution • Why do we do this in the Adder. App rather than leave it alone and modify the Adding. Frame? – Because in the end this makes our Adding. Frame slightly more versatile. – Think about it. . . Adding. Frame works with an Accumulator (or Counted. Accumulator). If one is provided, it uses it. If one is not provided, it creates it. – THAT, is more versatile than telling an Adding. Frame to now always create a Counted. Accumulator.

A solution • Now we can run this. . . – Notice that we

A 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?

A solution that USES the counting functionality • If we want to actually use

A 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 Counted. Accumulator. • Without discussing the details of exception handling, we could do this by writing: try { Thread. sleep(10000); } catch(Exception e) { } System. out. println("Performed“ +a. get. Operations()+"operations");

Another Exercise Create a class named Even. Odd. Accumulator that subclasses Accumulator to implement

Another Exercise Create a class named Even. Odd. Accumulator that subclasses Accumulator to implement this behavior. Even. Odd. Accumulators respond to all the same messages as regular Accumulators. But, in response to plus() and minus() messages, an Even. Odd. Accumulator both computes the new sum and writes a congratulatory message if the sum is even.

Toward a Solution Here is the critical new piece of the Even. Odd. Accumulator

Toward a Solution Here is the critical new piece of the Even. Odd. Accumulator class: if ( current. Sum % 2 == 0 ) { System. out. println( "Hurray! You made an even number. " ); } The big question is, what else is a part of the class?

Toward a Solution • Let’s look at one version of this…

Toward a Solution • Let’s look at one version of this…

A Problem Accessing Inherited Data $ javac Even. Odd. Accumulator. java: 17: current. Sum

A Problem Accessing Inherited Data $ javac Even. Odd. Accumulator. java: 17: current. Sum has private access in Accumulator if ( current. Sum % 2 == 0 ) ^ Even. Odd. Accumulator. java: 24: current. Sum has private access in Accumulator if ( current. Sum % 2 == 0 ) ^ 2 errors Oops! current. Sum is declared as a private instance variable in class Accumulator. private means private: no code outside the Accumulator class can access that variable.

A Possible Solution for Accessing Inherited Data • Change current. Sum to be public

A Possible Solution for Accessing Inherited Data • Change current. Sum to be public or protected. public class Accumulator { protected int current. Sum; . . . }

A Better Solution for Accessing Inherited Data (2) Add a protected “accessor” method to

A Better Solution for Accessing Inherited Data (2) Add a protected “accessor” method to the Accumulator class. Use that method to access the current. Sum instance variable in the subclass. public class Accumulator {. . . protected int current. Sum() { return current. Sum; } } Then use current. Sum() in Even. Odd. Accumulator.

Programming with Inheritance is an object-oriented programming construct that enables us to add behavior

Programming with Inheritance is an object-oriented programming construct that enables us to add behavior to an existing system without modifying the existing classes.

Programming with Inheritance Our new Even. Odd. Accumulator class adds behavior to a program

Programming with Inheritance Our new Even. Odd. Accumulator class adds behavior to a program that uses Accumulators without modifying: • the behavior of the existing Accumulator class or • the existing Adding. Frame 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 don’t need instances of Even. Odd. Accumulator. • The ability to use Even. Odd. Accumulators in programs that expect to use Accumulators.

Programming with Inheritance We could have achieved some of these results without using inheritance

Programming with Inheritance We could have achieved some of these results without using inheritance by creating a new class named Even. Odd. Accumulator 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.