Java

Zip Code Search

16 points

This program works with New Jersey zip codes. It begins by reading in a list of all the zip codes and the associated towns. Then it allows the user to:
1. find out if a given zip code is a valid NJ zip code
2. find the town associated with a given zip code, and
3. find the zip code closest to a given zip code.

ZipCode.java

This file creates a ZipCode class. A ZipCode object contains a String for the zip code and a String for the associated town. In ZipCode.java, import 'java.util.ArrayList'. In the private instance variable section, create a String to store the zip code and a String to store the town name. The constructor 'ZipCode' should accept these 2 Strings (perhaps 'a_ZipCode' and 'a_Town') and assign them to the 2 instance variables of the class. The method 'getZipCode()' returns the zip code String. The method 'getTown()' returns the town name String.

ZipCodeFile.java

import statements
You will want to import: java.util.ArrayList; java.io.FileReader; java.util.StringTokenizer; java.io.BufferedReader; java.io.IOException; and javax.swing.JOptionPane.

private instance variables
Declare an instance variable 'zipCodes' of type ArrayList <ZipCode>, a variable 'reader' of type FileReader and a variable 'zipCode' of type ZipCode. (ZipCode is another class, defined in ZipCode.java. See more info below.)

ZipCodeFile (constructor)
In the constructor, construct the object 'zipCodes' with a call to 'new ArrayList()'.

readZipCodes()
Inside the 'try' section, construct the object 'reader' with a call to 'new FileReader()', where you put the path to the input file 'NJZipCodes.dat' inside the parentheses. Then include the line 'BufferedReader in = new BufferedReader(reader);' to create a BufferedReader object 'in'. (Input/output is complicated in Java.)

Declare a variable 'tokenizer' of type StringTokenizer (recall that a StringTokenizer helps to parse a line of input into separate variables.) Declare variables 'line', 'zipCodeTemp' and 'townTemp' of type String, 'i' of type int, and 'done' of type boolean (and give it the value 'false').

Begin a WHILE loop based on the value of 'done' -- set it up so that the loop runs as long as 'done' is 'false'. Read in a line of input by calling the method 'readLine()' of the 'in' object, assigning the result to 'line'. If the end of the input file has been reached, 'line' will have the value 'null'. Set up an IF - ELSE statement, and in the IF check if 'line' equals 'null'. If it does, set 'done' to 'true'.

If line does not equal null (in the ELSE section), construct the object 'tokenizer' with a call to 'new StringTokenizer()', sending the variable 'line' to the constructor, inside the parentheses. Construct 'zipCodeTemp' and 'townTemp' as String objects with calls to 'new String()'. Call the 'nextToken()' method of the 'tokenizer' object and assign the result to 'zipCodeTemp'. (This assigns the zip code on 1 line of the input file to 'zipCodeTemp'.) The town name is more difficult, because it can include several words. You cannot just call 'nextToken()' again and expect to capture the entire town name. Instead, set up a WHILE loop that runs as long as 'tokenizer' has more tokens (call the 'hasMoreTokens()' method of the 'tokenizer' object.) Inside the WHILE loop, include just one line. Use syntax like 'townTemp += tokenizer.nextToken() + " ";' to ensure that 'townTemp' includes the full town name. After the WHILE loop ends, construct the object 'zipCode' with a call to 'new ZipCode()', sending into the ZipCode constructor the variables 'zipCodeTemp' and 'townTemp'. In the last line inside the ELSE, call the 'add()' method of the object 'zipCodes', sending the object 'zipCode' into 'add()'. This adds the newly-constructed 'zipCode' object to the ArrayList 'zipCodes'. Clear 'townTemp' by setting it equal to " ". End the WHILE loop, and then close the 'reader' object with a call to 'close()'.

findZipCode(String zipCode)
Declare an int 'i' and set it equal to 0. Declare a String 'zipCodeTemp'. Set up a WHILE loop that runs through all the zip codes stored in the ArrayList 'zipCodes'. Inside the loop, use the '.get()' method to retrieve 1 zip code from the ArrayList 'zipCodes'. Apply the 'getZipCode()' method to this ZipCode object, and assign the resulting zip code to 'zipCodeTemp'. You then want to compare 'zipCode' (sent in as a parameter) with 'zipCodeTemp' in an IF statement. If the 2 zip codes are equal, return 'true' and end the IF statement. In the last line in the WHILE loop, increment 'i'. After the WHILE loop, return 'false'. (This return statement only runs if 'zipCode' is not a New Jersey zip code.)

