Difference between revisions of "CSC212 Lab 5 2014"
(→Make Main() catch MyException Objects) |
|||
(65 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
--[[User:Thiebaut|D. Thiebaut]] ([[User talk:Thiebaut|talk]]) 16:12, 23 September 2014 (EDT) | --[[User:Thiebaut|D. Thiebaut]] ([[User talk:Thiebaut|talk]]) 16:12, 23 September 2014 (EDT) | ||
---- | ---- | ||
− | =Problem 1= | + | =Problem 1: Generic Classes= |
+ | [[Image:GenericCupOfT.jpg|frame|from research.microsoft.com/en-us/um/people/akenn/generics/cupt.jpg]] | ||
<br /> | <br /> | ||
− | <source lang="java"> | + | * Store the program below in a file called '''Pair.java''' |
+ | <br /> | ||
+ | |||
+ | :::<source lang="java"> | ||
public class Pair<T, P> { | public class Pair<T, P> { | ||
private T first; | private T first; | ||
Line 21: | Line 25: | ||
</source> | </source> | ||
+ | <br /> | ||
+ | |||
+ | * Store the program below in a file called TestPair.java | ||
+ | <br /> | ||
+ | :::<source lang="java"> | ||
+ | class TestPair { | ||
+ | static public void main( String[] args ) { | ||
+ | Pair<Integer, Integer> p1 = null, p2 = null; | ||
+ | |||
+ | p1 = new Pair<Integer, Integer>( 10, 3 ); | ||
+ | p2 = new Pair<Integer, Integer>( 5, -9 ); | ||
+ | |||
+ | System.out.println( "p1 = " + p1 ); | ||
+ | System.out.println( "p2 = " + p2 ); | ||
+ | p1.setFirst( p2.getSecond() ); | ||
+ | System.out.println( "p1 = " + p1 ); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | <br /> | ||
+ | ;Question 1 | ||
+ | : Compile and run your program: | ||
+ | |||
+ | javac TestPair.java Pair.java | ||
+ | java TestPair | ||
+ | |||
+ | :<font color="magenta"> Verify that your program works.</font> | ||
+ | <br /> | ||
+ | ;Question 2 | ||
+ | : Modify the '''toString()''' method of Pair.java, so that it prints a pair this way: '''[10|3]''', rather than '''(10, 3)'''. <font color="magenta"> Verify that your edited program works.</font> | ||
+ | <br /> | ||
+ | ;Question 3 | ||
+ | : Change ''TestPair.java'' and replace '''Integer''' with '''Double''', so that your program can hold pairs of '''real numbers'''. Update the initialization of p1 and p2, so that you store real numbers in the pairs (e.g. 3.14159). <font color="magenta"> Verify that your edited program works.</font> Notice that you do not have to modify ''Pair.java'' at all; that's the beauty of a generic class: it will work for any type of data you want it to contain. | ||
+ | <br /> | ||
+ | ; Question 4 | ||
+ | : Change '''TestPair.java''' again, and this time modify it so that '''p1''' and '''p2''' will contain ( "Smith College", 1871 ), and ( "Hampshire College", 1965). <font color="magenta"> Verify that your edited program works.</font> | ||
+ | <br /> | ||
+ | ; Question 5 | ||
+ | : Study the [[CSC212_Example_of_Generic_Pair_Class_%26_Exercise_Solutions#Exercise_2|solution program for Exercise 2]] (seen in class). Modify '''TestPair.java''' so that it now holds an '''array of 6 (String, Integer) pairs'''. Initialize the array with these university names and the year they were founded: | ||
+ | ::* U. Bologna, 1088 | ||
+ | ::* U. Oxford, 1167 | ||
+ | ::* U. Cambridge, 1209 | ||
+ | ::* U. Salamanca, 1218 | ||
+ | ::* U. Padua, 1222 | ||
+ | ::* U. Naples, 1224 | ||
+ | : '''You will get two ''Note'' message from the compiler. This is normal. It doesn't like us using arrays of objects. But it will still generate the code. Just ignore these two '''Note'''s. | ||
+ | : Make your program output the 6 pairs. <font color="magenta"> Verify that your program works.</font> | ||
+ | <br /> | ||
+ | |||
+ | =Problem #2: Create your Own Generic Class= | ||
+ | <br /> | ||
+ | * Create a new '''generic class''' that will hold a ''triplet'' (i.e. 3 items). Call it '''Triplet.java''' and use '''Pair.java''' as an example. | ||
+ | * Create a new class called '''TestTriplet.java''' that you will adapt from '''TestPair.java'''. Make your '''TestTriplet.java''' use 3-integer triplets. <font color="magenta"> Verify that your edited program works.</font> | ||
+ | <br /> | ||
+ | <br /> | ||
+ | ;Question 1 | ||
+ | : Modify '''TestTriplet.java''' so that it now holds two ( String, Double, Integer) triplets: '''p1''', and '''p2'''. <font color="magenta"> Verify that your edited program works.</font> | ||
+ | <br /> | ||
+ | ;Question 2 | ||
+ | : Modify '''TestTriplet.java''' so that now it holds ( String, Integer, Pair( Integer, Integer ) ) !!!<br />You shouldn't have to modify '''Triplet.java''' at all! Initialize '''p1''' to ( "Smith College", 1871, ( 2600, 2014 ) ), and '''p2''' to ( "Hampshire College", 1965, ( 1400, 2014 ) ). <font color="magenta"> Verify that your edited program works.</font> | ||
+ | <br /> | ||
+ | ;Question 3 | ||
+ | : Modify '''TestTriplet.java''' and make it hold an array of 5 (Integer, Integer, Integer) triplets. Initialize the triplets as you wish. <font color="magenta"> Verify that your edited program works.</font> | ||
+ | <br /> | ||
− | # | + | =Problem #3: Review '''Continue''' and '''Break''' Statements= |
− | + | <br /> | |
− | # | + | * This tiny section is just to make sure you remember how '''break''' and '''continue''' work in loops. They work equally well in '''for-loops''' as in '''while-loops'''. |
− | + | * Study the program below. | |
− | + | * Guess its output. | |
− | + | * <font color="magenta">Run the program and verify that your intuition was correct!</font> | |
− | + | <br /> | |
− | : | + | :::<source lang="java"> |
− | : | + | public class ContinueBreak { |
+ | |||
+ | public static void main(String[] args) { | ||
+ | |||
+ | for ( int i=0; i<10000; i++ ) { | ||
+ | if ( i % 3 == 0 ) | ||
+ | continue; | ||
+ | if ( i >= 50 ) | ||
+ | break; | ||
+ | System.out.println( "i = " + i); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | </source> | ||
+ | <br /> | ||
+ | |||
+ | =Problem #4: Exceptions= | ||
+ | [[Image:Bomb.jpg|right|250px|http://4.bp.blogspot.com/-UfVU-B94K0A/UFH6jxMoy9I/AAAAAAAAFt4/qzZuyn5_-kE/s1600/bomb.jpeg]] | ||
+ | <br /> | ||
+ | ==Simple Exceptions== | ||
+ | * Create a new program called Bomb.java with the following code: | ||
+ | <br /> | ||
+ | ::<source lang="java"> | ||
+ | import java.util.Scanner; | ||
+ | |||
+ | public class Bomb { | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | Scanner input = new Scanner( System.in ); | ||
+ | |||
+ | while ( true ) { | ||
+ | System.out.println( "Please enter 2 integers" | ||
+ | +" (-1 to stop): "); | ||
+ | int n1 = input.nextInt(); | ||
+ | if ( n1==-1 ) | ||
+ | break; | ||
+ | int n2 = input.nextInt(); | ||
+ | System.out.println( n1 + " / " + n2 + " is " + (n1/n2) ); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | </source> | ||
+ | <br /> | ||
+ | * Run your program and enter some numbers. Nothing terribly exciting will happen, until you enter 0 as the second number, of course. Try it. | ||
+ | * Boom! | ||
+ | * Note the name of the exception that appears on your screen: java.lang.'''SomeNameException'''. | ||
+ | * Edit your program so that you can now '''catch''' the exception and process it. Put the '''try'''/'''catch''' statement as close to the problematic code as possible (and replace xxxxxxxxxxxxxxx by the actual exception name). | ||
+ | ::<source lang="java"> | ||
+ | |||
+ | while ( true ) { | ||
+ | System.out.println( "Please enter 2 integers (-1 to stop): "); | ||
+ | int n1 = input.nextInt(); | ||
+ | int n2 = input.nextInt(); | ||
+ | if ( n1==-1 || n2==-1 ) | ||
+ | break; | ||
+ | try { | ||
+ | System.out.println( n1 + " / " + n2 + " is " + (n1/n2) ); | ||
+ | } | ||
+ | catch ( xxxxxxxxxxxxxxx e ) { | ||
+ | System.out.println("Exception: " + e.getMessage() + | ||
+ | "\nReenter numbers." ); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | <br /> | ||
+ | * Note that we not using a '''finally''' block here. | ||
+ | <br /> | ||
+ | ==More Complex Exceptions== | ||
+ | <br /> | ||
+ | * The '''ArithmeticException''' exception above is known to the java compiler. We refer to this type of exections as ''checked'' exceptions. The compiler knows how to deal with them. However, other exceptions (''unchecked'') are associated with library functions, or with our own classes, and the compiler may not flag them at compile time. Nevertheless, we should catch them. We illustrate this situation in this section. | ||
+ | <br /> | ||
+ | |||
+ | * Use the same program (Bomb.java) as above. Try inputting a string instead of an integer | ||
+ | * Note that an exception occurs. Write down its name. | ||
+ | * Add a '''try/catch ''' statement around the input sections of your program. <font color="red">Make sure you declare your variables '''before''' the '''try/catch''' statement.</font> This is because if you do not, n1 and n2 would not "exist" outside the '''try/catch''' block. | ||
+ | <br /> | ||
+ | ::<source lang="java"> | ||
+ | int n1, n2; | ||
+ | try { | ||
+ | n1 = input.nextInt(); | ||
+ | if ( n1==-1 ) break; | ||
+ | n2 = input.nextInt(); | ||
+ | } catch ( InputMismatchException e ) { | ||
+ | // add your code here... | ||
+ | } | ||
+ | </source> | ||
+ | <br /> | ||
+ | * Compile your program. Observe that you have an error... The compiler is complaining that the '''InputMismatchException''' type is unknown. So we have to import it in our program: | ||
+ | <br /> | ||
+ | ::<source lang="java" highlight="2"> | ||
+ | import java.util.Scanner; | ||
+ | import java.util.InputMismatchException; | ||
+ | |||
+ | public class Bomb { | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | Scanner input = new Scanner( System.in ); | ||
+ | |||
+ | while ( true ) { | ||
+ | System.out.println( "Please enter 2 integers (-1 to stop): "); | ||
+ | int n1, n2; | ||
+ | try { | ||
+ | n1 = input.nextInt(); | ||
+ | if ( n1==-1 ) break; | ||
+ | n2 = input.nextInt(); | ||
+ | } catch ( InputMismatchException e ) { | ||
+ | // add your code here... | ||
+ | } | ||
+ | |||
+ | //... some code missing... | ||
+ | </source> | ||
+ | <br /> | ||
+ | * Make your program skip printing n1 / n2 if the user inputs a string instead of an integer. | ||
+ | <br /> | ||
+ | <br /> | ||
+ | * Are you getting an infinite loop? You should be getting an infinite loop. The reason is that if the user enters a string and your program executes an '''input.nextInt()''' statement, nextInt() stops on the first character that is not a number, and never removes the string from the ''input buffer''. So when the loop starts again, the next nextInt() to run gets stuck on the same string the user entered the first time. | ||
+ | :Solution: Add an '''input.nextLine()''' statement in your '''catch''' statement to clear the ''input buffer''. | ||
+ | * Try it. <font color="magenta"> Verify that your program works</font>. | ||
+ | <br /> | ||
+ | |||
+ | ==Still More Complex Exceptions== | ||
+ | <br /> | ||
+ | ===Create a Data File=== | ||
+ | * Use '''emacs''' to create a text file called '''data.txt''' containing a few lines with 2 numbers on each line: | ||
+ | <br /> | ||
+ | ::<source lang="text"> | ||
+ | 2 1 | ||
+ | 10 2 | ||
+ | 100 3 | ||
+ | -10 2 | ||
+ | 6 3 | ||
+ | </source> | ||
+ | <br /> | ||
+ | * Make sure there are no extra blank lines in your file. | ||
+ | <br /> | ||
+ | |||
+ | ===Create a New Java Program=== | ||
+ | * Create a program called '''Lab5ReadFile.java''' with the code below: | ||
+ | <br /> | ||
+ | ::<source lang="java"> | ||
+ | /** | ||
+ | * Lab5ReadFile.java | ||
+ | * @author your-name | ||
+ | */ | ||
+ | |||
+ | import java.io.File; | ||
+ | import java.util.Scanner; | ||
+ | |||
+ | public class Lab5ReadFile { | ||
+ | |||
+ | public static void main( String[] args ) { | ||
+ | |||
+ | String fileName; | ||
+ | int n1, n2; | ||
+ | Scanner inFile = null; | ||
+ | |||
+ | // if user forgot the enter file name on command line, remind her | ||
+ | if ( args.length == 0 ) { | ||
+ | System.out.println( "Syntax: java Lab5ReadFile textFileName" ); | ||
+ | System.out.println( " where textFileName is a name of a data file."); | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | // set file name to first argument on command line | ||
+ | fileName = args[0]; | ||
+ | inFile = new Scanner( new File( fileName ) ); | ||
+ | |||
+ | // read the file | ||
+ | while ( inFile.hasNext() ) { | ||
+ | n1 = inFile.nextInt(); | ||
+ | n2 = inFile.nextInt(); | ||
+ | System.out.println( n1 + " / " + n2 + " is " + n1/n2 ); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | <br /> | ||
+ | ===Pass 1=== | ||
+ | <br /> | ||
+ | * Compile it! | ||
+ | * You will get an error: | ||
+ | |||
+ | '''Lab5ReadFile.java:XX: error''': unreported exception FileNotFoundException; must be caught or declared to be thrown | ||
+ | inFile = new Scanner( new File( fileName ) ); | ||
+ | |||
+ | :The Java compiler knows that the '''File''' class is designed to '''throw''' an exception if something goes wrong opening a file. The Java compiler is thus '''forcing''' you to put a '''try/catch''' statement around the '''new File(...)''' statement, or forcing you to add a '''throw''' statement after main(). Let's worry about '''throw''' later. | ||
+ | <br /> | ||
+ | * Add a throw/catch statement around the '''inFile = new Scanner( new File( fileName ) );''' statement. The exception you want to catch is a '''FileNotFoundException''', which should be imported with a '''import java.io.FileNotFoundException;''' statement. | ||
+ | : You probably want your program to stop (i.e. return from main) in your catch block. | ||
+ | * Run your program, first with an erroneous file name: | ||
+ | |||
+ | javac Lab5ReadFile.java | ||
+ | java Lab5ReadFile '''toto.txt''' | ||
+ | |||
+ | :<font color="magenta">Verify that your program does not crash.</font> | ||
+ | * Try again, but this time with the name of your data file: | ||
+ | |||
+ | java Lab5ReadFile data.txt | ||
+ | |||
+ | :<font color="magenta">Verify that your program displays the correct numbers.</font> | ||
+ | <br /> | ||
+ | |||
+ | ===Pass 2 === | ||
+ | <br /> | ||
+ | * Copy your data file into a new file: | ||
+ | |||
+ | cp data.txt badData.txt | ||
+ | |||
+ | : and add some eroneous integers in the new data file, something that the '''nextInt()''' function will not like (e.g. 3.145, Toto, Smith, 1E10, etc.) | ||
+ | * Also make sure one of the input lines has 0 as the second number. | ||
+ | * Run your program with the new data file: | ||
+ | |||
+ | java Lab5ReadFile badData.txt | ||
+ | |||
+ | :and fix every exception that gets sent to the Operating System. | ||
+ | * You should now be able to protect your program with try/catch statements similar to what you did with the keyboard input version. | ||
+ | * Go at it! <font color="magenta">Make sure your program does not crash on any of the erroneous inputs</font>. | ||
+ | <br /> | ||
+ | =Throwing Exceptions= | ||
+ | <br /> | ||
+ | * Create this new program, called '''Lab5ReadFileThrow.java''': | ||
+ | <br /> | ||
+ | ::<source lang="java"> | ||
+ | import java.io.File; | ||
+ | import java.io.FileNotFoundException; | ||
+ | import java.util.Scanner; | ||
+ | |||
+ | public class Lab5ReadFileThrow { | ||
+ | |||
+ | private static Scanner openFile( String fileName ) throws FileNotFoundException { | ||
+ | Scanner inFile; | ||
+ | inFile = new Scanner(new File(fileName)); | ||
+ | return inFile; | ||
+ | } | ||
+ | |||
+ | private static int[] get2Ints( Scanner inFile ) { | ||
+ | int n1 = inFile.nextInt(); | ||
+ | int n2 = inFile.nextInt(); | ||
+ | return new int[] { n1, n2 }; | ||
+ | } | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | |||
+ | Scanner inFile = null; | ||
+ | |||
+ | // if user forgot the enter file name on command line, remind her | ||
+ | if (args.length == 0) { | ||
+ | System.out.println("Syntax: java Lab5ReadFile textFileName"); | ||
+ | System.out | ||
+ | .println(" where textFileName is a name of a data file."); | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | // set file name to first argument on command line | ||
+ | try { | ||
+ | inFile = openFile( args[0] ); | ||
+ | } catch (FileNotFoundException e) { | ||
+ | System.err.println( "Could not find file " + args[0] ); | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | // read the file | ||
+ | while (inFile.hasNext()) { | ||
+ | int[] a = get2Ints( inFile ); | ||
+ | System.out.println( a[0] + " / " + a[1] + " is " + a[0] / a[1] ); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | <br /> | ||
+ | * It is slightly different from the previous version. | ||
+ | * Take a few minutes to read it, and study the new ''method'', and the use of the array '''int[] a'''. Make sure you understand the code. Otherwise ask the TA or myself for explanations. | ||
+ | * Compile, then run your program with your good text file: | ||
+ | |||
+ | java Lab5ReadFileThrow data.txt | ||
+ | |||
+ | * <font color="magenta">Verify that you get a valid output.</font> | ||
+ | * Run your program with the erroneous data file: | ||
+ | |||
+ | java Lab5ReadFileThrow badData.txt | ||
+ | |||
+ | : and observe the exception thrown back by your program. | ||
+ | * Fix the errors by making the method '''get2Ints()''' throw an '''InputMismatchException''' exception. | ||
+ | * Enclose the call to the method in main by a '''try/catch''' block. | ||
+ | * Run your program again on the bad data, and <font color="magenta">verify that you do not get the inputMismatchException any longer.</font> You get another type of exception, though... Let's deal with that now. | ||
+ | |||
+ | <br /> | ||
+ | ==Creating Our Own Exception Objects, and Throwing Them!== | ||
+ | <br /> | ||
+ | * In this section, you will create your Exception class, and make the get2Ints() method throw an object of this new class if the second int on a line of the data file is 0. The main program will catch this exception. | ||
+ | <br /> | ||
+ | ===Create an Exception Class=== | ||
+ | <br /> | ||
+ | * Add this class at the top of your program, between the '''import''' lines and the '''public class Lab5ReadFileThrow''' line: | ||
+ | <br /> | ||
+ | ::<source lang="Java"> | ||
+ | class MyException extends Exception { | ||
+ | MyException( String message ) { | ||
+ | super( message ); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | <br /> | ||
+ | : It is a very simple container that inherit the Java class '''Exception''' and just stores an error message that will be specified when the object is created. | ||
+ | <br /> | ||
+ | ===Make '''get2Ints()''' throw MyException=== | ||
+ | <br /> | ||
+ | ::<source lang="java" highlight="1,4-6"> | ||
+ | private static int[] get2Ints( Scanner inFile ) throws InputMismatchException, MyException { | ||
+ | int n1 = inFile.nextInt(); | ||
+ | int n2 = inFile.nextInt(); | ||
+ | if ( n2 == 0 ) { | ||
+ | throw new MyException( "Invalid 2nd operand: 0\n" ); | ||
+ | } | ||
+ | return new int[] { n1, n2 }; | ||
+ | } | ||
+ | </source> | ||
+ | <br /> | ||
+ | |||
+ | ===Make Main() catch MyException Objects=== | ||
+ | <br /> | ||
+ | ::<source lang="java"> | ||
+ | while (inFile.hasNext()) { | ||
+ | int[] a; | ||
+ | try { | ||
+ | a = get2Ints( inFile ); | ||
+ | } catch ( InputMismatchException e ) { | ||
+ | System.err.println( "Wrong number format. Please reenter!" ); | ||
+ | inFile.nextLine(); | ||
+ | continue; | ||
+ | } catch ( MyException e) { | ||
+ | System.err.println( "Invalid second int: 0. Skipping this line." ); | ||
+ | continue; | ||
+ | } | ||
+ | System.out.println( a[0] + " / " + a[1] + " is " + a[0] / a[1] ); | ||
+ | } | ||
+ | </source> | ||
+ | <br /> | ||
+ | |||
+ | ===Verification=== | ||
+ | <br /> | ||
+ | * Put your program together, and verify that it works on the '''badData.txt''' file. In my case, this is what I get: | ||
+ | <br /> | ||
+ | $: '''cat badData.txt ''' | ||
+ | 1 2 | ||
+ | 10 5 | ||
+ | Smith 4 3 | ||
+ | 5 0 | ||
+ | -1 -1 | ||
+ | 6 2 | ||
+ | |||
+ | $: '''java Lab5ReadFileThrow badData.txt ''' | ||
+ | 1 / 2 is 0 | ||
+ | 10 / 5 is 2 | ||
+ | Wrong number format. Please reenter! | ||
+ | Invalid second int: 0. Skipping this line. | ||
+ | -1 / -1 is 1 | ||
+ | 6 / 2 is 3 | ||
+ | |||
+ | <br /> | ||
+ | |||
+ | =Moodle Submission= | ||
+ | <br /> | ||
+ | * Submit your program to Moodle. | ||
+ | <br /> | ||
+ | <br /> | ||
+ | <br /> | ||
+ | <br /> | ||
+ | <br /> | ||
+ | [[Category:CSC212]][[Category:Java]] |
Latest revision as of 15:24, 25 September 2014
--D. Thiebaut (talk) 16:12, 23 September 2014 (EDT)
Contents
Problem 1: Generic Classes
- Store the program below in a file called Pair.java
public class Pair<T, P> { private T first; private P second; public Pair( T f, P s ) { first = f; second = s; } public T getFirst() { return first; } public P getSecond() { return second; } public void setFirst( T f ) { first = f; } public void setSecond( P s ) { second = s; } public String toString( ) { return "(" + first + ", " + second + ")"; } }
- Store the program below in a file called TestPair.java
class TestPair { static public void main( String[] args ) { Pair<Integer, Integer> p1 = null, p2 = null; p1 = new Pair<Integer, Integer>( 10, 3 ); p2 = new Pair<Integer, Integer>( 5, -9 ); System.out.println( "p1 = " + p1 ); System.out.println( "p2 = " + p2 ); p1.setFirst( p2.getSecond() ); System.out.println( "p1 = " + p1 ); } }
- Question 1
- Compile and run your program:
javac TestPair.java Pair.java java TestPair
- Verify that your program works.
- Question 2
- Modify the toString() method of Pair.java, so that it prints a pair this way: [10|3], rather than (10, 3). Verify that your edited program works.
- Question 3
- Change TestPair.java and replace Integer with Double, so that your program can hold pairs of real numbers. Update the initialization of p1 and p2, so that you store real numbers in the pairs (e.g. 3.14159). Verify that your edited program works. Notice that you do not have to modify Pair.java at all; that's the beauty of a generic class: it will work for any type of data you want it to contain.
- Question 4
- Change TestPair.java again, and this time modify it so that p1 and p2 will contain ( "Smith College", 1871 ), and ( "Hampshire College", 1965). Verify that your edited program works.
- Question 5
- Study the solution program for Exercise 2 (seen in class). Modify TestPair.java so that it now holds an array of 6 (String, Integer) pairs. Initialize the array with these university names and the year they were founded:
- U. Bologna, 1088
- U. Oxford, 1167
- U. Cambridge, 1209
- U. Salamanca, 1218
- U. Padua, 1222
- U. Naples, 1224
- You will get two Note message from the compiler. This is normal. It doesn't like us using arrays of objects. But it will still generate the code. Just ignore these two Notes.
- Make your program output the 6 pairs. Verify that your program works.
Problem #2: Create your Own Generic Class
- Create a new generic class that will hold a triplet (i.e. 3 items). Call it Triplet.java and use Pair.java as an example.
- Create a new class called TestTriplet.java that you will adapt from TestPair.java. Make your TestTriplet.java use 3-integer triplets. Verify that your edited program works.
- Question 1
- Modify TestTriplet.java so that it now holds two ( String, Double, Integer) triplets: p1, and p2. Verify that your edited program works.
- Question 2
- Modify TestTriplet.java so that now it holds ( String, Integer, Pair( Integer, Integer ) ) !!!
You shouldn't have to modify Triplet.java at all! Initialize p1 to ( "Smith College", 1871, ( 2600, 2014 ) ), and p2 to ( "Hampshire College", 1965, ( 1400, 2014 ) ). Verify that your edited program works.
- Question 3
- Modify TestTriplet.java and make it hold an array of 5 (Integer, Integer, Integer) triplets. Initialize the triplets as you wish. Verify that your edited program works.
Problem #3: Review Continue and Break Statements
- This tiny section is just to make sure you remember how break and continue work in loops. They work equally well in for-loops as in while-loops.
- Study the program below.
- Guess its output.
- Run the program and verify that your intuition was correct!
public class ContinueBreak { public static void main(String[] args) { for ( int i=0; i<10000; i++ ) { if ( i % 3 == 0 ) continue; if ( i >= 50 ) break; System.out.println( "i = " + i); } } }
Problem #4: Exceptions
Simple Exceptions
- Create a new program called Bomb.java with the following code:
import java.util.Scanner; public class Bomb { public static void main(String[] args) { Scanner input = new Scanner( System.in ); while ( true ) { System.out.println( "Please enter 2 integers" +" (-1 to stop): "); int n1 = input.nextInt(); if ( n1==-1 ) break; int n2 = input.nextInt(); System.out.println( n1 + " / " + n2 + " is " + (n1/n2) ); } } }
- Run your program and enter some numbers. Nothing terribly exciting will happen, until you enter 0 as the second number, of course. Try it.
- Boom!
- Note the name of the exception that appears on your screen: java.lang.SomeNameException.
- Edit your program so that you can now catch the exception and process it. Put the try/catch statement as close to the problematic code as possible (and replace xxxxxxxxxxxxxxx by the actual exception name).
while ( true ) { System.out.println( "Please enter 2 integers (-1 to stop): "); int n1 = input.nextInt(); int n2 = input.nextInt(); if ( n1==-1 || n2==-1 ) break; try { System.out.println( n1 + " / " + n2 + " is " + (n1/n2) ); } catch ( xxxxxxxxxxxxxxx e ) { System.out.println("Exception: " + e.getMessage() + "\nReenter numbers." ); } }
- Note that we not using a finally block here.
More Complex Exceptions
- The ArithmeticException exception above is known to the java compiler. We refer to this type of exections as checked exceptions. The compiler knows how to deal with them. However, other exceptions (unchecked) are associated with library functions, or with our own classes, and the compiler may not flag them at compile time. Nevertheless, we should catch them. We illustrate this situation in this section.
- Use the same program (Bomb.java) as above. Try inputting a string instead of an integer
- Note that an exception occurs. Write down its name.
- Add a try/catch statement around the input sections of your program. Make sure you declare your variables before the try/catch statement. This is because if you do not, n1 and n2 would not "exist" outside the try/catch block.
int n1, n2; try { n1 = input.nextInt(); if ( n1==-1 ) break; n2 = input.nextInt(); } catch ( InputMismatchException e ) { // add your code here... }
- Compile your program. Observe that you have an error... The compiler is complaining that the InputMismatchException type is unknown. So we have to import it in our program:
import java.util.Scanner; import java.util.InputMismatchException; public class Bomb { public static void main(String[] args) { Scanner input = new Scanner( System.in ); while ( true ) { System.out.println( "Please enter 2 integers (-1 to stop): "); int n1, n2; try { n1 = input.nextInt(); if ( n1==-1 ) break; n2 = input.nextInt(); } catch ( InputMismatchException e ) { // add your code here... } //... some code missing...
- Make your program skip printing n1 / n2 if the user inputs a string instead of an integer.
- Are you getting an infinite loop? You should be getting an infinite loop. The reason is that if the user enters a string and your program executes an input.nextInt() statement, nextInt() stops on the first character that is not a number, and never removes the string from the input buffer. So when the loop starts again, the next nextInt() to run gets stuck on the same string the user entered the first time.
- Solution: Add an input.nextLine() statement in your catch statement to clear the input buffer.
- Try it. Verify that your program works.
Still More Complex Exceptions
Create a Data File
- Use emacs to create a text file called data.txt containing a few lines with 2 numbers on each line:
2 1 10 2 100 3 -10 2 6 3
- Make sure there are no extra blank lines in your file.
Create a New Java Program
- Create a program called Lab5ReadFile.java with the code below:
/** * Lab5ReadFile.java * @author your-name */ import java.io.File; import java.util.Scanner; public class Lab5ReadFile { public static void main( String[] args ) { String fileName; int n1, n2; Scanner inFile = null; // if user forgot the enter file name on command line, remind her if ( args.length == 0 ) { System.out.println( "Syntax: java Lab5ReadFile textFileName" ); System.out.println( " where textFileName is a name of a data file."); return; } // set file name to first argument on command line fileName = args[0]; inFile = new Scanner( new File( fileName ) ); // read the file while ( inFile.hasNext() ) { n1 = inFile.nextInt(); n2 = inFile.nextInt(); System.out.println( n1 + " / " + n2 + " is " + n1/n2 ); } } }
Pass 1
- Compile it!
- You will get an error:
Lab5ReadFile.java:XX: error: unreported exception FileNotFoundException; must be caught or declared to be thrown inFile = new Scanner( new File( fileName ) );
- The Java compiler knows that the File class is designed to throw an exception if something goes wrong opening a file. The Java compiler is thus forcing you to put a try/catch statement around the new File(...) statement, or forcing you to add a throw statement after main(). Let's worry about throw later.
- Add a throw/catch statement around the inFile = new Scanner( new File( fileName ) ); statement. The exception you want to catch is a FileNotFoundException, which should be imported with a import java.io.FileNotFoundException; statement.
- You probably want your program to stop (i.e. return from main) in your catch block.
- Run your program, first with an erroneous file name:
javac Lab5ReadFile.java java Lab5ReadFile toto.txt
- Verify that your program does not crash.
- Try again, but this time with the name of your data file:
java Lab5ReadFile data.txt
- Verify that your program displays the correct numbers.
Pass 2
- Copy your data file into a new file:
cp data.txt badData.txt
- and add some eroneous integers in the new data file, something that the nextInt() function will not like (e.g. 3.145, Toto, Smith, 1E10, etc.)
- Also make sure one of the input lines has 0 as the second number.
- Run your program with the new data file:
java Lab5ReadFile badData.txt
- and fix every exception that gets sent to the Operating System.
- You should now be able to protect your program with try/catch statements similar to what you did with the keyboard input version.
- Go at it! Make sure your program does not crash on any of the erroneous inputs.
Throwing Exceptions
- Create this new program, called Lab5ReadFileThrow.java:
import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; public class Lab5ReadFileThrow { private static Scanner openFile( String fileName ) throws FileNotFoundException { Scanner inFile; inFile = new Scanner(new File(fileName)); return inFile; } private static int[] get2Ints( Scanner inFile ) { int n1 = inFile.nextInt(); int n2 = inFile.nextInt(); return new int[] { n1, n2 }; } public static void main(String[] args) { Scanner inFile = null; // if user forgot the enter file name on command line, remind her if (args.length == 0) { System.out.println("Syntax: java Lab5ReadFile textFileName"); System.out .println(" where textFileName is a name of a data file."); return; } // set file name to first argument on command line try { inFile = openFile( args[0] ); } catch (FileNotFoundException e) { System.err.println( "Could not find file " + args[0] ); return; } // read the file while (inFile.hasNext()) { int[] a = get2Ints( inFile ); System.out.println( a[0] + " / " + a[1] + " is " + a[0] / a[1] ); } } }
- It is slightly different from the previous version.
- Take a few minutes to read it, and study the new method, and the use of the array int[] a. Make sure you understand the code. Otherwise ask the TA or myself for explanations.
- Compile, then run your program with your good text file:
java Lab5ReadFileThrow data.txt
- Verify that you get a valid output.
- Run your program with the erroneous data file:
java Lab5ReadFileThrow badData.txt
- and observe the exception thrown back by your program.
- Fix the errors by making the method get2Ints() throw an InputMismatchException exception.
- Enclose the call to the method in main by a try/catch block.
- Run your program again on the bad data, and verify that you do not get the inputMismatchException any longer. You get another type of exception, though... Let's deal with that now.
Creating Our Own Exception Objects, and Throwing Them!
- In this section, you will create your Exception class, and make the get2Ints() method throw an object of this new class if the second int on a line of the data file is 0. The main program will catch this exception.
Create an Exception Class
- Add this class at the top of your program, between the import lines and the public class Lab5ReadFileThrow line:
class MyException extends Exception { MyException( String message ) { super( message ); } }
- It is a very simple container that inherit the Java class Exception and just stores an error message that will be specified when the object is created.
Make get2Ints() throw MyException
private static int[] get2Ints( Scanner inFile ) throws InputMismatchException, MyException { int n1 = inFile.nextInt(); int n2 = inFile.nextInt(); if ( n2 == 0 ) { throw new MyException( "Invalid 2nd operand: 0\n" ); } return new int[] { n1, n2 }; }
Make Main() catch MyException Objects
while (inFile.hasNext()) { int[] a; try { a = get2Ints( inFile ); } catch ( InputMismatchException e ) { System.err.println( "Wrong number format. Please reenter!" ); inFile.nextLine(); continue; } catch ( MyException e) { System.err.println( "Invalid second int: 0. Skipping this line." ); continue; } System.out.println( a[0] + " / " + a[1] + " is " + a[0] / a[1] ); }
Verification
- Put your program together, and verify that it works on the badData.txt file. In my case, this is what I get:
$: cat badData.txt 1 2 10 5 Smith 4 3 5 0 -1 -1 6 2 $: java Lab5ReadFileThrow badData.txt 1 / 2 is 0 10 / 5 is 2 Wrong number format. Please reenter! Invalid second int: 0. Skipping this line. -1 / -1 is 1 6 / 2 is 3
Moodle Submission
- Submit your program to Moodle.