Class Diagram - Weather Data Application
This UML diagram shows the overall solution design:
Step One - Create the custom exception classes
There will be two custom exceptions that will need to be created in the repository, InvalidWeekException and InvalidDayOfWeekException. Each of these will pass in a root error from IllegalArgumentException. Remember, for each class, you will need to write a constructor that takes in a message as well as a Throwable argument.
Step Two - Read from file
Fill in the method readCSVLines(String filename) to get data from the CSV file and return a String with its contents.
Step Three - Read the lines into a 2D array
Fill in the method saveToMultidimensionalArray(String csvData, int numRows, int numColumns)) that takes in a String for the result from readCSVLines() and returns a String[][] value.
The CSV file will have ten weeks of data, and there are seven days a week, so the 2D String array will have 10 rows and 7 columns.
Each line in the file looks something like this:
2014-01-16,Thursday,72,56,40
Each line in the file will be written into a single element in the multi-dimensional array.
It will be your job to use a nested loop to loop through the array using a counter to keep track of the day and the week. You can assume the first entry will be at index [0][0] and the last entry will be at index [9][6].
The final multi-dimensional array "looks" like this:
Step Four - Wrap the code inside the do-while loops in try/catch blocks
We attempt to get user input inside of the do-part of the do-while loops because if the user enters an invalid input, we want to be able to keep prompting them until they enter a valid input.
Therefore, we will need to catch any exceptions created from attempting to get data for the week and the day from the user. To figure out what exception you need to catch, execute the program and attempt to put in a string input. When the program fails, look at which exception is thrown in your output so you can catch that exception.
When you catch the exception, instead of printing the exception's message, you can instead print the variables integerExceptionWeekMessage and integerExceptionDayOfWeekMessage for each of the do-while loops, depending on whether you're attempting to get week or day of week from the user.
Step Five - Throw custom exceptions for invalid input
Before we attempt to retrieve data from the multi-dimensional array, we have to make sure we have numbers for the day and week that are valid within the bounds of the array.
We want to create two try/catch blocks, one for the week number and another for the day of week number.
In each catch block, we want to print the message received from the exception and then exit the program without crashing. We don't want the program to continue running after we've received an invalid week or day of week when the input is a number outside the bounds of our multidimensional array.
Throw exception for invalid week number
We will want to check if the week number is less than 1 or greater than 10. Even though the indices for the weeks will be 0 through 9, we are asking for 1 through 10 from the user so that we can provide a more natural user experience.
If the number entered for the week is greater than 10 or less than 1, we want to throw an InvalidWeekException. For the message, we will pass it in from the variable invalidNumberExceptionWeekMessage created above.
Throw exception for invalid day of week number
We will want to check if the day of week number is less than 1 or greater than 7. Even though the indices for the days of the week will be 0 through 6, we are asking for 1 through 7 from the user so that we can provide a more natural user experience.
If the number entered for the week is greater than 7 or less than 1, we want to throw an InvalidDayWeekException. For the message, we will pass it in from the variable invalidNumberExceptionDayOfWeekMessage created above.
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.InputMismatchException; import java.util.Scanner; // create custom exceptions InvalidWeekException and InvalidDayOfWeekException first public class Application { static final String INPUT_FILENAME = "austin_weather.csv"; // removes the CSV header from the array of lines // DO NOT MODIFY THIS METHOD public static String[] removeCSVHeader(String[] originalArray){ String[] newArray = new String[originalArray.length - 1]; for (int i = 0, j = 0; i < originalArray.length; i++) { if (i != 0) { newArray[j++] = originalArray[i]; } } return newArray; } public static String readCSVLines(String filename) throws IOException{ // read in the file and return its contents return ""; } public static String[][] saveToMultidimensionalArray(String csvContent, int numRows, int numColumns){ String[] csvLines = csvContent.split("\n"); String[] csvDataWithoutHeaders = removeCSVHeader(csvLines); // create a multidimensional array with numRows rows and numColumns columns // use a nested loop to loop through each line of the CSV to put in the multidimensional array // return the multidimensional array return new String[][]{}; } public static String getWeekToSelectFromData(Scanner scanner){ System.out.print("Enter a week number between 1 and 10 with information you want: "); String weekToSelect = scanner.nextLine(); return weekToSelect; } public static String getDayToSelectFromData(Scanner scanner){ System.out.print("Enter a day number between 1 and 7 with information you want: "); String dayToSelect = scanner.nextLine(); return dayToSelect; } public static void main(String[] args) throws IOException { String csvContent = readCSVLines(INPUT_FILENAME); String[][] csvData = saveToMultidimensionalArray(csvContent, 10, 7); Scanner scanner = new Scanner(System.in); String weekToSelect; int weekNumberToSelect = 0; String dayToSelect; int dayNumberToSelect = 0; String integerExceptionDayOfWeekMessage = "You have to enter an integer for the day!"; String integerExceptionWeekMessage = "You have to enter an integer for the week!"; String invalidNumberExceptionDayOfWeekMessage = "You need to enter a number between 1 and 7 for the day!"; String invalidNumberExceptionWeekMessage = "You need to enter a number between 1 and 10 for the week!"; // do not change code in main() above this line do { // TODO: wrap the code inside the do-part of the do-while loop with a try/catch block // when the exception is caught, print the message from variable integerExceptionWeekMessage above weekToSelect = getWeekToSelectFromData(scanner); weekNumberToSelect = Integer.parseInt(weekToSelect); } while(weekNumberToSelect == 0); // TODO: Throw an InvalidWeekException if the week entered is greater than 10 or less than 1. // Use a try/catch block here to catch the exception and print the message before adding an empty return statement. // When throwing the exception, pass in the message from variable invalidNumberExceptionWeekMessage. do { // TODO: wrap the code inside the do-part of the do-while loop with a try/catch block // when the exception is caught, print the message from variable integerExceptionDayOfWeekMessage above dayToSelect = getDayToSelectFromData(scanner); dayNumberToSelect = Integer.parseInt(dayToSelect); } while(dayNumberToSelect == 0); // TODO: Throw an InvalidDayOfWeekException if the day of week entered is greater than 7 or less than 1. // Use a try/catch block here to catch the exception and print the message before adding an empty return statement. // When throwing the exception, pass in the message from variable invalidNumberExceptionDayOfWeekMessage. // do not change code in main() below this line String specificDayInfo = csvData[weekNumberToSelect - 1][dayNumberToSelect - 1]; String[] dayInfoArray = specificDayInfo.split(","); System.out.println("Date: " + dayInfoArray[0].strip()); System.out.println("Day Of Week: " + dayInfoArray[1].strip()); System.out.println("High temperature (degrees F): " + dayInfoArray[2].strip()); System.out.println("Low temperature (degrees F): " + dayInfoArray[4].strip()); System.out.println("Average temperature (degrees F): " + dayInfoArray[3].strip()); } }
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.CoreMatchers.containsString; import org.junit.jupiter.api.*; import java.io.IOException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.NoSuchElementException; import static org.junit.jupiter.api.Assertions.assertEquals; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ApplicationTest { private ByteArrayOutputStream outContent = new ByteArrayOutputStream(); private final PrintStream originalOut = System.out; private final InputStream originalIn = System.in; // Set up streams to test console input and output @BeforeAll public void setUpStreams() { System.setOut(new PrintStream(outContent)); } @AfterAll public void restoreStreams() { System.setOut(originalOut); System.setIn(originalIn); } @BeforeEach public void setTestInput() { outContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent)); } @Test public void testReadCSVFromFile() throws IOException { String filename = "austin_weather_test.csv"; String fileContents = Application.readCSVLines(filename); String expectedFileContents; if (System.getProperty("os.name").contains("Windows")) { expectedFileContents = "Date,DayOfWeek,TempHighF,TempAvgF,TempLowF\r\n" + "2013-12-22,Sunday,56,48,39\r\n" + "2013-12-23,Monday,58,45,32\r\n" + "2013-12-24,Tuesday,61,46,31\r\n" + "2013-12-25,Wednesday,58,50,41\r\n" + "2013-12-26,Thursday,57,48,39\r\n" + "2013-12-27,Friday,60,53,45\r\n" + "2013-12-28,Saturday,62,51,40"; } else { expectedFileContents = "Date,DayOfWeek,TempHighF,TempAvgF,TempLowF\n" + "2013-12-22,Sunday,56,48,39\n" + "2013-12-23,Monday,58,45,32\n" + "2013-12-24,Tuesday,61,46,31\n" + "2013-12-25,Wednesday,58,50,41\n" + "2013-12-26,Thursday,57,48,39\n" + "2013-12-27,Friday,60,53,45\n" + "2013-12-28,Saturday,62,51,40"; } assertEquals(expectedFileContents, fileContents); } @Test public void testCreateMultidimensionalArray() { int numRows = 1; int numColumns = 6; String fileContents; if (System.getProperty("os.name").contains("Windows")) { fileContents = "2013-12-22,Sunday,56,48,39\r\n" + "2013-12-23,Monday,58,45,32\r\n" + "2013-12-24,Tuesday,61,46,31\r\n" + "2013-12-25,Wednesday,58,50,41\r\n" + "2013-12-26,Thursday,57,48,39\r\n" + "2013-12-27,Friday,60,53,45\r\n" + "2013-12-28,Saturday,62,51,40"; } else { fileContents = "2013-12-22,Sunday,56,48,39\n" + "2013-12-23,Monday,58,45,32\n" + "2013-12-24,Tuesday,61,46,31\n" + "2013-12-25,Wednesday,58,50,41\n" + "2013-12-26,Thursday,57,48,39\n" + "2013-12-27,Friday,60,53,45\n" + "2013-12-28,Saturday,62,51,40"; } String[][] contentArray = Application.saveToMultidimensionalArray(fileContents, numRows, numColumns); String[] expectedArray = Application.removeCSVHeader(fileContents.split("\n")); for (int i = 0; i < 6; i++) { assertEquals(expectedArray[i], contentArray[0][i]); } } @Test public void testRunMainBadWeekInput_Word(){ runMainWithInput("Oranges\n14\n"); assertThat(outContent.toString(), containsString("You have to enter an integer for the week!")); assertThat(outContent.toString(), containsString("You need to enter a number between 1 and 10 for the week!")); } @Test public void testRunMainBadWeekInput_Number(){ runMainWithInput("14\n"); assertThat(outContent.toString(), containsString("You need to enter a number between 1 and 10 for the week!")); } @Test public void testRunMainBadWeekInput_Word_ThenGoodInput(){ runMainWithInput("Oranges\n10\n7\n"); assertThat(outContent.toString(), containsString("You have to enter an integer for the week!")); assertThat(outContent.toString(), containsString("Average temperature (degrees F): ")); } @Test public void testRunMainBadDayInput_Word(){ runMainWithInput("10\napples\n7\n"); assertThat(outContent.toString(), containsString("You have to enter an integer for the day!")); assertThat(outContent.toString(), containsString("Average temperature (degrees F): ")); } @Test public void testRunMainBadDayInput_Number(){ runMainWithInput("10\n8\n"); assertThat(outContent.toString(), containsString("You need to enter a number between 1 and 7 for the day!")); } private static void runMainWithInput(String input) { ByteArrayInputStream in = new ByteArrayInputStream(input.getBytes()); System.setIn(in); try { Application.main(new String[]{}); } catch(IOException e){ } } }