1z0-808 Oracle Java SE 8 Programmer – Exception Handling
- Section Overview
In this section, we’re going to talk about how do we write code to handle situations. That where things might not go as according to plan. Give you an example. You’re running a program. It connects to the database, but the database is down. How do you prepare for that in your code? Well, Java gives us something called exception handling. And that’s the concept we’re going to learn in this section.
- Throwable
Whenever we write a program, we really hope that everything is going to go according to plan. But the reality is that things can disrupt the normal flow of a program. For example, imagine that I’ve got a method that needs to connect to a database. What if that database is down? How do I handle that? Well, Java has an infrastructure in place that allows us to create an object that sort of encapsulates went wrong at that time. And we call that a throwable. So it’s an event that disrupts the normal flow of a program. So when we call a method and something goes wrong, an object is created and the object is handed off to the Java runtime system.
The object that’s created is known as a throwable object. And it’s a class. It’s a class that’s defined in Java lang. So it’s part of the API. So this object is thrown by the runtime system. And what we do is write code to catch that object. Here’s an example. So we’ve created a string here and we want to get a character in the string. The problem is, when we say string character at 20, there is no index 20. We’ve gone too far. So this method creates a throwable. In this case, it’s called a string index out of bounds exception. And then the runtime system throws it. The throwable object has all the information we need about what went wrong.
It’s a snapshot of the entire execution stack at the time it was created. Plus, it has a message in there that gives us a human readable, I guess we hope a human readable bit of information of what went wrong. And if it’s possible that this particular issue was caused by another issue, there can be a link from one throwable to another throwable. Now, specifically, we don’t usually work with a throwable class. We usually work with something called an exception. In fact, there’s two different kinds of throwables. There’s error and exception. Now, an error is some catastrophic problem. We don’t typically recover from those kind of errors. Like, for example, an out of memory error.
There’s no way to really recover from that kind of a problem. But exceptions we can recover from. And so we can look and see what’s happened and see if there’s code we can then execute to handle the problem or at least log what happened. So if you open up the Java, you’ll see that there are a number of exceptions that are included with the Java API. And the general exception and errors are all part of the Java dot laying class. But there are a number of exceptions that are already prebuilt, which we certainly can handle. But we can also create our own custom exceptions as well.
- Catching Exceptions
So let’s take a look at how we’re able to catch an exception. Here’s the same code that we looked at before, but let’s look and see what happens in more detail when the problem occurs. So we are creating a string, it’s just called a char string. And we’re printing out a line here before the problem. And then we’re calling on the string class a method called char at. Password sing in an index and then we’re writing after problem. So what happens here? Well, as we saw, an exception is thrown once we try to access that character. Because the string is only 13 characters long, it’s an exception and it’s known as a string index out of bounds exception.
And at the moment we don’t have any code to catch this exception. So it fails at runtime. What we would see in the console is something like this. We’d first see before problem and then we’d see the stack trace along with a message about what went wrong. So in this case it says exception in thread main tells us the exception string index out of bounds exception and then tells us what went wrong. String index out of range 20 the lines underneath it, that’s the stack trace. Now, think about we spent a lot of time talking about the stack and the heap. What happens every time we call a method? Well, a frame is placed on the stack.
That’s what we’re seeing here. We’re seeing all the different frames, all the different methods that were called that are on the stack. In this case it started with main and when it got to line seven in main, it called char at and that’s where the exception was thrown. But that’s what happens if we don’t try to catch the exception. Here’s some code that we’ll add that will actually catch a string index out of bounds exception. The first thing that we do is we wrap the code that we think might throw the problem in a try block. So we write the keyword try. We put our curly braces to specify the block. And then after that block we put catch in parentheses.
We write the name of the exception, give it a variable so we can handle it if we’d like. And then we have another code block. That’s the code that will be run should that exception be thrown. So let’s walk through the code. So we create the string. We write before problem and we see that right down here. It says before problem. We try to get the character at 20 and that’s where the exception is thrown. So at that point it stops executing the code in the try block. Instead it goes to the catch and says do you handle the string index out of bounds exception? And the answer is yes. So then it prints out, hey, your string is not that big.
And then it continues on the code that we’ve written in the catch block can either say something to the user, it could write to the log, or can actually do something to handle the problem. In that example, in our catch block, we had an argument e and its type was string index out of bounds exception that specifies what type of problem the catch block will capture. You can actually have multiple catch blocks for any try block. So here’s another example. We’re catching a string index out of bounds exception. We’re also catching a null pointer exception. You can have as many of these as you need. So each catch block is a handler and it handles the type of exception that it specifies.
By the way, polymorphism is at work here. So what we’re saying is we’ll catch string index out of bounds exception and any subtype. Here we’re saying we’ll catch null pointer exception and any subtype. So you can catch any number of exceptions. And if you want to, you can even try to catch errors, although that’s not typical or recommended. Another thing you’ll often see is that the very last catch block will just be a generic exception. It would look like this. The very last one will just say catch exception and that’s considered sort of a general catch. All the rest of the problems, because in Java, when we make an exception, it’s going to inherit directly or indirectly from exception.
So with polymorphism at work, that means it’ll catch any of the exceptions that we didn’t catch above. But polymorphism can bring a problem. What if we had a very general exception? Like we catch exception and it’s the first thing that we list? Well, none of the other exceptions would then be caught, but that’s okay, the compiler is going to help us with that. If we happen to list the more general exceptions first, then the compiler will complain. It actually won’t let us compile. We’ll get this kind of an error. It’ll say this exception that you’re trying to catch has already been caught. When you see that, all it means is that you’ve got a more general exception before a more specific exception.
And as of Java seven, you can actually catch multiple exceptions in the same block. We use the single or operator between the different types and that just lets us write one block of code for a bunch of different exceptions. So here’s an example. Here we’ve got a catch and we’ve got our string index out of bounds exception or null pointer exception. Notice that you only have one variable for each type of an exception and we really haven’t seen yet how we’re going to use that variable, but that’s coming up. So this catch will catch both a string and x out of bounds exception or a null pointer exception and all the subtypes of both.
- Finally Block
So in the previous example, the Catch block is what allows our code to handle the problem and move on. Once again, if we didn’t have that catch, then the program would eventually stop executing and we’d see some kind of a message, an error message in the console or in a log. The one thing that the catch block doesn’t allow us to do, however, is finish anything that was inside of the Try block. Anything that was after the problem is just skipped and that might not be acceptable. We may have some code that we absolutely want to execute no matter what happens. So for example, let’s say that we had a connection to a database or a file, some kind of a stream.
After the exception is caught, we want to make sure that that connection is released. So that’s where a finally block comes into play. It’s part of the try catch system. So we’ve got try catch and then you list finally and so the way that this works is finally is going to be executed just in any type of situation, with the exception of maybe an error or doing a system exit. Let’s say that we go through the happy path and no exception is thrown. So all these lines in the Try block would be executed and then the finally would be executed. Let’s say a string index out of bounds exception is thrown, so it would execute all these lines.
Once it hits the string index out of bounds exception, it stops the execution of the triblock, goes to this catch, and then goes to this finally and continues on. Another possibility is that an exception would be thrown that we’re not even catching here. So in that scenario, let’s say it’s thrown here, so some kind of an exception is thrown, it stops executing the triblock, it looks in the catch to see if anything handles it. It doesn’t. So it does the Finally Block right here, and then it’s going to go up. It’s not going to continue on. At that point, it’s going to call the method that called this, it’s going to go up the stack and say, hey, does this frame have any code to be able to handle the problem? But basically the Finally Block is going to be executed.
In most situations, unless there’s an error, unless there’s a system exit, the Finally Block will be executed. Java Seven also gave us another addition to the exception handling syntax. It’s called try with resources. So prior to the syntax, any code that we would write to close a connection, to close a stream, would be put in the Finally Block. But the problem is oftentimes that code itself would also throw an exception. So we start to write crazy code like this, where here we are trying to do something with a connection, we catch an exception and finally we would try again to see if the connection is not equal to null and if it isn’t, if it’s still there, we can close it.
But notice that in our finally block that we’ve got another try catch. And a lot of us found this code to be quite maddening. So try with resources allows us to omit that finally clause. And what it will do is the system will automatically try to close the connection at the end of the method or before an exception is thrown from that method on our behalf. This is available to any object that implements the Java lang autoclosable interface. So this is tried with resources. We create the tribe lock and in parentheses we establish our variables that we’re going to want to close.
In this case, connection con equals driver manager get connection and that’s it. It will automatically close that connection as if it was in a finally block for us. So let’s put this all together. When we have a try statement, it’s going to either have zero or more catch blocks or zero and one finally block. So here are the possible combinations. We can have a try with as many catches as we need and a finally. We can have a try with as many catches as we need. And we can also have a try and a finally. You’ve can’t just have a try on its own. It’s got to be one of these three combinations.
- The Exception Object
At this point we’ve been catching exceptions but we haven’t been doing anything with the throwable object itself. And the throat object contains a lot of great information. We can either log it and let the developer see what went wrong. We could potentially recover programmatically with what went wrong. So each throwable object has a set of methods so we can see what actually occurred. And here are the methods. So we have get cause and that will return the cause of the throwable or null if it’s not known. We have get message which will just be that human readable message of what went wrong.
There’s the stack trace we’ve talked about the stack. When I call a method and that method calls another method and that method calls another method, each of these methods are placed on the stack. This includes all of those methods so that we can seewhat was the path that we took to get here. And finally there’s print stack trace which will just do what it says it will print the stack trace to the standard air stream. So here’s an example of logging the problem.
So we are catching the string index out of bounds exception and then we’re just printing out to our console or to our log depending on how we’ve configured our standard out. We’re saying there’s a problem in main and then we’re getting the message and that’s that first line here. Problem in main, string index out of range 20. That’s the e get message. And then when we do the e print stack trace it says what the exception was. So in this case it was Java laying string index out of bounds exception. It includes that message again and then we have the stack trace. What was the path that we took to get to this problem?
- Unchecked (Runtime) vs. Checked Exceptions
When we look at the hierarchy of all of the Java problems that can be thrown, we’ve got throwable at the very top and underneath throwable we have error and we have exception. And remember that errors are something that are really serious. We don’t try to recover from them. We don’t typically catch an error. And out of memory error is a common example. Hopefully not a common problem, but a common an example. Exceptions are problems that we might want to capture or we might have to capture. And that’s what ties us into this concept of checked and unchecked exceptions. So here’s the hierarchy.
If you look down here, we’ve got our throwable and then we’ve got error and exception which inherit from throwable. But exception can be broken down into two different types as well. We’ve got Java, Lang, Runtime and any exception that inherits from that. And then we’ve got basically everything else. And that’s how we differentiate between checked and unchecked exceptions. So anything that inherits from runtime is considered a runtime exception and we can try to catch it if we want, but we’re not required to. Everything else is considered a checked exception and those the compiler will force us to handle in some sort of way.
Any exception that inherits directly or indirectly from a Runtime exception is a runtime unchecked exception. We’ve talked about string index out of bounds exception, class cast exception, arithmetic exception, array index, out of bounds exception. There’s also null pointer exception. All of those inherit from runtime exceptions, so they’re considered unchecked. Most exceptions are not runtime exceptions but checked exceptions. And what that means is we must handle them. We have a couple of options of how we can handle it. We can use the Try catch block that we just talked about or we can rethrow the exception.
Typically you’re going to want to try to handle the exception with Try Catch, but there are situations where it makes a little more sense to rethrow the exception so that something else can handle it. Some examples of checked exceptions include SQL exception, file not found exception, and really most exceptions that you’ll create yourself. Let’s look at some code. So here I’ve got a main method and it’s calling an open Http connection. We’re creating in that method a new URL object. URL object is something that’s part of the Java net library. It represents a network connection like it sounds. And if we were to write this code and we were to compile it, we would get an error.
The error would say unreported exception, Java net malformed URL exception must be caught or declared to be thrown. And it shows us that the problem is with the URL constructor. So what they’re telling us is that we can’t do that. There’s a checked exception that this constructor can throw and so we have to handle it. So here’s how we can handle it. We add our Try Catch to the constructor we catch the Malformed URL exception, and then we do something with it. And at that point, now we can compile we’ve handled the error, or rather, we’ve handled the exception.
But there are times where it makes more sense to say, I don’t have enough information here to reasonably recover. I will throw this exception to whoever called me. So here’s an example of that. Imagine that our open Http connection is given a URL. And so when we say new URL, we don’t really know where we were trying to go. We don’t know if whoever called us has some kind of recovery plan in mind. If this URL doesn’t work, maybe they can give us another one. So rather than putting a try catch here, we can write on the method throws Malformed URL exception.
And now any code that calls our method will be forced to try and catch, or they can declare that they throw it themselves. So now the try catch is up here. In the main method, we’ve got the Malformed URL exception, and it could recover or do whatever it needs to do. But even the main method doesn’t have to handle the Malformed URL exception with a try catch. It too could say that it throws the Malformed URL exception, but that’s really not a good idea. This is known as passing the buck. And remember, main is the front door of our application. If we throw an exception here, our program just crashes. So this is not a good idea, even though it’s legal.
- Creating Exceptions
Java’s exception handling infrastructure allows you to create your own throwable subclasses if you’d like. You may have something that happens in your application where there’s a unique kind of problem and any code that calls into the area into the method that could potentially exhibit this problem. This might be a time where you want to say here, here’s an exception, this is what happened and allow all the a calling code to recover. And the way we do it is we just make sure that our exception class directly or indirectly extends throwable. Although it’s not as common for you to extend directly throwable. Instead, what we typically do is extend Java lang exception. If you do that, then it’s going to be a checked exception.
If you extend Java lang runtime exception then it will be an unchecked exception. By doing that we’re going to inherit a lot of the behavior we need. In fact, most of the exception objects that I’ve seen really don’t do anything. It’s really just the name of the exception that allows people to write code to catch it. And once they know what the type of the exception is, they just use the regular throwable methods to get more information about the problem. But it’s really the name that’s the power of the exception. It allows us to decide what we should do when a specific type of exception occurs. And of course we’re going to need to create a constructor. Remember that we don’t inherit constructors so we will define our own.
And let’s look at an example. So we’ve got a banking application and there are times where an overdraft could occur. So we’ve created here an overdraft exception. It extends exception. And notice that the only thing I put here is a new constructor. This is pretty common. You accept a string so what is the problem? And then you call the super constructor an exception and pass it that message. So here’s some code to show that. First of all, you define in your method that you throw this exception. So throws overdraft exception. And then if we get a scenario where there’s an overdraft, we say throw new overdraft exception passing in the message. So now the code that called withdraw can handle the overdraft exception and possibly notify the user that something went wrong.
- Exception Handling Lab
For the exceptions lab, you’re going to create a custom exception called holiday orders not allowed. Exception. You’re going to work with a try catch block. You’re going to be throwing exceptions. And the instructions for all of this are in the resources for this lecture. It’s called lab 17 exceptions PDF. The solution code is in the file as well. And if you have any questions, let me know.