Stage 11 Array Practice With. Zip Code Encoding

Similar documents
Table of Laplace Transforms

Chapter01.fm Page 1 Monday, August 23, :52 PM. Part I of Change. The Mechanics. of Change

CSCI 1100L: Topics in Computing Lab Lab 11: Programming with Scratch

Text Input and Conditionals

Fundamentals. Fundamentals. Fundamentals. We build up instructions from three types of materials

Due: 9 February 2017 at 1159pm (2359, Pacific Standard Time)

Basic Keywords Practice Session

The compiler is spewing error messages.

6.001 Notes: Section 8.1

Repetition Through Recursion

Divisibility Rules and Their Explanations

CS201 - Assignment 3, Part 1 Due: Friday February 28, at the beginning of class

Post Experiment Interview Questions

6.001 Notes: Section 17.5

CSE 143: Computer Programming II Summer 2017 HW5: Anagrams (due Thursday, August 3, :30pm)

2SKILL. Variables Lesson 6. Remembering numbers (and other stuff)...

Chapter 5 Errors. Bjarne Stroustrup

CMSC 201 Fall 2016 Lab 09 Advanced Debugging

Reliable programming

Intro to Programming. Unit 7. What is Programming? What is Programming? Intro to Programming

CSE 142/143 Unofficial Commenting Guide Eric Arendt, Alyssa Harding, Melissa Winstanley

Note: This is a miniassignment and the grading is automated. If you do not submit it correctly, you will receive at most half credit.

Introduction to Programming

Week 3 Classes and Objects

If Statements, For Loops, Functions

Slide 1 CS 170 Java Programming 1 Testing Karel

CSE 331 Final Exam 3/16/15 Sample Solution

4. Java Project Design, Input Methods

CS103 Handout 29 Winter 2018 February 9, 2018 Inductive Proofwriting Checklist

Excel Basics: Working with Spreadsheets

COMP 202 Java in one week

Problem Solving for Intro to Computer Science

(Python) Chapter 3: Repetition

Skill 1: Multiplying Polynomials

Intro. Scheme Basics. scm> 5 5. scm>

TOPIC 2 INTRODUCTION TO JAVA AND DR JAVA

Lecture 14: Exceptions 10:00 AM, Feb 26, 2018

Initial Coding Guidelines

These are notes for the third lecture; if statements and loops.

CSE 143: Computer Programming II Winter 2019 HW6: AnagramSolver (due Thursday, Feb 28, :30pm)

T H E I N T E R A C T I V E S H E L L

Mobile Computing Professor Pushpendra Singh Indraprastha Institute of Information Technology Delhi Java Basics Lecture 02

Lab 4: Super Sudoku Solver CSCI 2101 Fall 2017

Excerpt from "Art of Problem Solving Volume 1: the Basics" 2014 AoPS Inc.

Errors. Lecture 6. Hartmut Kaiser hkaiser/fall_2011/csc1254.html

CONTENTS: While loops Class (static) variables and constants Top Down Programming For loops Nested Loops

Chapter 5 Errors. Hyunyoung Lee. Based on slides by Bjarne Stroustrup.

6.001 Notes: Section 6.1

SCRATCH MODULE 3: NUMBER CONVERSIONS

Test-Driven Development (TDD)

Assignment 4: Dodo gets smarter

************ THIS PROGRAM IS NOT ELIGIBLE FOR LATE SUBMISSION. ALL SUBMISSIONS MUST BE RECEIVED BY THE DUE DATE/TIME INDICATED ABOVE HERE

Variables and Data Representation

CSE143X: Computer Programming I & II Programming Assignment #9 due: Monday, 11/27/17, 11:00 pm

CSE 142 Su 04 Computer Programming 1 - Java. Objects

COMP-202: Foundations of Programming. Lecture 2: Variables, and Data Types Sandeep Manjanna, Summer 2015

QUIZ. What is wrong with this code that uses default arguments?

Math Modeling in Java: An S-I Compartment Model

CS 315 Software Design Homework 3 Preconditions, Postconditions, Invariants Due: Sept. 29, 11:30 PM

