飞道的博客

Java底子差的进来吧,关于异常知识点都在这里了

384人阅读  评论(0)

异常

1.1 异常概述

1.1.1 什么是异常

程序运行过程中出现的问题在Java中被称为异常,异常本身也是一个Java类,封装着异常信息;我们可以通过异常信息来快速定位问题所在;我们也可以针对性的定制异常,如用户找不到异常、密码错误异常、页面找不到异常、支付失败异常、文件找不到异常等等…
当程序出现异常时,我们可以提取异常信息,然后进行封装优化等操作,提示用户;

注意:语法错误并不是异常,语法错了编译都不能通过(但Java有提供编译时异常),不会生成字节码文件,根本不能运行;

默认情况下,出现异常时JVM默认的处理方式是中断程序执行,因此我们需要控制异常,当出现异常后进行相应修改,提供其他方案等操作,不要让程序中断执行;
我们之前有见到过很多的异常:

  • 空指针异常:java.lang.NullPointerException
String str=null;
str.toString();
  • 数字下标越界异常:java.lang.ArrayIndexOutOfBoundsException
int[] arr = {
   1, 3, 4};
System.out.println(arr[3]);
  • 类型转换异常:java.lang.ClassCastException
class A {
   
}
class B extends A {
   
}
class C extends A {
   
}
public static void main(String[] args) {
   
    A a = new B();
    C c = (C) a;
}
  • 算数异常:java.lang.ArithmeticException
int i=1/0;
  • 日期格式化异常:java.text.ParseException
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date parse = sdf.parse("2000a10-24");

1.1.2 异常体系

Java程序运行过程中所发生的异常事件可分为两类:

  • Error:表示严重错误,一般是JVM系统内部错误、资源耗尽等严重情况,无法通过代码来处理;
  • Exception:表示异常,一般是由于编程不当导致的问题,可以通过Java代码来处理,使得程序依旧正常运行;

Tips:我们平常说的异常指的就是Exception;因为Exception可以通过代码来控制,而Error一般是系统内部问题,代码处理不了;

1.1.3 异常分类

异常的分类是根据在编译器检查异常还是在运行时检查异常;

  • 编译时期异常:在编译时期就会检查该异常,如果没有处理异常,则编译失败;
  • 运行时期异常:在运行时才出发异常,编译时不检测异常;

Tips:在Java中如果一个类直接继承与Exception,那么这个异常将是编译时异常;如果继承与RuntimeException,那么这个类是运行时异常。即使RuntimeException也继承与Exception;

  • 编译时异常举例:
public class Demo {
   
    public static void main(String[] args) {
   
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = sdf.parse("2000-10-24");
    }
}

  • 运行时异常:
public class Demo {
   
    public static void main(String[] args) {
   
        int i = 1 / 0;
    }
}


1.2 异常的处理

Java程序的执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给Java运行时系统(JVM),这个过程称为抛出(throw)异常。
如果一个方法内抛出异常,该异常会被抛到调用方法中。如果异常没有在调用方法中处理,它继续被抛给这个调用方法的调用者。这个过程将一直继续下去,直到异常被处理。这一过程称为捕获(catch)异常。如果一个异常回到main()方法,并且main()也不处理,则程序运行终止。
流程如下:

1.2.1 异常的捕获

异常的捕获和处理需要采用 try 和 catch 来处理,具体格式如下:

  • 1)try...catch(){}
try {
   
	// 可能会出现异常的代码
} catch (Exception1 e) {
   
	// 处理异常1
} catch (Exception2 e) {
   
	// 处理异常2
} catch (ExceptionN e) {
   
	// 处理异常N
}

Tips:后处理的异常必须是前面处理异常的父类异常;

  • 2)try...catch(){}...finally{}
try {
   
	// 可能会出现异常的代码
} catch (Exception1 e) {
   
	// 处理异常1
} catch (Exception2 e) {
   
	// 处理异常2
} catch (ExceptionN e) {
   
	// 处理异常N
} finally {
   
	// 不管是否出现异常都会执行的代码
}
  • 3)try...finally{}
try {
   
	// 可能会出现异常的代码
}  finally {
   
	// 不管是否出现异常都会执行的代码
}

示例代码:

package com.dfbz.demo01;
public class Demo01 {
   
    public static void main(String[] args) {
   
        method();
        System.out.println("程序终止我就不能执行了~");
    }
    public static void method() {
   
        try {
   
            String str = null;
            System.out.println(str.toString());
        } catch (Exception e) {
   
            System.out.println("执行代码出现异常了!");
        } finally {
   
            System.out.println("释放一些资源...");
        }
    }
}

 

