第六章 异常
6.1 什么是异常
| public class Demo { |
| public static void main(String[] args) { |
| int i = 10; |
| int n = 0; |
| |
| int res = i/n; |
| System.out.println(res); |
| } |
| } |
- 错误的原因就是因为被0除
- 这种信息被java的运行环境报出来了,这就是java的异常体系
- 注意:java的异常都是"类"
6.2 异常的分类
6.2.1 异常分类图
6.2.2 异常分类
- Error错误:如果程序出现Error,那么将无法恢复,只能重新启动应用程序,例如:OutOfMemeoryError
- 一般性异常(受控异常;编译期异常):这种异常出现时,必须显示的处理,因为,不处理程序无法运行
- 运行期异常(非受控异常):这种异常不需要显示处理,只在运行期间出现
6.2.3 try、catch、finally
- 异常的捕获和处理采用try-catch完成,具体的格式:
| try{ |
| |
| }catch(OneException e){ |
| |
| }catch(TwoException e){ |
| |
| }finally{ |
| |
| } |
- try中包含任何可能产生的代码
- try后面可以是一个catch或者多个catch;catch就是捕获异常的
- 如果try代码块中出现了异常,那么,立刻跳转到catch语句块中
- 在try出现异常的代码中以下的代码不会执行了
- finally表示,无论上面的代码是否有异常出现都必须执行
- try可以直接使用finally
6.2.3.1 案例
| public class Demo { |
| public static void main(String[] args) { |
| int i = 10; |
| int n = 0; |
| try { |
| |
| |
| int res = i/n; |
| |
| System.out.println(res); |
| }catch(ArithmeticException e){ |
| |
| System.out.println("不能被0除"); |
| } |
| } |
| } |
6.2.3.2 可以使用两种方式输出异常信息
| public class Demo { |
| public static void main(String[] args) { |
| int i = 10; |
| int n = 0; |
| try { |
| |
| |
| int res = i/n; |
| |
| System.out.println(res); |
| }catch(ArithmeticException e){ |
| |
| String message = e.getMessage(); |
| System.out.println("异常的描述信息:"+message); |
| } |
| } |
| } |
| public class Demo { |
| public static void main(String[] args) { |
| int i = 10; |
| int n = 0; |
| try { |
| |
| |
| int res = i/n; |
| |
| System.out.println(res); |
| }catch(ArithmeticException e){ |
| |
| e.printStackTrace(); |
| } |
| } |
| } |
6.2.3.3 受控异常
| public class Demo { |
| public static void main(String[] args) { |
| try{ |
| FileInputStream fileInputStream = new FileInputStream(); |
| }catch (FileNotFoundException e){ |
| e.printStackTrace(); |
| } |
| } |
| } |
6.2.3.4 finally关键字
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| |
| public class Demo { |
| public static void main(String[] args) { |
| try{ |
| FileInputStream fileInputStream = new FileInputStream("D:/a/a.txt"); |
| }catch (FileNotFoundException e){ |
| e.printStackTrace(); |
| }finally { |
| System.out.println("是必须执行的代码"); |
| } |
| } |
| } |
- 使用场景:释放资源
- 深入finally:在return前执行finally代码块,但是,返回的是10,因为a变量已经在弹栈过程中了
| public class Demo { |
| public static void main(String[] args) { |
| int result = method(); |
| System.out.println(result); |
| } |
| |
| public static int method(){ |
| int a = 10; |
| try{ |
| return a; |
| }finally { |
| System.out.println("在return前执行"); |
| a = 100; |
| } |
| } |
| } |
| public class Demo { |
| public static void main(String[] args) { |
| int result = method(); |
| System.out.println(result); |
| } |
| |
| public static int method(){ |
| int a = 10; |
| try{ |
| a = 200; |
| }finally { |
| System.out.println("在return前执行"); |
| a = 100; |
| } |
| return a; |
| } |
| } |
6.2.3.5 final、finally、finalize的区别?
- final:
- 修饰类不能被继承
- 修饰参数:
- 基本类型:值不能修改
- 引用类型:地址(对象)不能修改
- static final修饰常量
- finally:代码无论如何都必须执行
- finalize():垃圾回收前调用的方法
6.3 如何声明异常
- 在方法中可以使用throws声明异常,如果声明的异常为受控异常,那么,在调用方法的时候必须处理
6.3.1 声明异常;处理异常
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| |
| public class Demo { |
| public static void main(String[] args) { |
| |
| try { |
| method(); |
| } catch (FileNotFoundException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| public static void method() throws FileNotFoundException{ |
| FileInputStream fileInputStream = new FileInputStream("d:/a.txt"); |
| } |
| } |
6.3.2 还是使用声明异常(不推荐)
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| |
| public class Demo { |
| |
| public static void main(String[] args) throws FileNotFoundException { |
| |
| method(); |
| } |
| |
| public static void method() throws FileNotFoundException{ |
| FileInputStream fileInputStream = new FileInputStream("d:/a.txt"); |
| } |
| } |
6.3.3 声明非受控异常
| public class Demo { |
| public static void main(String[] args) { |
| |
| |
| |
| |
| try{ |
| method(); |
| }catch (ArithmeticException e){ |
| e.printStackTrace(); |
| } |
| } |
| |
| |
| public static void method() throws ArithmeticException{ |
| int i = 10,n = 0; |
| int r = i/0; |
| System.out.println(r); |
| } |
| } |
6.4 手动抛出异常
- 使用throw关键字抛出异常
- 相当于return,以下的代码不被执行
- 可以抛出受控异常或非受控异常
6.4.1 自定义一般性异常
| public class Demo { |
| public static void main(String[] args) { |
| |
| method(1,0); |
| } |
| |
| public static void method(int i,int n) { |
| try{ |
| if (n==0){ |
| |
| throw new MyException("不能为0"); |
| } |
| if (!(n > 0 && n<=100)){ |
| |
| throw new MyException("必须在1-100之间"); |
| } |
| int result = i / n; |
| System.out.println("------------>>"+result); |
| |
| }catch(Exception e){ |
| e.printStackTrace(); |
| } |
| |
| } |
| } |
| |
| |
| class MyException extends Exception{ |
| public MyException() { |
| super(); |
| } |
| |
| public MyException(String message) { |
| super(message); |
| } |
| |
| public MyException(String message, Throwable cause) { |
| super(message, cause); |
| } |
| |
| public MyException(Throwable cause) { |
| super(cause); |
| } |
| |
| protected MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { |
| super(message, cause, enableSuppression, writableStackTrace); |
| } |
| } |
6.4.2 自定义运行期异常
| public class Demo { |
| public static void main(String[] args) { |
| |
| method(1,0); |
| } |
| |
| public static void method(int i,int n) { |
| if (n==0){ |
| |
| throw new MyException("不能为0"); |
| } |
| if (!(n > 0 && n<=100)){ |
| |
| throw new MyException("必须在1-100之间"); |
| } |
| int result = i / n; |
| System.out.println("------------>>"+result); |
| } |
| } |
| |
| |
| class MyException extends RuntimeException{ |
| public MyException() { |
| super(); |
| } |
| |
| public MyException(String message) { |
| super(message); |
| } |
| |
| public MyException(String message, Throwable cause) { |
| super(message, cause); |
| } |
| |
| public MyException(Throwable cause) { |
| super(cause); |
| } |
| |
| protected MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { |
| super(message, cause, enableSuppression, writableStackTrace); |
| } |
| } |
6.4.3 throws和throw的区别?
- throws:声明异常(不处理,谁使用谁处理)
- throw:抛出异常(抛出自定义异常)
6.5 异常的捕获顺序
| public static void main(String[] args) { |
| try { |
| FileInputStream fileInputStream = new FileInputStream(""); |
| } catch (FileNotFoundException e) { |
| e.printStackTrace(); |
| } catch (IOException e){ |
| e.printStackTrace(); |
| } catch (Exception e){ |
| e.printStackTrace(); |
| } |
| } |
6.6 方法覆盖(重写)与异常
- 子类不能抛出比父类更多的异常,可以抛出父类异常的子异常
6.6.1 自定义异常类和接口
| |
| class UserNotFound extends IOException{} |
| class PasswordException extends UserNotFound{} |
| class RegisterException extends Exception {} |
| |
| |
| interface UserDao{ |
| |
| void show() throws UserNotFound; |
| } |
6.6.2 第一种情况(正确),实现类抛出的异常与接口中抛出的异常相同
| class UserDaoImpl implements UserDao{ |
| |
| @Override |
| public void show() throws UserNotFound { |
| |
| } |
| } |
6.6.3 第二种情况(正确),可以抛出父类异常的子异常
| class UserDaoImpl implements UserDao{ |
| |
| @Override |
| public void show() throws UserNotFound,PasswordException { |
| |
| } |
| } |
6.6.4 第三种情况(错误),不能抛出比父类更多的异常
| class UserDaoImpl implements UserDao{ |
| |
| @Override |
| public void show() throws UserNotFound,RegisterException { |
| |
| } |
| } |
6.7 总结
6.7.1 受控异常、非受控异常区别:
- 受控异常:必须显示的处理
- 非受控异常:可以不用显示处理,运行时不需要处理,直接由jvm捕获;
6.7.2 异常的关键字:
- try把有可能出现问题的代码编写在此
- catch异常捕获
- finally代码无论如何都必须执行
- throws声明异常,但不处理(一般都是底层代码)
- throws手动抛出异常(自定义异常)
6.7.3 方法覆盖与异常
- 子类不能抛出比父类更多的异常,可以抛出父类异常的子异常