How to approach a computational problem

Supplemental Handout: Exceptions CS 1070, Spring 2012 Thursday, 23 Feb 2012

This course supports the assessment for Scripting and Programming Applications. The course covers 4 competencies and represents 4 competency units.

Selec%on and Decision Structures in Java: If Statements and Switch Statements CSC 121 Spring 2016 Howard Rosenthal

Math 25 and Maple 3 + 4;

Types, Expressions, and States

CS 115 Lecture 4. More Python; testing software. Neil Moore

Tips from the experts: How to waste a lot of time on this assignment

Java/RealJ Troubleshooting Guide

COMP-202 Unit 2: Java Basics. CONTENTS: Using Expressions and Variables Types Strings Methods

n! = 1 * 2 * 3 * 4 * * (n-1) * n

16 Multiple Inheritance and Extending ADTs

6.001 Notes: Section 15.1

Repetition Structures

Import Statements, Instance Members, and the Default Constructor

Condition-Controlled Loop. Condition-Controlled Loop. If Statement. Various Forms. Conditional-Controlled Loop. Loop Caution.

CS103 Spring 2018 Mathematical Vocabulary

CS 251 Intermediate Programming Methods and Classes

Signed umbers. Sign/Magnitude otation

CS 251 Intermediate Programming Methods and More

LOOPS. Repetition using the while statement

MITOCW watch?v=0jljzrnhwoi

Mathematical Data Operators

A PROGRAM IS A SEQUENCE of instructions that a computer can execute to

CSCI-1200 Data Structures Spring 2018 Lecture 14 Associative Containers (Maps), Part 1 (and Problem Solving Too)

MITOCW watch?v=zm5mw5nkzjg

Software Design and Analysis for Engineers

COMP-202 Unit 4: Programming with Iterations

UNIVERSITY OF CALIFORNIA, SANTA CRUZ BOARD OF STUDIES IN COMPUTER ENGINEERING

Compilation and Execution Simplifying Fractions. Loops If Statements. Variables Operations Using Functions Errors

5 R1 The one green in the same place so either of these could be green.

Programming II (CS300)

CS125 : Introduction to Computer Science. Lecture Notes #4 Type Checking, Input/Output, and Programming Style

COP Programming Assignment #7

Programming II (CS300)

The NetBeans IDE is a big file --- a minimum of around 30 MB. After you have downloaded the file, simply execute the file to install the software.

CIS220 In Class/Lab 1: Due Sunday night at midnight. Submit all files through Canvas (25 pts)

C++ Data Types. 1 Simple C++ Data Types 2. 3 Numeric Types Integers (whole numbers) Decimal Numbers... 5

contain a geometry package, and so on). All Java classes should belong to a package, and you specify that package by typing:

Selec%on and Decision Structures in Java: If Statements and Switch Statements CSC 121 Fall 2016 Howard Rosenthal

Expressions and Data Types CSC 121 Spring 2015 Howard Rosenthal

Transcription:

A Review of Strings You should now be proficient at using strings, but, as usual, there are a few more details you should know. First, remember these facts about strings: Array Practice With Strings are not primitives; String is a reference type. In other words, every string is really an instance of the Java s String class. This is because the compiler has to create the memory space for a string without knowing how long the string will be. A String object essentially holds an array of characters (the primitive type char) that, like all arrays, indexes the positions starting at zero. As you have seen, the String class gives us a number of methods to access the individual characters it contains, and, many applications use those capabilities to deconstruct one large string into its constituent parts. For example, if we had a String containing the date in MM/DD/YYYY format, we might want to isolate the substrings for the month, day, and year and treat them separately. Zip Code Encodings Zip Code Encoding The postal service speeds the sorting of mail by printing the zip codes as bar codes that are easily readable by various sorting machines. In this lab, we'll experiment with encoding and decoding zip codes. First, we need to understand how 5-digit zip codes are translated into bar codes. As an example, here is the encoding for the zip code "95014" using the simpler Postnet bar code that is being replaced by the more complex Intelligent Mail code: The encoding is made up of a set of bars that can be full or half height. Since each bar can only be one of two sizes, they are assigned bit values of 0 and 1. The code always begins and ends with a full height bar to help the scanning equipment line up the image. These bits are called frame bits. 241

