Want this course?
Exceptions and Errors
Course: JVM Fundamentals for Clojure
In this lesson, I go through throwing, catching, and extracting information from exceptions and errors.
So the JBM has a system for throwing things, we call throwing things it's errors and exceptions. There's two main types, errors and exceptions. Exceptions are for stuff like, If I wanna open a file, I give it a filename, and the file isn't there. That's an exception. Or I pass in a string, it has the wrong format or something like that. That's an exception. It's considered a programming error and in theory it's recoverable. You try to file it's not there, you can just can an exception. These are exception and there's a class called Java lang exception.
Now on the other side, there's a thing called error. This is stuff like a stack overflow or an out of memory error when you're using too much memory and you're off your heap, there's no more room, you get an error. So the distinction between these is supposed to be sort of like recoverable, not recoverable.
Something your program should be dealing with versus something that's just like, your program is just wrong. But I find that this distinction is not so helpful because, as you can imagine there are things that maybe are recoverable that the people who wrote the JVM weren't thinking about. Like there's some design problems.
There's actually a superclass, and we'll get back to that. There's actually a superclass of these two called throwable. So in clojure you know there's a form, special form called throw. And you can give it an exception or an error, so I can do exception set to exception and give it a oops, okay I'ma run that.
Go look at the ripple, and we see this exception. Ooh uh it's all right, oh that's fine. And you see it through the exception. And we got put onto the ripple, print it out, because nothing caught it. You probably also know, that you can do a try and a catch, give the name of the exception, give the class of the exception and give it a variable. And now we can do something like that and we'll go see here, if we print to the exception, and it's gonna print, this is a stack trace.
It's a nice printed representation of that. Now all throwables actually have a .getMessage. No, oh sorry, getmessage e. And let's scroll down. We can see the message here. All right that's 'cause I missed, I didn't put a bis on the target, so that's why I compiled an exception. But then I ran it again and I got this message being printed out, it's kind of bothering me now that it doesn't an s, okay, there we go.
So now I'm printing out the message. And then there's also this other thing, getStacktrace, There. Oops. Not what I wanted to do. So we have the stack trace, and it's obviously an object. It's some kind of a ray.
So let's go turn it into a vec. And now we see all the elements of the stack trace there. And we're back there. And these are gonna be the line numbers, and the file names, stuff like that. Okay so stack traces are really nice 'cause they show where, who's calling who and where they're happened. Okay so very often exception is not what I wanna catch. This is a trick, so I, most of the time I catch throwables.
Some people are gonna think that's terrible. But I wanna catch throwable. I don't want this to ever fail. This is something like if I'm running in a loop and it's a thread that has a loop. I don't want that thread to ever fail. It might catch the exception and print it out so I know that something is going wrong, but I want it to keep trying.
So, oops, that wasn't where I wanted to do. And let me clear this out. Okay, so we're gonna print t, not vec t. Okay, there. So this is the throwable, it looks the same. It's still an exception, but since this is a superclass of this, we can put it in here. That's the idea, that this is capturing all throwables. But this is a way to capture throwable and errors, sorry exception and errors.
What's something that throws an error not an exception? Well if I do assert equals one two, that's obviously not true, so if I assert that I'll get an exception print it. Assert failed one equals two. Notice the type is java lang assertion error, subtype of error. And that's one of the reasons why I like to use throwable. Because I can't think all the time of all the possible errors that I might wanna use. And sometimes we'll write code that's, okay I'll do fibonacci of n, and the first thing we write is assert that n is greater than or equal to zero, okay. And if we do that, oops. Fib of negative one. We get, oh sorry, I'm in the wrong package. All right. All right, assertion error, assert failed.
To me this is not an unrecoverable error. This is more like an exception is supposed to be. And so I feel like this is something that we need to think about, is that we're using assertions, there gonna do assertion errors and those are supposed to be nonrecoverable. So I tend to just catch all throwables.
You don't have to, you can have multiple catches so that you could do something different like, well I wanna catch exceptions here. And do something. Or like ignore them, and I wanna catch error. I wanna catch assertion error. And I'll print it and then I'll just ignore everything else. Ignore meaning throw it up to the next level, that's fine. You gotta do what you gotta do. And I don't know what you have to do, 'cause I'm not writing your code. So the other thing is, in clojure there's a thing called ex-info, which is a handy way to make an exception.
Instead of making a new type and everything, we just have a thing that has a message. Hi, I am an exception. And it has some data, so you can put anything you want in there, like you can put your name. You can put some other information like cause I was just testing this out. You can put whatever you want, it's just in a map. And so we see whatever returns, and I'll do it with this.
Okay so this is what it returns, oh it didn't comment the whole thing, well that's weird. Anyway it returns an error, so you can throw it. All right, returns and exceptioninfo, which is, I said error, it's hard to use language properly when it has to be so precise. This is a clojure lang exception info, it is an exception. You know it's a sub-class. And, ohthere, it didn't throw it. There, it threw exception info, Hi I'm an exception. And you don't see it here in the ripple, this is the cyber ripple, but if I went to, oops. Cyber error, you would see that data that we passed it. And you see the whole stack trace in a nice clickable format.
Those are exceptions. In clojure we tend not to make new exceptions, meaning new types of exceptions. We just use something that exists already. But you can, and we'll probably see that in the gen class, the gen class lesson.