运行结果:

tips:try…catch语句是可以单独使用的;即:不要finally代码块;

需要注意的是:如果finally有return语句,则永远返回finally中的结果。我们在开发过程中应该避免该情况;

  • 示例代码:
package com.dfbz.demo02;
public class Demo02 {
   
    public static void main(String[] args) {
   
        int result = method();
        System.out.println("method方法的返回值: " + result);
    }
    public static int method() {
   
        try {
   
            int i = 10;
            return 1;
        } catch (Exception e) {
   
            e.printStackTrace();
            return 2;
        } finally {
   
            return 3;           // 不管是否出现异常都是返回3
        }
    }
}

 

1.2.2 异常的常用方法

Throwable类中具备如下几个常用异常信息提示方法:

  • public void printStackTrace():获取异常的追踪信息;
    包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。
  • public String getMessage():异常的错误信息;

异常触发被抓捕时,异常的错误信息都被封装到了catch代码块中的Exception类中了,我可以通过该对象获取异常错误信息;
示例代码:

package com.dfbz.demo01;
public class Demo02 {
   
    public static void main(String[] args) {
   
        method();
        System.out.println("我继续执行~");
    }
    public static void method() {
   
        try {
   
            int i=1/0;
        } catch (Exception e) {
   
            System.out.println("异常的错误信息: " + e.getMessage());
            // 打印异常的追踪信息
            e.printStackTrace();
        }
    }
}

 

运行结果如下:

异常的追踪信息可以帮助我们追踪异常的调用链路,一步一步找出异常所涉及到的方法,在实际开发非常常用;

1.2.3 异常的抛出

我们已经学习过出现异常该怎么抓捕了,有时候异常就当做提示信息一样,在调用者调用某个方法出现异常后及时针对性的进行处理,目前为止异常都是由JVM自行抛出,当然我们可以选择性的自己手动抛出某个异常;
Java提供了一个throw关键字,它用来抛出一个指定的异常对象;抛给上一级;

Tips:自己抛出的异常和JVM抛出的异常是一样的效果,都要进行处理,如果是自身抛出的异常一直未处理,最终抛给JVM时程序一样会终止执行;

语法格式:

throw new 异常类名(参数);

示例:

throw new NullPointerException("调用方法的对象是空的!");
throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");

示例代码:

package com.dfbz.demo01;
public class Demo03 {
   
    public static void main(String[] args) {
   
        method(null);
        System.out.println("我还会执行吗?");
    }
    public static void method(Object object) {
   
        if (object == null) {
   
            // 手动抛出异常(抛出异常后,后面的代码将不会被执行)
            throw new NullPointerException("这个对象是空的!不能调用方法!");
        }
        System.out.println(object.toString());
    }
}

运行结果:

手动抛出的异常和JVM抛出的异常是一个效果,也需要我来处理抛出的异常;
修改代码:

package com.dfbz.demo01;
public class Demo03 {
   
    public static void main(String[] args) {
   
        try {
   
            method(null);
        } catch (Exception e) {
   
            System.out.println("调用method方法出现异常了");
        }
        System.out.println("我还会执行吗?");
    }
    public static void method(Object object) {
   
        if (object == null) {
   
            // 手动抛出异常(抛出异常后,后面的代码将不会被执行)
            throw new NullPointerException("这个对象是空的!不能调用方法!");
        }
        System.out.println("如果出现了异常我是不会执行了,你能执行到这里说明没有异常");
        System.out.println(object.toString());
    }
}

 

运行结果:

1.2.4 声明异常

1)运行时异常

在定义方法时,可以在方法上声明异常,用于提示调用者;
Java提供throws关键字来声明异常;关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常);
语法格式:

... 方法名(参数) throws 异常类名1,异常类名2{
      }

代码示例:

package com.dfbz.demo01;
import java.text.ParseException;
public class Demo04 {
   
    public static void main(String[] args) {
   
        // 可以处理,也可以不处理
        method("你好~");
        // 编译时异常必须处理
        try {
   
            method2("hello~");
        } catch (ParseException e) {
   
            System.out.println("出现异常啦!");
        }
    }
    // 调用此方法可能会出现空指针异常,提示调用者处理异常
    public static void method(Object obj) throws NullPointerException {
   
        System.out.println(obj.toString());
    }
    // 抛出的不是运行时异常,调用者调用该方法时必须处理
    public static void method2(Object obj) throws ParseException {
   
        System.out.println(obj.toString());
    }
    // 也可以同时抛出多个异常
    public static void method3(Object obj) throws ClassCastException,ArithmeticException {
   
        System.out.println(obj.toString());
    }
}

 