Each digit is encoded using five bits. The first four bits of the encoding are based on positional math, like decimal math, except that the positions are assigned an unique set of multipliers. When using decimal math, a number represents a total value by multiplying each position by a power of 10, starting with a multiplier of 1 in the far right position. Each position to the left has a value of 10 times the value of the position to its right, so 1062 would be the sum of 1*1000 + 0*100 + 6*10 + 2*1. For our bar codes, each position is a bit (0 or 1) and multiplied by 1, 2, 4, and 7 starting from the right. For example, when the first four bits are 1010, the number encoded is 1*7 + 0*4 + 1*2 + 0*1 giving us a total value of 9. This positional encoding is used for every number except zero. Instead of setting the first four digits of zero to 0000, the encoding is 1100. This translates to 1*7 + 1*4 + 0*2 + 0*1 = 11! We'll come back to that to explain why in a minute. The fifth bit in the encoding of a digit is called a parity bit and is used for error checking. The value of that bit is selected so that the encoding of every digit has exactly two full-height bars and three half-height bars. This allows the scanner to detect a variety of scanning errors. For example, it will be able to detect the error of reading a full height bar as a half height bar. If it made that mistake, there would only be one full-height bar and that breaks the rules of our encodings, so we know there is an error. This detection is valid regardless of whether the misread bar is one of the first four bits or the parity bit. Now you should be able to explain why the encoding of 0 is unique. Could we have met the parity rule with the normal 0000 encoding? Can we meet it with the 1100 encoding? How do we know that 1100 isn t used anywhere else? The following table shows the encodings of every digit between 0 and 9 (where 1 is full height and 0 is half height): Digit Multiplier 7 4 2 1 Parity 1 0 0 0 1 1 2 0 0 1 0 1 3 0 0 1 1 0 4 0 1 0 0 1 5 0 1 0 1 0 6 0 1 1 0 0 7 1 0 0 0 1 8 1 0 0 1 0 9 1 0 1 0 0 0 1 1 0 0 0 The encoding of the full zip code has one more form of error checking: a check digit. The check digit is chosen so that adding up all of the digits including the check digit results in a sum that is a multiple of 10. For example, the digits in 17257 add up to 1+7+2+5+7 = 22, so the check digit would be 8 and the total sum would be 30 which is divisible by 10. 242

Tricks with the Mod Operator As we ve seen before, the modulus operator (usually shortened to mod and expressed as a % in Java) performs integer division, but, instead of returning the quotient, it returns the remainder. For example, 7 % 3 returns 1 (the remainder left after dividing 7 by 3). Often, the mod operator is used when we cycle through a series of numbers. For example, look at the following code: int count = 0; for (int i = 0; i < 10; i++) System.out.print(count + " "); count = (count + 1) % 4; Run that code with a pencil, what is the output? The interesting statement is the one that is incrementing count. When count is 0, count + 1 is 1 and the remainder when you divide by 4 is still 1, so count appears to increment. However, when count reaches 3, count + 1 is 4 and the remainder when you divide 4 by 4 is 0, so count becomes zero. In other words, count will take on this sequence of values: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1 (and then thefor loop ends). Initializing Arrays at Declaration When we worked on Decks and Cards, we studied array initializers. We re going to use them again, so let s do a quick review. If we know the initial values to be stored in an array, we can put those values in at the declaration of the array. For example, if we wanted an array that contained the first five prime numbers, we could declare and fill the array like this: int[] firstprimes = 1, 2, 3, 5, 7; That would create an array with this memory diagram. We can use this technique for initializing any array regardless of what type of values it holds. For example, boolean[] available = false, true, true, false ; creates this array: 243

