DOC PREVIEW
UNC-Chapel Hill COMP 401 - Iterator, Scanning & Streams

This preview shows page 1-2-21-22 out of 22 pages.

Save
View full document
View full document
Premium Document
Do you want full access? Go Premium and unlock all 22 pages.
Access to all documents
Download any document
Ad free experience
View full document
Premium Document
Do you want full access? Go Premium and unlock all 22 pages.
Access to all documents
Download any document
Ad free experience
View full document
Premium Document
Do you want full access? Go Premium and unlock all 22 pages.
Access to all documents
Download any document
Ad free experience
View full document
Premium Document
Do you want full access? Go Premium and unlock all 22 pages.
Access to all documents
Download any document
Ad free experience
Premium Document
Do you want full access? Go Premium and unlock all 22 pages.
Access to all documents
Download any document
Ad free experience

Unformatted text preview:

Iterator 1 COMP 401 Prasun Dewan1 18. Iterator, Scanning & Streams Now that we understand some basic principles of creating and using objects, let us revisit the scanning problem we saw earlier and redo it using objects. In this process, we will learn about an important kind of interface, called an enumeration or iterator interface, which applies to scanning and other kinds of problems. We will motivate this interface using another scanning problem – we will show that the solutions to the two problems can reuse code if such an interface is defined. Previous Scanning Problem Recall the scanning problem we implemented in the introduction. Figure 1 Finding Upper Case Letters The following is the code we wrote: package warmup; public class AnUpperCasePrinter { public static void main(String[] args){ if (args.length != 1) { System.out.println("Illegal number of arguments:" + args.length + ". Terminating program."); System.exit(‐1); } System.out.println("Upper Case Letters:"); 1  Copyright Prasun Dewan, 2009.Iterator 2 int index = 0; while (index < args[0].length()) { if (Character.isUpperCase(args[0].charAt(index))) System.out.print(args[0].charAt(index)); index++; } } System.out.println(); } } Figure 2 An UpperCasePrinter Scanning Problem Extension Consider an extension of the problem above, in which we wante to print a string forwards and backwards, as shown below: Figure 3 Forward and Reverse Printing We can scan the string twice, once forwards and once backwards, to implement this user interface, but that is inefficient. So what we will do instead is store the upper case characters we scan into an array, and then simply print the array backwards, as shown below: package warmup; public class AReverseUpperCasePrinter { static final int MAX_CHARS = 5; static char[] upperCaseLetters = new char[MAX_CHARS]; static int numberOfUpperCaseLetters = 0; public static void main(String[] args){ if (args.length != 1) { System.out.println("Illegal number of arguments:" + args.length + ". Terminating program."); System.exit(‐1); } int index = 0; System.out.println("Upper Case Letters:"); while (index < args[0].length()) {Iterator 3 if (Character.isUpperCase(args[0].charAt(index))) { System.out.print(args[0].charAt(index)); storeChar(args[0].charAt(index)); } index++; } System.out.println(); printReverse(); } public static void storeChar(char c) { if (numberOfUpperCaseLetters == MAX_CHARS) { System.out.println("Too many upper case letters. Terminating program. "); System.exit(‐1); } upperCaseLetters[numberOfUpperCaseLetters] = c; numberOfUpperCaseLetters++; } public static void printReverse() { System.out.println("Upper Case Letters in Reverse:"); for (int index =numberOfUpperCaseLetters ‐ 1; index >= 0; index‐‐) { System.out.print(upperCaseLetters[index]); } } } Figure 4 Code for Reverse and Forward Printing In the interest of modularity, separate methods are defined for storing a character in the array and for printing them in reverse. Comparison of two solutions As we can see by comparing Figures 1 and 2, the second user‐interface is an extension of the first one. Yet the programs implementing the two user‐interfaces do not share any code. A symptom of this problem is that the main class does all of the computation. Ideally, a main class should be “skinny”, simply instantiating classes and invoking methods in the instantiated classses. The real work should be carried out in the instantiated classes ‐ that is what makes the code object‐oriented and allows for code sharing Let us look at some concrete consequences of violating this principle. Compare the two loops in the classes: //loop in AnUpperCasePrinter while (index < args[0].length()) { if (Chracater.isUpperCase(args[0].charAt(index))) System.out.print(args[0].charAt(index));Iterator 4 index++; } } //loop in AReverseUpperCasePrinter while (index < args[0].length()) { if (isUpperCase(args[0].charAt(index))) { System.out.print(args[0].charAt(index)); storeChar(args[0].charAt(index)); } index++; } The only difference in the two is that the latter does an extra step in the loop body of storing a character in the array. Yet we do not share the code. If we followed our principle of creating an extra class for the scanning part, as shown in Figure 5, then we should be able to share code? Figure 5 Creating a separate scanner class Index-based Scanner Interface It is not easy to figure out the nature of the interface of such a class. One approach is to create one that exports an array of scanned tokens: public interface IndexBasedScanner { public String[] getTokenArray () ; public int getNumberOfTokens (); } Here is an outline of the implementation of such an interface: Main Class that prints and/or stores tokensScanner class that produces tokensScanner objectInstance ofUses: Invokes methods inIntantiatesIterator 5 public class AnIndexBasedScanner implements IndexBasedScanner { static final int MAX_CHARS = 5; static char[] upperCaseLetters = new char[MAX_CHARS]; static int numberOfUpperCaseLetters = 0; public AnIndexBasedScanner(String theScannedString) { scanAndStore(theScannerString); } void scanAndStore (String theScannedString) { // store all scanned tokens in upperCaseLetters … … public String[] getTokenArray () { return upperCaseLetters; } public int getNumberOfTokens { return numberOfUpperCaseLetters; } } The idea here is to extract and store all tokens when the scanner is instantiated. A user of the class simply accesses the stored values, which are exposed by two properties: NumberOfTokens, which stores the number of scanned tokens, and TokenArray, which stores the tokens in its first NumberOfTokens slots. The getter methods for these are trivial, simply returning values of associated instance variables. The only non‐trivial method is scan(). However, it is a straightforward variation of the code we saw above, scanning all tokens in a single loop and storing each of them in the array. In comparison to the implementations we see below, this implementation is the simplest one. However, it has the serious disadvantage that it scans and stores all of the tokens, even if the user of the object needs only the first few tokens, and does no need these tokens to be stored. To help us


View Full Document

UNC-Chapel Hill COMP 401 - Iterator, Scanning & Streams

Documents in this Course
Objects

Objects

36 pages

Recursion

Recursion

45 pages

Load more
Download Iterator, Scanning & Streams
Our administrator received your request to download this document. We will send you the file to your email shortly.
Loading Unlocking...
Login

Join to view Iterator, Scanning & Streams and access 3M+ class-specific study document.

or
We will never post anything without your permission.
Don't have an account?
Sign Up

Join to view Iterator, Scanning & Streams 2 2 and access 3M+ class-specific study document.

or

By creating an account you agree to our Privacy Policy and Terms Of Use

Already a member?