Exceptions and Errors
> Click or hit Control-Enter to run the code above
Review: So What’s a Web API?
What’s An API?
In computer programming, an application programming interface (API) is a set of subroutine definitions, protocols, and tools for building application software.
In English, an API is a set of functions that perform a set of related and useful tasks.
Example API
Let’s say we wanted to find out the weather at a particular location:
// Get the current weather a particular location
static WeatherInfo getAtLocation(WeatherLocation location)
// Get the current weather a particular location and a particular time
static WeatherInfo getAtLocation(WeatherLocation location, Date date)
// Get a list of possible WeatherInfo objects for a given location string
static WeatherLocation[] searchLocations(String query)
Web APIs
A web API is just an API that you access over the web. Consider that:
-
We can send data to a web server using
POST
and also using URL parameters in aGET
request -
The web server can run code in response
-
And return a response, which does not have to be an HTML document
-
And in many cases custom internet protocols are blocked by firewalls, making it attractive to run APIs over HTTP
Web APIs: Sending Arguments
// Get the current weather a particular location
static WeatherInfo getAtLocation(WeatherLocation location)
To send the location
argument to the getAtLocation
function over the web we
have several options:
-
Stick it the URL:
/api/getAtLocation/(location)/
, which can be mapped to a function call -
Add it as a query parameter:
/api/getAtLocation?location=(location)
-
Use a
POST
request and put it in the body, possibly as JSON:
POST /api/getAtLocation/
{
"location": (location)
}
Web APIs: Returning Results
// Get the current weather a particular location
static WeatherInfo getAtLocation(WeatherLocation location)
In many cases web APIs return results using JSON (JavaScript Object Notation):
{
"consolidated_weather": [
{
"id": 6511056423747584,
"weather_state_name": "Thunder",
"weather_state_abbr": "t",
"wind_direction_compass": "E",
"created": "2018-04-09T02:37:19.655990Z",
"applicable_date": "2018-04-08",
"min_temp": -2.6099999999999999,
"max_temp": 2.2149999999999999,
"the_temp": 2.4950000000000001,
"wind_speed": 2.8707529204565336,
...
What’s Awesome…
Is that there are a gazillion public APIs out there. So go have fun!
Questions about the Internet, Web, and Web APIs?
Exceptions
Because things go wrong…
Why Exceptions?
What do you do when you can’t go on?
class StringStorage {
/**
* Create a new object to store strings.
*
* @param storageSize the size of the StringStorage,
* must be positive
*/
public StringStorage(final int storageSize) {
if (storageSize <= 0) {
// what now?
}
}
}
Why Exceptions?
What do you do when you can’t go on?
/**
* Read an integer from a passed string
* and then do something with it.
*/
static int readInteger(final String intAsString) {
int value = Integer.parseInt(intAsString);
// But what if intAsString was "foo"?
}
try-catch
Java’s exception handling control structure is called a try-catch
block:
try {
// Do something that could cause an exception
} catch (Exception e) {
// Handle all exceptions that inherit from Exception
}
// Go on if things proceeded normally
catch
Matching
A catch
block will match any exceptions that inherit from the one provided.
And they are tried in order.
try-catch
with Multiple catch
Sometimes you want to handle errors differently depending on what caused them:
try {
// Do something that could cause an exception
} catch (NullPointerException e) {
// Handle null pointer exceptions
} catch (ArrayIndexOutOfBoundsException e) {
// Handle array out of bounds exceptions
}
// Go on if things proceeded normally
try-catch
with Multiple catch
You can also merge multiple exception types together like this:
try {
// Do something that could cause an exception
} catch (NullPointerException|IllegalArgumentException e) {
// Handle null pointer and illegal argument exceptions
}
// Go on if things proceeded normally
try-catch
in Python
Many other languages have similar error handling constructs. In Python:
try:
// do something
except ValueError:
// handle
except Another Error:
// handle
else:
// Run if no error is thrown. No analog in Java
finally:
// Always run
try-catch
in JavaScript
Many other languages have similar error handling constructs. In JavaScript:
try {
// do something
} catch (err) {
// handle the err
} finally {
// Always run
}
> Click or hit Control-Enter to run the code above
Exceptional Control Flow
When an error is thrown control flow immediately jumps to an
enclosing catch
statement, if one exists.
The catch
may be in the caller or multiple levels up.
static void foo1() {
Object it = null;
int hash = it.hashCode();
}
static void foo2() {
foo1();
}
static void foo3() {
foo2();
}
static void foo4() {
try {
foo3();
} catch (Exception e) {
}
}
> Click or hit Control-Enter to run the code above
Types of Exceptions
Java exceptions are broken into three distinct categories:
-
Checked exceptions: these are for places where you know something might go wrong and it’s out of your control
-
Unchecked exceptions (or runtime errors): these are unanticipated errors usually caused by something dumb that you (the programmer) did wrong
-
Errors: these are reserved for serious system problems that are probably not recoverable
Checked Exceptions: Examples
Checked exceptions are for cases where an failure external to your program can cause an exception to occur
-
FileNotFoundException
: your program tried to open a file that you expected to exist but it did not -
URISyntaxException
: your program tried to parse a universal resource identifier (URI) but it was invalid
Checked Exceptions: Handling
If you use a function that may generate a checked exception, you must either
wrap it in a try-catch
block or declare that you may throw it.
static URI createURI(final String input) {
// Example where we handle URISyntaxExceptions
try {
return new URI(input);
} catch (URISyntaxException e) {
System.out.println(input + " is not a valid URI");
}
}
// Example where we throw URISyntaxExceptions
static URI createURI(final String input) throws URISyntaxException {
return new URI(input);
}
> Click or hit Control-Enter to run the code above
Unchecked Exceptions
Unchecked examples are usually the result of programmer error.
(They are fundamentally unanticipated, since if you had anticipated them you would have fixed them.)
You’ve probably made many of these mistakes by now…
-
ArrayIndexOutOfBoundsException
: you walked off the end of an array -
NullPointerException
: you dereferenced anull
reference -
ClassCastException
: you tried to cast something to a subclass of which it is not an instance -
IllegalArgumentException
: you passed incorrect arguments to a function or constructor
> Click or hit Control-Enter to run the code above
Unchecked Exceptions: Handling
Unlike checked exceptions, you do not need to declare or handle unchecked exceptions.
However, you can handle them:
try {
String s = callMyPartnersDodgyCode();
if (s.length() == 0) {
return;
}
} catch (NullPointerException e) {
return;
}
Errors: Examples
Java errors indicate serious conditions that are usually not recoverable:
-
OutOfMemoryError
: Java ran out of memory and is going to crash -
StackOverflowError
: You recursed too deeply and Java is going to crash -
Note that sometimes these are still your fault: you used too much memory or forgot your base case
Exception Handling Strategies
Here are reasonable strategies for handling each kind of exception:
-
Errors: don’t try to handle these, just go bye-bye
-
Unchecked exceptions: try to avoid these by improving your code
-
Checked exceptions: try to handle these and have your program continue running, or exit gracefully…
-
but don’t go on unless you can.
Working with Exceptions
Java exceptions are just another kind of Java object—and they have some useful features, particularly when debugging:
-
toString
: like every other JavaObject
, exceptions can be printed -
getMessage
: retrieves just the message associated with this exception -
printStackTrace
: print a stack trace for the error showing what caused it and what other functions were involved
> Click or hit Control-Enter to run the code above
Rethrowing Exceptions
Sometimes you may want to just record what happened but not know what to do with an error.
In that case you may want to rethrow it out of the catch block:
static URI createURI(final String input) {
// Example where we handle URISyntaxExceptions
try {
return new URI(input);
} catch (URISyntaxException e) {
// Log that something went wrong
Log.e(TAG, input + " is not a valid URI");
// Rethrow the exception
throw(e);
}
}
Throwing Your Own Exceptions
So how do we handle a case like this?
class StringStorage {
/**
* Create a new object to store strings.
*
* @param storageSize the size of the StringStorage,
* must be positive
*/
public StringStorage(final int storageSize) {
if (storageSize <= 0) {
// what now?
}
}
}
> Click or hit Control-Enter to run Example.main above
throw
To throw an exception in Java we use the throw
keyword:
Exception e = new Exception("you did something awful");
throw(e);
throw
Well
If you need to throw an exception:
-
Look for an existing
Exception
class that’s a good fit -
Or, create your own:
public class MyException extends Exception {
}
throw(new MyException("bad bad"));
finally
Java’s try-catch
also supports a finally
block. It is always executed after
either the try
or the catch
completes:
try {
System.out.println("start");
couldError();
System.out.println("done");
} catch (Exception e) {
System.out.println("catch");
} finally {
System.out.println("finally");
}
> Click or hit Control-Enter to run the code above
Intelligent try
Usage
You can make intelligent use of try-catch
blocks to avoid repetitive sanity
checking:
JsonParser parser = new JsonParser();
JsonObject info = parser.parse(json).getAsJsonObject();
if (!info.has("metadata")) {
return 0;
}
JsonObject metadata = info.getAsJsonObject("metadata");
if (!metadata.has("width")) {
return 0;
}
JsonElement width = metadata.getAsJsonElement("width");
return width.getAsInt();
Intelligent try
Usage
You can make intelligent use of try-catch
blocks to avoid repetitive sanity
checking:
(This is particularly nice when you can chain calls together.)
try {
JsonParser parser = new JsonParser();
return parser.parse(json)
.getAsJsonObject()
.getAsJsonObject("metadata")
.get("width")
.getAsInt();
} catch (Exception e) {
return 0;
}
Questions About Exceptions?
Announcements
-
The final project description has been posted. Please get started!
-
I have office hours today from 1–3PM. Please come by to say hi!