Initializing arrays at declaration isn t limited to primitive types. For example, if we have a Student class whose constructor takes anint representing the student s id number, this code: Student[] mystudents = new Student(32), new Student(46), new Student(2)); creates this array: Throwing Exceptions In Java, an exception is a condition that is unexpected and requires special handling. You have already seen two exceptions: ArrayIndexOutOfBoundsException and StringIndexOutOfBoundsException. Those exceptions occurred when your code tried to use an index that was too large for the structure it was indexing. Since the code didn t know what to do, it caused an exception. In the next lab, we ll study ways to handle exceptions; for now, we will learn how to detect and throw exceptions. When the code detects that an exception has occurred, it throws the exception. This means that the current method stops running (essentially returns without a return value) and the exception is thrown to the code that called the method. For example, if we are developed a method that uses a parameter that it expects to be positive, but passed a negative value into that parameter, that would be an exception. We would want to throw an exception. Our code would look like this: public void sillymethod(int myint) throws Exception if (myint <= 0) throw new Exception("myInt cannot be negative"); // the rest of our method starting here won't // execute if the exception is thrown Since throwing the exception causes the method to return, we can be sure that myint is positive when the rest of the method starts executing. Look carefully at the throw statement; it is usually combined with the new statement. It is creating an instance of type Exception and that is what is being thrown. The parameter to the constructor of Exception is a String that is a message explaining what caused the exception. 244

Exception is the most generic type of exception you can throw. Java also comes with a number of other exception types. If you look in the Java API for the class Exception it will list a number of subclasses which are more specific types of exceptions you can throw. For example, oursillymethod() might have been more specific if it had thrown IllegalArgumentException (which is a more specific version of RunTimeException) in place of the genericexception. When you throw an exception, there is one more thing you have to do. The compiler needs to know that there is a possibility that an exception will be thrown. It will use this information to make sure that the code that called your method will either handle the exception or pass it on to the code that called it. Therefore, if the code in your method causes an exception and doesn t handle it, you must add athrows clause to your method declaration as shown in the previous example. Testing For Exceptions It is just as important that we test that exceptions are thrown correctly as it is that we test the normal functionality of our code. JUnit gives us a simple way to denote that a test should expect an exception to be thrown: after the @Test annotation, we put (expected = <expectedexception>.class). With this parameter on the annotation, the test will only pass if it sees the specified exception. For example, suppose the sillymethod() in the previous section was part of a SillyClass. If we modified it to throw an IllegalArgumentException, this test would verify that passing a zero as the parameter caused an exception: @Test (expected = IllegalArgumentException.class) public void testexception() SillyClass s = new SillyClass(); s.sillymethod(0); The only way for that test to pass is if something in it throws anillegalargumentexception. 245

Content Questions 1. Explain why 0110 is the encoding for 6. 2. There were two ways that we could have encoded 7: 1000 or 0111. Which did we pick and why? 3. Draw the memory diagram for the following code: double[] x = new double[5]; x[3] = 3.14; 4. Draw the memory diagram of the array built by the following code: String[] x = new String[6]; for (int i = 0; i < x.length; i++) x[i] = "String" + i; 5. Write a method that takes a string in the format mm/dd/yyyy and returns the day as an integer. 6. If x contains the String NXzW^&@3f what would each of the following evaluate to? a. x.charat(2); b. x.substring(3,5); c. x.length(); d. x.contains("w&"); e. x.contains("&@3"); f. x.substring(3); g. x =="NXzW^&@3f" 7. What is the output from the following code? String x = "NXzW^&@3f"; int count = 0; for (int i = 0; i < x.length(); i++) if ((x.charat(i) >= 'M') && (x.charat(i) <= 'T')) count++; System.out.println(count); 246

8. How do we mark a test that is testing to be sure a particular exception gets thrown? 9. What is the syntax to throw an exception? 10. How do you have to change the method declaration if you throw an exception? 11. In lab 8, when we built the SentenceCounter, we made it return -1 when something strange happened. Go back and look at that and describe a better solution. 12. What is the difference between the keywordsthrow andthrows? 247