2)编译时异常

在声明和抛出编译时异常时需要注意如下几点:

  • 1)如果是抛出(throw)编译是异常,那么必须要处理,可以选择在方法上声明,或者try…catch处理
  • 2)如果调用的方法上声明(throws)了编译时异常,那么在调用方法时就一定要处理这个异常,可以选择继续网上抛,也可以选择try…catch处理

  • 示例代码:
package com.dfbz.demo04;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo02 {
   
    public static void main(String[] args) throws Exception{
   
        // 如果调用的方法上声明了编译时异常,那么在调用方法时就一定要处理这个异常,可以选择继续往上抛,也可以选择try..catch处理
        test(500);
    }
    // 如果方法声明了编译时异常,那么在调用方法时就一定要处理这个异常
    public static void test(Integer num) throws MyException{
   
        if (num == 100) {
   
            // 如果是抛出编译是异常,那么必须要处理,可以选择在方法上声明,或者try...catch处理
            throw new MyException();
            
            /*try {
                throw new MyException();
            } catch (MyException e) {
                e.printStackTrace();
            }*/
        }
    }
}
// 直接继承与Exception,那么这个异常是一个编译时异常
class MyException extends Exception {
   
}

 

1.3 自定义异常

我们说了Java中不同的异常类,分别表示着某一种具体的异常情况,那么在开发中总是有些异常情况是Java中没有定义好的,此时我们根据自己业务的异常情况来定义异常类。
我们前面提到过异常分类编译时异常运行时异常

  • 1)继承于java.lang.Exception的类为编译时异常,编译时必须处理;
  • 2)继承于java.lang.RuntimeException的类为运行时异常,编译时可不处理;
  • 自定义用户名不存在异常:
package com.dfbz.demo04;
public class UsernameNotFoundException extends RuntimeException {
   
    /**
     * 空参构造
     */
    public UsernameNotFoundException() {
   
    }
    /**
     * @param message 表示异常提示
     */
    public UsernameNotFoundException(String message) {
   
        // 调用父类的构造方法
        super(message);
    }
}
  • 测试类:
package com.dfbz.demo04;
public class Demo01 {
   
    // 定义内置账户
    public static String[] users = {
   "xiaohui", "xiaolan", "xiaoliu"};
    public static void main(String[] args) {
   
        findByUsername("abc");
    }
    public static void findByUsername(String username) throws UsernameNotFoundException {
   
        for (String user : users) {
   
            if (username.equals(user)) {
   
                System.out.println("找到了: " + user);
                return;
            }
        }
        // 用户名没找到
        throw new UsernameNotFoundException("没有用户: " + username);
    }
}

 

运行结果:

1.4 方法的重写与异常

  • 1)子类在重写方法时,父类方法没有声明编译时异常,则子类方法也不能声明编译时异常

需要注意的是:运行时异常没有这个规定;也就是子类在重写父类方法时,不管父类方法是否有声明异常,子类方法都可以声明异常;

package com.dfbz.demo05;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo01 {
   
    public static void main(String[] args) throws Exception {
   
    }
}
// 定义一个编译时异常
class MyException extends Exception {
   
}
class Fu {
   
    public void method() {
   
    }
    public void method2() {
   
    }
}
class Zi extends Fu {
   
    // 语法通过,运行时异常随意
    public void method() throws NullPointerException {
   
    }
    // 语法报错,父类方法没有声明编译时异常,那么子类重写方法时也不能声明编译时异常
    public void method2() throws MyException {
   
    }
}

 
  • 2)同样是在编译时异常中,在子类重写父类方法时,子类不可以声明比父类方法大的编译时异常
package com.dfbz.demo06;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo01 {
   
    public static void main(String[] args) throws Exception {
   
    }
}
// 定义一个编译时异常
class MyException extends Exception {
   
}
class Fu {
   
    public void method() throws NullPointerException{
   
    }
    public void method2()throws MyException{
   
    }
}
class Zi extends Fu {
   
    
    // 运行时异常没有问题
    public void method() throws RuntimeException {
   
    }
    // 语法报错,如果是编译时异常,子类在重写父类方法时,不可以抛出比父类大的编译时异常
    public void method2() throws Exception {
   
    }
}

 

转载:https://blog.csdn.net/Bb15070047748/article/details/129244552
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场