CS62 - Fall 2020 - Class 5
Example code in this lecture
GuessingGame
GradeGenerator
GenericsExamples
Lecture notes
admin
- quiz returned (was everyone able to see their feedback?)
- assignment 1 returned
- lab tomorrow
- first half, some experimentation
- second half, start the assignment
this
run GuessingGameWithProblem in
GuessingGame code
look at GuessingGameWithProblem in
GuessingGame code
- Is there anything that the user could do while playing the game to cause a problem?
- if the user enters something that is not a number!
- What do you think happens when the user enters something that is not a number?
- We get an Exception!
Exceptions
- What exceptions have you seen already?
- NullPointerException
- ArrayIndexOutOfBoundsException
- StringIndexOutOfBoundsException
- Exceptions may seem like errors (and they are), but they're also another way for a method to communicate to whoever calls it
- return allows it to return a value
- throwing an Exception tells whoever called the method that something went wrong
try-catch blocks
- If you want to program to stop when an Exception is thrown, you don't have to do anything (as you've noticed)
- If you want to try and handle a problem and NOT have the program stop, you can "catch" an Exception
- Syntax:
try{
// code that might throw an Exception
} catch (exception_class_name variable_name){
// code to run if an exception of type exception_class_name occurs in the try block above
}
- When the code is run, if no Exception occurs, then the catch block is skipped
- If an Exception of the type exception_class_name occurs in the try block of code, then the code jumps immediately down to catch block, executes the code in there and then continues on after the block
Can we use this to help us solve our problem with the guessing game?
Look at GuessingGame in
GuessingGame code
- We've surrounded the part of the code that handles the input and response with a try-catch block
- If the user enters a number, everything works as before
- If the user enters something that is not a number, then the in.nextInt() call will throw an Exception
- It will skip the if/else if/else block of code and go immediately to the catch block
- It will then print out that there was an issue
- The scanner class buffers the input and so it still has that string sitting there. We have to read the string and ignore it.
- The loop will then continue as normal
Reading from files
- There are many ways to read data from files (we'll see 2 today)
- One is to use the Scanner class
Given a String with a filename:
Scanner in = new Scanner(new File(filename));
- Same Scanner class/interface we were using before except now we created it to read from a file instead of from System.in (from the user)
Checked Exceptions
- Could anything go wrong when opening a file like this? Put another way, what Exceptions could occur?
- If you just try and open the scanner like this, Java will complain
- Some Exceptions are called "checked" Exceptions
- checked Exceptions MUST be handled
- we must wrap the statement that could throw that Exception in a try-catch block
If you try and do the above line for creating a Scanner from a file, you'll get a compilation error
"Unhandled Exception"
- Opening a file can generate a FileNotFoundException which is a checked exception, so we have to put it in a try-catch block
look at GradeGeneratorPrint in
GradeGenerator code
Writing to files
- Printing the grades list is nice, but in some situations it would be better to print it to a file
- As with reading from files, there are many ways to do it
- One easy way is with the PrintWriter class
PrintWriter out = new PrintWriter(new FileOutputStream(outfilename));
- PrintWriter has a similar interface to the System.out, in particular, it has a method called out.println()
- the difference is that it prints it out to the file
- When you're done writing to a file, *** don't forget to close it ***
- Do you think opening a file for writing throws any Exceptions?
- Yes! FileNotFoundException
run and look at GradeGeneratorFile in
GradeGenerator code
- looks almost the same, except we create a PrintWriter and use that instead of System.out
- Why do I only have one try-catch block?
- the catch statement will catch *any* Exception of that type in the try block
- What's different about the code in the catch statement?
- Before, there was only one file that could be the offending file being opened
- Now, it could be either the file being read from or the file being written to
Exceptions are classes!
- they have methods, etc.
- When an exception is thrown/generated, a new exception object is generated
- The two most common methods you might want to call is:
- e.getMessage()
- get (as a String) a detailed messaged about this exception
- e.printStackTrace()
- prints out the normal thing you see with the hierarchy of method calls that led to the exception being thrown
Look at GradeGeneratorFileBufferedReader
- BufferedReader is another class that allows us to read from files (well, really the FileReader class)
- It has less bells and whistles than the scanner class
- it doesn't support things like nextInt, nextFloat, etc.
- the most common method that you'll call is readLine(), which reads the next line of the file and returns it as a String
- when the file is out of data, this method returns null
- so the general form of a loop is something like:
read a line
while that line isn't null
do some stuff
read another line
IOException
- When you open a FileReader(i.e. BufferedReader) it can throw a FileNotFoundException
- When you read from a BufferedReader it can throw an IOException, which is a type Exception
- I've only caught the IOException. Why is Java letting me do this?
- IOException is a superclass of FileNotFoundException!
Exception hierarchy
- There are a lot of Exceptions!
- All Exceptions, inherit from the class Exception
- it's kind of like Object for Exceptions (though remember that Exceptions are classes and actually do inherit from Object)
- If you put:
catch(Exception e){
}
- you will catch *ALL* exceptions that are thrown!
- however, it's better style to specifically list the Exception you're trying to catch
Look at GradeGeneratorFileBufferedReader2
- sometimes it may make sense to open the BufferedReader or the PrintWriter somewhere else and then pass it as a parameter
type casting
- If we have a class B extends A, is the following legal?
A varA = new B(...);
- yes, we can always assign a subclass to a variable of the type of a parent class
- Could we then do the following?
B varB = varA;
- No! Even though in this case we know that there is a B in varA, the Java compiler cannot be sure in all cases
- However, sometimes we (as the programmer) know the contents. We can tell Java that we know the type and to cast (interpret) the value as that type.
- The way to do that is with parentheses and the type:
B varB = (B)varA
Object class
- I've said that all classes have a toString method and an equals method
- what are their default behaviors?
- toString: the class name@memory location
- equals: return true only if they are exactly the same object (i.e., equivalent to using ==)
- We can write out own to change the behavior for a particular class
- Where do you think these default methods come from?
- we inherit them!
- If we do not specify a parent (i.e., extends), then by default we extend a class called Object
- we either implicitly extend Object
- or, we extend something that somewhere along the parents extends Object (either implicitly or explicitly)
- What type of classes could we store in a variable of type Object? I.e.,
Object o = ?
- Anything!
the Java class hierarchy
- *everything* in Java is a subclass of some class (except for 1 class in Java)
- you can only inherit from one class
- if you don't inherit from a class, by default, you inherit from the class Object
- You can see the object hierarchy at:
http://docs.oracle.com/javase/7/docs/api/overview-tree.html
Generics
- Recall from our discussion of ArrayList that we can instantiate an ArrayList to hold any type of Object
- For example, we can have ArrayLists of many different types:
ArrayList<Integer> nums = new ArrayList<Integer>();
ArrayList<String> strings = new ArrayList<String>();
- The reason we can do this all called "generics"
- generics weren't always a part of Java
- Before generics, we had to make a choice between:
- Defining one class for every type we wanted to use it for, e.g. ArrayListInteger
- this allowed Java to ensure that the methods like get and set returned/took as parameters appropriate types
- the downside is we had to create one class for every type!
- Defining a single class that used Object
- get would return and Object and you would have to type cast it, e.g.:
ArrayList list = new ArrayList();
list.add("banana");
String val = (String)list.get(0)
- We only have to write one class, but we have to type case a lot and we lose the type checking that goes along with that
- If you look at the documentation for ArrayLists, you can see that they have a generic type argument, E:
https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html
- The "type variable" E, is used anywhere that a type would be expected
- We can write our own classes that use generics!
- Look at Container class in
GenericsExamples code
- We can specify one or my type variables in the class header inside < >
public class Container<V>{
}
- by convention, we use a single uppercase letter to indicate a type variable
- You can then use this variable anywhere in your program where a type would be used
- private V value;
- public Container(V value)
- public V getValue()
- public void setValue(V newValue)
- When you instantiate this class you should specify a type parameter
Container<Integer> c = new Container<Integer>();
int val = c.getValue();
or
Container<String> c = new Container<String>();
String val = c.getValue();
- For example, we could add the main:
Container<String> c1 = new Container<String>("banana");
Container<Integer> c2 = new Container<Integer>(10);
System.out.println(c1.getValue());
System.out.println(c2.getValue());
// c2.setValue("car"); // DOESN'T WORK!
- How can we return multiple objects/data types from a method in java?
- The bad way: public void Object[] method()
- The good way: implement a Pair class using generics
- implement a class called Pair that supports generics for 2 types
- if you need more than one type variable, you can introduce another one and comma separate
- What methods should the class contain?
- Constructor(s)?
- private instance variables?
- methods?
- look at the Pair class in the
GenericsExamples code
ArrayLists
- Java has a List interface for data structures that store data sequentially:
-
https://docs.oracle.com/javase/8/docs/api/java/util/List.html
- lots of methods, but key: get and set and particular indices
- The ArrayList class implements this interface
- Why do you think its called "ArrayList"?
- the underlying structure that it stores the data in is an array
- what was the main functionality that ArrayLists added over arrays?
- add/extend
- how do you think this is done?