Set Things Up Lab In this lab, we are going to build a class, ZipCode, that builds the bar code for a given zip code. As a plan for where we are going, here is a class diagram of the class we are working on building: There is one instance variable, zipcode, that will hold the zip code we are working on and these are the methods we are going to create are: a constructor that takes an integer parameter and stores it in the instance variable, tostring() that builds a string containing the zip code, getcheckdigit() that computes the value of the check digit for this zip code, and getbarcode() that builds a String containing the bar code for this zip code. As always, we ll build this a little at a time. Create a project in Eclipse and a JUnit test class called ZipCodeTest. Start With the Constructor You're going to create a ZipCode class that is given an integer representing a five digit zip code at construction. For now, we just want to check to make sure that it can identify itself correctly in its tostring() method. First, we write the test. In the test class, create a test method called testinitializationsimple(). This test should do the following: 1. Create an instance of ZipCode for zip code 17257. 2. Check that the tostring() of that zip code returns the string "17257"; Build the test, write enough code to make it compile, and watch it fail. (RED) The simplest way to make this test pass is to make tostring() return the String "17257". Do that to make your test pass. (GREEN) Now, we have some duplication (the 17257 is in our test and the tostring()of our ZipCode class). We are going to need to REFACTOR to get rid of it. To do that, follow these instructions: make the constructor store the zip code in its argument into the instance variable in the class diagram and return that variable (converted to a String by concatenating it to the empty String) in the tostring() method. Make sure your tests still pass. (GREEN) Zip Code Encoding 248

Constructor Border Cases Part 1 In our constructor, we are passing the zip code as an integer even though zip codes always have the same number of digits. In this case, the border cases involve the zip code beginning or ending with zeroes because these are the cases in which we are most likely to lose information, so we d like to write tests for each of those possibilities. First, let s address the issue of trailing zeros. Build a new test that does the following: 1. Create an instance of ZipCode passing 12340 to the constructor. 2. Check that the tostring() of that zip code returns the string "12340"; This test is making sure that the trailing zero in the zip code is handled properly. Luckily, it will go GREEN without any work. That doesn t mean the test isn t useful, it just means it didn t require any special code. If you want to be very thorough, make your test verify zip codes 12300, 12000, and 10000 to make sure that all trailing zeros work. Now, let s deal with leading zeros. Consider the zip code 01234. If we think of that as an integer, we wouldn t normally write the leading zero. In Java, if we use 01234 as an int, the leading zero tells the compiler to treat the number as base 8 instead of base 10. There s a long explanation for this, but, for this exercise, it s enough to know that we shouldn t put leading zeroes on ints. To test for zip codes with leading zeros, build a test that does the following: 1. Create an instance of ZipCode passing 1234 to the constructor. 2. Check that the tostring() of that zip code returns the string "01234"; Build the test and watch it fail. (RED) Clearly, leading zeroes are going to require some special handling. tostring() Phase 2 Making the leading zeros test pass is going to take a little more work, but you've done this before. Remember the issue we had when we output seconds in the duration of a song. All you have to do is tag on the leading zero to the output in the appropriate case. Don't go on until the test passes. (GREEN) More tostring() Testing Zip Codes can be any value between 1 and 99999, so they may have more than one leading zero. I doubt we've handled all of those cases, but let's improve our tests to be sure. For each of the following values, create a test, watch to see it fail (RED), then write the code to make it pass again. (GREEN) 123, 12, and 1. At this point, there s a good chance your tostring() method is getting messy. Take a minute to REFACTOR and make sure your tests still run. Right now, we are working with five-digit zip codes. However, sometimes our customers change their minds about details like that. It d be nice if we coded this in a way that would work for nine-digit zipcodes as well. Define a constant for the number of digits in a zip code and make your tostring() use it to decide when to stop adding leading zeros. Hint: you are going to need a loop. 249