findTown(String zipCode)
The method 'findTown' accepts a String 'zipCode' as a parameter, and (if 'zipCode' is a valid New Jersey zip code) returns a String with the name of the town. Declare Strings 'zipCodeTemp' and 'townTemp'. Declare an integer. In a WHILE loop, access each zip code stored in the ArrayList 'zipCodes'. Retrieve one zip code at a time and store it in 'zipCodeTemp', just as you did in the method 'findZipCode'. In an IF statement, compare 'zipCodeTemp' with the parameter 'zipCode'. If they match, retrieve the name of the town for the zip code, using a syntax similar to what you used in 'findZipCode()' to assign a value to 'zipCodeTemp'. The difference here is that you assign the town's name to 'townTemp'. Then return 'townTemp', and end the IF statement. In the last line of the WHILE loop, increment the integer. After the WHILE loop ends, return 'null'. (This return statement runs only if 'zipCode' is not a New Jersey zip code.)

findClosest(String zipCode)
Declare integers 'i', 'diff', 'min', 'zipInt1' and 'zipInt2'. Declare Strings 'diffStr' and 'minStr'. Call 'Integer.parseInt()' to convert the parameter 'zipCode' to 'zipInt1'. In 'findZipCode()' you retrieved a zip code from a ZipCode object stored in the ArrayList 'zipCodes'. Here, use similar syntax to store the zip code from the 0th element in 'zipCodes' in 'diffStr'. Call 'Integer.parseInt()' to convert 'diffStr' to 'zipInt2'. Define 'min' to be the absolute value of the difference between 'zipInt1' and 'zipInt2'. (Math.abs() is the absolute value function.) Define 'minStr' to be equal to 'diffStr'. What you are doing here is giving 'min' and 'minStr' initial values based on the 0th ZipCode in 'zipCodes'.

Set up a WHILE loop that steps through all of the ZipCode objects stored in 'zipCodes'. If 'i' is the loop index, retrieve the 'ith' zip code String and store it in 'diffStr'. As you did above, convert 'diffStr' to 'zipInt2'. Set 'diff' equal to the absolute value of the difference between 'zipInt1' and 'zipInt2'. In an IF statement, compare 'diff' to 'min'. If 'diff' is smaller than 'min' and 'diff' is greater than 0, set 'min' equal to 'diff' and 'minStr' equal to 'diffStr'. As you step through each ZipCode in 'zipCodes', 'min' stores the difference (in integer form) between the zip code that is closest (so far) to the parameter 'zipCode' and 'zipCode', and 'minStr' stores that closest zip code. End the IF statement. Increment 'i' and end the WHILE loop. Return 'minStr'.

showMenu()
This method pops up a user-friendly menu for accessing the different methods of the program. The 3 things that a user can do are: 1) find out if a zip code is a valid New Jersey zip code, 2) for a given zip code, find the associated town, and 3) for a given zip code, find the closest zip code. Here is how the menu might appear:

Declare a String 'message' and use syntax like this to set up the menu:
message = "start of message";
message += "second line of message";
message += "third line of message"; ...
Declare an integer 'option'.

Set up a DO-WHILE loop. Inside the loop, call 'JOptionPane.showInputDialog(message)' to display 'message' and store the user's response. Call 'Integer.parseInt()' to convert the user's response from a String to the integer 'option'. Begin an IF - ELSE IF statement. If 'option' equals 1, call 'JOptionPane.showInputDialog()' to find out which zip code the user wants to search for. Then call 'findZipCode()' and store the result in a boolean variable. If 'findZipCode()' returned true, call 'JOptionPane.showMessageDialog(null, "")' to let the user know that this is a valid New Jersey zip code. Otherwise, let the user know that the zip code is not valid.

If 'option' equals 2, call 'JOptionPane.showInputDialog()' to find out for which zip code the user wants to identify the town. Call 'findTown()' and store the result in a String 'townTemp'. 'townTemp' either stores a town name or is null, if the zip code entered is not a valid NJ zip code. If 'townTemp' is not null, call 'JOptionPane.showMessageDialog(null, "")' to let the user know the name of the town:


If 'townTemp' is null, similarly let the user know that the zip code is not valid.

If 'option' equals 3, call 'JOptionPane.showInputDialog()' to find out for which zip code the user wants the closest zip code. Call 'findClosest()' and store the result in a String 'closest'. In a 'JOptionPane.showMessageDialog(null, "")' call, print out 'closest':


Finally, if 'option' equals 4, pop up a 'JOptionPane.showMessageDialog()' box saying goodbye. This is the end of the IF statement. End the DO-WHILE loop with a statement that says "keep looping as long as 'option' is not equal to 4".

public static void main(String[] args)
In 'main' construct the object 'zip' with a call to 'new ZipCodeFile()'. Call the methods 'readZipCodes()' and 'showMenu()'.

 

Demo

You can download and run CompletedZipCode.jar to get an idea of how this program will run when it is done. Before running the JAR file, download NJZipCodes.dat and store it in the same folder as CompletedZipCode.jar.

 

Starting Point

You can download ZipCode.java and ZipCodeFile.java to use as a starting point in writing your program.

You can also download NJZipCodes.dat, which lists the zip codes and the associated towns.