概念
所谓异常,就是代码发生错误导致无法运行。
分类
异常主要分为两类,一类是Error,一般是硬件导致的问题。一类是Exception,是软件导致的问题
体系
Throwable
Error(错误)
Exception(异常)
CheckedException(检查时异常,一般是语法有问题,在编译代码时产生)
RuntimeExcetion(运行时异常,逻辑有问题,在运行过程中产生)
常见的异常
1.NullPointerException 空指针异常,一般是调用某个对象中的方法或属性,但这个对象是null,会导致空指针异常.
public class Test {
public static void main(String[] args) {
String str = null;
str.trim();
}
}
2.ArithmeticException算法异常,一般是我们的数学公式有问题,如10/0;
public class Test{
public static void main(String[] args){
System.out.println(10 / 0);
}
}
3.IndexOutOfBoundsException下标越界,在使用数组、集合等有下标的存储方式时,使用超出数组或集合最大下标的下标进行操作就会导致下标越界。
public class Test{
pulic static void main(String[] args){
int[] arr = {1,2};
//最大下标是1;
arr[2] = 0;
}
}
4.ClassCastException,类型转换异常,在父类对象转子类对象时,如果没有确认要转换的对象是不是子类对象就进行强制转换 ,很容易产生这种异常。
public class Test{
public static void main(String[] args){
Integer i = new Integer(10);
//子类对象转父类对象没有风险,可以自动转换。
Object o = i;
//父类对象转子类对象是有风险的,这个风险就是类型转换异常。‘
String str = (String) o;
}
}
异常的传递
在实际开发中,我们需要使用到大量的第三方工具,在使用过程中必然是经过层层调用的,如果在使用工具的过程中出现了错误,那么将会将错误产生的地方以及调用这处代码的地方一层层列出,直到最外层我们自己实际调用的地方。
public class Test {
public static void main(String[] args) {
a();
}
private static void a() {
b();
}
static void b(){
c();
}
static void c(){
System.out.println(10 /0);
}
}
如上述代码,我们在经过多重调用方法之后,产生了ArithmeticException异常,在报错显示中会显示多个函数的位置。最上面一层是异常发生的代码,最下面一行是我们最外层调用的地方。一般就是由于我们在实际编码时不了解源码的使用说明,在最外层调用时传入了错误的参数或者错误的值导致的。
异常产生的后果
异常产生的后果其实很简单,就是程序崩溃,程序停止运行。
异常的处理
处理异常的方式主要有两种,一种是声明\抛出异常;
1.throws throw
throws为声明异常,定义位置在方法上,其主要语法是
/*
访问权限修饰符 修饰符 返回值类型 变量名(形参列表) throws 异常类型1,异常类型2{
方法体
}
*/
public static void main(String[] args) throws ArithmeticException{
div();
}
public static void div() throws ArithmeticException{
System.out.println(10 / 0);
}
这种处理异常的方式就是只抛出不处理,就类似于我们去医院看病,医生只是帮我们做了检查,告诉我们身体出现了什么问题,但是这个病该怎么治,医生并没有说,而是等待我们找下一个医生去解决,如果我们找到下一个医生还是使用throws抛出,就相当于这个问题还没有解决,仍然存在,让我们再去等待下一个医生。
我们在定义方法div的时候很清楚的知道10/0是会产生异常的,但是我们不处理,我们把这个问题抛出,等待下一个调用我们这个方法的人去处理。如到了main函数还不处理,只是抛出的话,就会将异常传递给JVM,而JVM处理异常就只有一种方法——程序崩溃,结束运行。所以我们尽量不要把异常抛给JVM,在实际调用时尽量处理异常。
throw是抛出异常,在语法上和throws有一点小区别,throw是抛出异常对象,如:
public class Test{
public static void main(String[] args) throws ArithmeticException{
div(0);
}
public static void div(int num) throws ArithmeticException{
if (num == 0) throw new ArithmeticException();
System.out.println(10 / num);
}
}
当我们在调用这个div方法时,如果传入了0,就会抛出这个异常
如果我们抛出异常只是用了throw,并没有用throws。如
public class Test{
public static void main(String[] args){
div(0);
}
public static void div(int num){
if (num == 0) throw new ArithmeticException();
System.out.println(10 / num);
}
}
这样的处理方式就相当于我们去医院看病,医生知道了我们得的什么病,但是医生不说。。。
我们正常调用第三方工具时并不会去查看源码,所以如果出现这种问题,开发工具没有提示,很容易就会导致程序崩溃。
try catch
之前的throw 和 throws只是将问题抛出,并没有解决问题,如果产生了异常,程序还是会崩溃,try catch 就是解决问题的,语法:
/*
try{
可能会产生异常的代码
}catch(异常类型1 变量名){
当try中的代码产生异常1时,执行此处代码
}catch(异常类型2 变量名){
当try中的代码产生异常2时,执行此处代码
}finally{
此处代码无论try中的代码会不会产生异常,都会执行此处。
}
*/
public class Test{
public static void main(String[] args){
try{
div(0);
System.out.println("div之后,try内部的代码");
}catch(ArithmeticException err){
System.out.println("不能传入0");
}
System.out.println("try catch 之外的代码");
}
public static void div(int num) throws ArithmeticException{
if (num == 0) throw new ArithmeticException();
System.out.println(10 / num);
}
}
当try中的代码产生了我们预期的异常之后,程序并不会崩溃,而是停止执行异常代码之后,在try中的代码,去执行catch中对应错误类型的代码,之后执行try catch后面的代码。这样就解决了我们产生异常后程序崩溃的问题。
注意:
- catch可以有多个
- 处在上方的catch期望的异常不能是下面catch期望的异常的父类,上面的异常类型必须小于或等于下面的异常。
自定义异常
jvm给我们提供的异常是有限的,而且有时我们根据制定的规则去规定属于我们当前项目特有的异常,这种情况下就需要我们自定义异常:
步骤:
- 自定义一个类
- 使这个类继承于Exception类。
- 创建无参构造和有参构造(String),有参构造中输入的内容就是产生异常之后的提示内容。
public class Test {
public static void main(String[] args) {
try {
div(0);
} catch (ZeroException err) {
System.out.println(err);
}
System.out.println("try catch 之外的代码");
}
public static void div(int num) throws ZeroException {
if (num == 0) throw new ZeroException("除数不能为0");
System.out.println(10 / num);
}
}
class ZeroException extends Exception {
public ZeroException() {
super();
}
public ZeroException(String str) {
super(str);
}
}
如果没有处理异常,而是选择了抛出,最终的效果就是:
public class Test {
public static void main(String[] args) throws ZeroException {
div(0);
}
public static void div(int num) throws ZeroException {
if (num == 0) throw new ZeroException("除数不能为0");
System.out.println(10 / num);
}
}
class ZeroException extends Exception {
public ZeroException() {
super();
}
public ZeroException(String str) {
super(str);
}
}