Tests for Computing Check Digits The first step in encoding a zip code is to compute the check digit. As always, write the test first. Create a new test named testcheckdigit() that creates a number of different instances of zip code and checks that the getcheckdigit() method returns the appropriate integer. Watch the test fail. (RED) Computing the Check Digit Computing the check digit isn t hard, but it takes a sequence of calculations. First, we need to compute the sum of the digits in the zip code. We ve built loops that compute running sums before, so the question is, How do we tear the digits apart? To figure that out, think about what happens if evaluate x%10 for any integer x. If it helps, try it with a few different values of x. Once you see the magic that gives you, think about what happens to x if you execute: x = x/10; Together, modulus by ten and division by ten can make a beautiful sentinel-controlled loop that sums the digits of the zip code. Once you have the sum, you need to pick a number that, when added to that sum will give an overall total that is divisible by 10. That phrase, divisible by 10, should be a clue that, once again, the mod operator can help you. It might be valuable to think about what the check digits are when the sum of the digits is 2, 12, and 22. Write the code to get to GREEN and REFACTOR if necessary. Border Cases for Check Digits? As always, we need to think about the border cases. Where does the behavior of this computation change? It changes at the point where the sum of the digits is a multiple of ten. When the sum is a multiple of ten, the check digit will be zero, but when the sum is one more than a multiple of ten, the check digit will be nine. For example, the zip code 01234 needs a check digit of 0, but the zip code 11234 needs a check digit of 9. A change of one in the sum that causes a change of nine in the check digit that s certainly a cause for concern. Write a test that contains the border cases of check digits. If it passes right away, great, now we re sure it works. If not, fix the code and make sure that all of the tests run. Get to GREEN and don t forget to REFACTOR. Bar Codes - the Test Now we're really ready to generate the bar codes (or at least it feels that way!). Let's start by writing a simple test: 1. Create an instance of the zip code 17257. 2. Check to make sure that getbarcode() returns the correct bar code Wait a minute! How should we display the bar code? It should be a string, but we need to represent full height and half height bars. Let's use these characters: and ` (which looks upside down, but it's sufficient for now). Our bar code should look like this: ``` ``` `` ` ` ` ` ``` `` ` (You should be able to generate that from the zip code!) So, the assertion in the test will look like this: assertequals(" ``` ``` `` ` ` ` ` ``` `` ` ", zip.getbarcode()); Make the test compile. Run it and watch it fail. (RED) 250

Refactoring How We Store the Zip Code (background) Encoding our zip code is going to require us to look at its digits individually. We already did that once to generate the check digit. We could copy that code and modify it in getbarcode(), but it's never good to duplicate code (that duplicates bugs, too). It's time to think about how we're storing the zip code. This is an excellent example of the need to refactor. We often start with one solution and then realize that there is a better way to build the system. In these cases, we refactor the code in small steps to incrementally change from the current design to the improved design. Since we have test cases, we can be sure that we don't break anything along the way. The easiest initial strategy was to store the zip code as an int and that has carried us this far. However, since we often want to look at the individual digits, maybe it'd be better to store the digits in an array of ints. Here is a class diagram of where we are going: We re making a pretty fundamental change to our class and it s a change that will affect much of our code. The best strategy is to make this change in a series of small steps, which are detailed in the following sections of this lab. The basic idea is to create the new way we will store the data (the integer array) and then, one method at a time, convert the code to using the new array. At each step, we ll run the tests to be sure we haven t broken anything, and, if the tests are broken, the portion of the code that we have modified since the last time the tests pass will be relatively small so it shouldn t be difficult to locate the problem. We ll delete the original integer instance variable only after we have converted all of the code to use the array. While we do this, the one test of getbarcode() will be RED, but we should keep the rest of the tests GREEN. When we are refactoring, it s most comfortable if the tests are green at all times. For now, let s mark the getbarcode test with @Ignore (next to the @Test). You ll have to import org.junit.ignore to get it to compile. Then, when you run the tests, JUnit will show GREEN, and the one test that isn t complete will be shown as ignored. That way, we won t forget to come back to it after the refactoring. Refactoring How We Store the Zip Code (phase 1) For the start of this refactoring, declare the instance variable named zipdigits as an array of integers and fill it with the digits of the zip code in the constructor. (Note - we are not yet removing the integer zipcode in which you originally stored the zip code). You ll want to think about which order you want to store the digits in the array. You have two choices. For example, here are two ways we could store the zip code 17257: The first of those diagrams may seem most logical to you because you see the zip code in the order you expect. However, it s often easier to store it in the order of the second diagram because the digits that are multiplied by higher powers of ten are in the higher numbered position of the array. This means that we can calculate the value by multiplying the value in each position by ten to the power of the position minus one. In this lab, you can pick which order you prefer. And you can always change it by refactoring later! To test that you stored the digits into the array correctly, change tostring() to build the string from the array of integers. Don't go on until JUnit is GREEN. 251

Refactoring How We Store the Zip Code (phase 2) Our code now has duplication because we have the zip code stored in two places: the integer and the integer array. We need to get rid of our original integer instance variable. The only other place where we use it is in getcheckdigit(). Modify that method to use the new array (which should make it simpler). Don't go on until JUnit shows GREEN. Refactoring How We Store the Zip Code (phase 3) At this point, the original integer instance variable is not being used anywhere but the constructor. Remove it from your code and re-run your tests to be sure that everything is OK. It's important that we pay attention to what we just did. We've made a significant change to our system - its storage mechanisms are completely different. However, we made the change in stages (leaving the old storage around and replacing its use one method at a time). At every stage, we made sure that our tests pass. This way, if we broke anything, we only have to look at a small amount of modified code to find our mistakes. Back to bar codes Now that our zip code is stored in an integer array, generating the bar code will be much easier. Remove the @Ignore tag and our test will be RED. We are going to build the string in pieces, so the test won t go GREEN for a couple of steps. However, at each step we ll be able to look at the error message from JUnit to verify that we are getting closer. To start, we will need some way of generating the substrings for each digit. A simple way to do that is to store the mapping between digit and encoded string. We can define an array of strings that hold the encodings of each digit. For example, the string in position zero of this array will be " ```" since that is the encoding of 0. Similarly, to our declaration of the suits of the Cards, we can declare our array of strings for each encoded digit like this: private static final String[] CODE = " ```", "``` ", "`` ` ", "`` `", "` `` ", "` ` `", "` ``", " ``` ", " `` `", " ` ``"; You should be able to verify each string in this array. 252

Bar code generation (phase 1) Now, we're finally ready to start generating the bar code. In getbarcode(), you're going to build a string holding the bar code, but it has several pieces that we'll put together one step at a time. Remember, the bar code contains: 1. a framing full-height bit 2. encodings of each of the digits in the zip code 3. encoding of the check digit 4. a framing full-height bit Start by building a string that has the initial framing bar and make the method return that. (I know it's hard to match up these encoded strings.) Make sure the test fails with an appropriate error message. (RED) Bar code generation (phase 2) Now we need to walk through the array holding the digits of the zip code and concatenate each digit's encoding onto the string we're building. Here's a clue: since the array holding the digits is named zipdigits, the encoding of the first digit will be CODE[zipDigits[0]] Play with that code until you understand how it works. Here s how to analyze it: zipdigits[0] evaluates to an integer that is the first digit of the zip code. For example, if our zip code is 12345 and we stored the digits in the order we see them, zipdigits[0] will evaluate to 1. Therefore, CODE[zipDigits[0]] will be CODE[1]. That will be the second string in our CODE array which is "``` ". That is the string that will accurately represent the first number of our zip code. Once you see how that code works, combining it with our usual walking-through-the-array loops should be straightforward. You should be able to add the strings for the digits in the zip code to your initial framing bar. Just be careful about the direction you want to walk through the array. When you run your test, it still isn't going to pass, but you should be able to verify that the error message shows your progress. If that's too complex (because the strings are repetitive), put a breakpoint on the return statement and verify the contents of the string in the debugger. Bar code generation (completion) We're in the home stretch! You just need to concatenate the encoding of the check digit (you can call getcheckdigit() to get its value) and tack on the last framing bit. Watch all of your tests pass! (GREEN) You ve written quite a bit of code to get this test to pass. Go back and clean things up. Remember to check comments, variable names, and indentation. (REFACTOR) Let's be Thorough Just to be thorough, beef up your tests for bar code generation to include zip codes with leading and trailing zeroes and to use every digit from 0 to 9 in at least one zip code. If you code the tests correctly (and don't have any typos in the codes array declaration), they should still pass when you're finished. What Could Possibly Go Wrong? Our constructor takes an integer parameter and interprets it as a zip code, but there are integers that aren t valid zip codes. For example, negative numbers are not valid zip codes. If someone calls our constructor passing in a negative number as the zip code, that is clearly an exception (remember one definition of exception is: a situation that does not normally occur and requires special handling). Our code should detect that this has occurred and throw an appropriate exception (this time, the definition of exception is: An instance of the class Exception). 253

Testing for Negative Zip Codes Before we can throw exceptions, we first have to create our own exception class. The Java API includes some exceptions, but it d be more specific if we define our own. Create a new class called ZipCodeException and make it look like this: /** * Exceptions caused by invalid zip codes * @author Merlin * */ public class ZipCodeException extends Exception private String message; public ZipCodeException(String string) this.message = string; public String tostring() return message; In Lab 13, we ll learn what that extends keyword really means, but for now it s enough to know that it means that objects of type ZipCodeException can do everything that objects of type Exception can do. Essentially, we ve made a new type that matches Exception except that it has a different name. This way, our tests will be able to verify that the correct exception is being thrown by our code. In addition, we ve allowed that class to store a message describing what occurred just like the other exceptions that come with Java. The first exception we re going to work on is when the zip code we are given is negative. The border case for this would be when the parameter has a value of -1. Here is the JUnit test: @Test(expected = ZipCodeException.class) public void testnegative() ZipCode z = new ZipCode(-1); Run the test and it should be RED. Depending on how you coded the constructor, this might cause some other exception to be thrown (like ArrayIndexOutOfBoundsException) or, in the worst case, it could cause a loop to run forever (in this case, you won t see red the green bar in JUnit will never get to the end and the fans on your computer will probably turn on). The only way for this test to pass is for the constructor to throw the ZipCodeException. You ll need to add code at the beginning of the new constructor that checks the value of the parameter. If it is negative, throw an instance of ZipCodeException and put a reasonable description of the problem in the parameter to the new statement. When you add the throw statement, the compiler will complain because it isn t expecting that constructor to throw any exceptions. In order to fix that, you ll have to add a throws clause to the constructor definition like this: public ZipCode(int zipcode) throws ZipCodeException That will make your ZipCode class compile but it will make a number of your old tests not compile. Now that the compiler knows that the constructor might throw an exception, every method that calls that constructor must either handle the exception (which we don t yet know how to do) or just throw it on. In other words, since we aren t going to handle the exception in the tests, they will automatically throw it onto the code that called the test. Therefore we have to add a throws clause to the signature of each of those test methods. That should make everything compile and let you get back to RED. Get to GREEN and REFACTOR to clean things up. 254

Other Exceptions There are other ranges of values of the parameter to the constructor which would also represent invalid zip codes. For each, write an appropriate test. Get to RED. Then make the constructor detect the situation and throw an appropriate exception to get to GREEN. 255

Lab Questions 1. What is the bar code for the zip code 01437? 2. Explain your implementation ofgetcheckdigit(). 3. What does this code evaluate to? 4. Define these terms: CODE[getCheckDigit()] a. frame bit b. parity bit c. check digit 5. Explain the way we refactored the code to change how we stored the zip code. 6. Why did we create our own exception class? 7. Why did we have to change the definition of every test method when we made the constructor throw an exception? That seems like a terrible burden if the method throwing the exception is used in a lot of places. Why would the designers of Java forced it to work that way? 256

Vocabulary @Ignore JUnit annotation marking a test method so that it will not be run. Check digit a digit added to data with a particular characteristic that makes it unique so that errors made reading the data can be detected. Exception (1) a situation that does not normally occur and requires special handling. (2) A class provided by Java that holds information description an exception that has occurred. (3) An instance of the class Exception. Frame bit A bit at the beginning or ending of a bar code whose purpose is to allow the machine reading to bar code to orient the bar code for reading. Parity bit A bit that is added to a value to provide the ability to detect errors in reading the value. throw A statement that is used when an exception condition has been detected and handling of that exception is being passed to the calling method. throws A clause that is added to a method declaration to denote the fact that it might throw exceptions of the specified types. 257