程序在运行时出现的不正常情况
java把程序运行时出现的各种不正常情况提取属性和行为进行描述,从而出现了各种异常类,也就是异常被面向对象了。
异常名称、异常信息、异常发生的位置
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5(数组下标越界异常类)
at Demo2.main(Demo2.java:6)
体系结构
-
Throwable(父类)
-
Error: 表示严重的问题,合理的应用程序不应该试图捕获。
-
Exception: 可以处理的不严重的问题,指示合理的应用程序想要捕获的条件。
int[] arr=new int[5]; System.out.println(arr[5]); //throw new ArrayIndexOutOfBoundsException() //(数组下标越界异常类) System.out.println("hehe");//程序中断,不打印
当发生数组下标越界异常时:
因为这种异常(ArrayIndex0utOfBoundsException)java内部已经定义了,所以系统会自动创建一个ArrayIndex0utOfBoundsException类的对象。main无法处理这种异常,抛给了JVM。JVM默认的处理异常的方式是,调用异常类对象的printStackTrace方法,printStackTrace方法会打印异常名字、异常信息、异常发生的位置,然后程序中断。
-
捕获异常
try{
可能发生异常的代码
}catch(异常类 参数名){
处理异常的代码
}
Throwable常用方法
class MyMath{
public int divide(int a,int b){
return a/b;//throw new ArithmeticException();
}
}
class Demo3{
public static void main(String[] args){
MyMath math=new MyMath();
try{
int result=math.divide(5,0);
//throw new ArithmeticException();
System.out.println(result);
}catch (Exception e){//=new ArithmeticException();
//System.out.println("除数为0了");
String msg=e.getMessage();//异常信息
System.out.println(msg);
System.out.println(e.toString());//异常类名:异常信息
e.printStackTrace();//异常类名:异常信息 异常发生的位置
}
System.out.println("ok");
}
}
throws声明
-
throws: 声明自己可能发生异常。用在方法的后边,throws后边跟的是异常类。
一个方法使用throws声明了可能发生异常,那么调用者必须处理,处理方式有两种:- 使用try{}catch(){}处理
- 调用者继续使用throws声明自己可能异常
如果不使用try{}catch(){}处理就会出现程序编译正常,运行出问题。
class MyMath{ public int divide(int a,int b)throws Exception{ return a/b; } } class Demo4{ public static void main(String[] args)//throws Exception { MyMath math=new MyMath(); int result=math.divide(5,0); System.out.println(result); } }
多重异常
- 当要捕获多个异常时,子类异常要写在父类异常前面。
- 声明的才是需要处理的
class MyMath{
public int divide(int a, int b)throws ArrayIndexOutOfBoundsException,ArithmeticException//声明自己可能发生异常.
{
int[] arr=new int[3];
System.out.println(arr[3]);
return a/b;
}
}
class Demo5
{
public static void main(String[] args)
{
MyMath math=new MyMath();
try{
int result = math.divide(5,0);
System.out.println(result);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("下标越界了");
}catch(ArithmeticException ee){
System.out.println("除数为0了");
}//catch(Exception){……} 没有声明的异常不需要处理
System.out.println("ok");
}
}
throw
用来手动创建异常类对象,使用了throw,必须处理,处理方式有两种
//手动创建异常类
class FuShuException extends Exception{
FuShuException(){}
//构造方法,定义异常信息
FuShuException(String message){
super(message);
}
}
class MyMath{ //声明用throws
public int divide(int a, int b)throws FuShuException{
if(b<0)
throw new FuShuException("除数为负数了");
//手动创建异常类对象用throw
return a/b;
}
}
class Demo5{ //声明用throws
public static void main(String[] args) throws FuShuException{
MyMath math=new MyMath();
int result=math.divide(5,-4);
System.out.println("Hello World!");
}
}
手动抛出异常数据
class FuShuException extends Exception{
int num;
FuShuException(){}
FuShuException(String message ){
super(message);
}
FuShuException(String message,int num){
super(message);
this.num=num;
}
public int getNum(){
return num;
}
}
class MyMath{
public int divide(int a, int b)throws FuShuException
{
if(b<0)
throw new FuShuException("除数为负数",b);
return a/b;
}
}
class Demo5
{
public static void main(String[] args){
MyMath math=new MyMath();
try{
int result=math.divide(5,-4);
System.out.println(result);
}catch(FuShuException e){
//=new FuShuException("除数为负数",b);
System.out.println(e.getMessage()+":"+e.getNum());
}
}
}
throw后面不能再跟语句,但抛出异常的方法后可以。
class Demo { public static void main(String[] args) { try { showExce(); System.out.println("A"); } catch(Exception e) { System.out.println("B"); } finally { System.out.println("C"); } System.out.println("D"); } public static void showExce()throws Exception { throw new Exception(); } } // BCD
class Demo { public static void func() { try { throw new Exception(); System.out.println("A");//10 0%执行不了 } catch(Exception e) { System.out.println("B"); } } public static void main(String[] args) { try { func(); } catch(Exception e) { System.out.println("C"); } System.out.println("D"); } }
throws和throw的区别
- throws用在函数名的后边,throw用在函数内部
- throws后边跟的是类名,throw后边跟的是异常类对象
运行时异常
-
运行时异常
- 使用了throw不处理,编译照样通过
- 使用了throws不处理,编译照样通过
- 编译时不检测的异常
- RuntimeException及其子类属于运行时异常
- 运行时异常,不处理编译也通过,原因是这些异常都是因为数据错误造成的异常。程序就应该中断,处理错误的数据。
-
非运行时异常
- 使用了throw,必须处理
- 使用了throws,必须处理
- 编译时检测的异常
- Exception及其子类属于非运行时异常
非运行异常的练习:老师用电脑上课 day13\Demo10.java
class LanPingException extends Exception{ LanPingException(){} LanPingException(String message){ super(message); } } class MaoYanException extends Exception{ MaoYanException(){} MaoYanException(String message){ super(message); } } class TeachProgramException extends Exception{ TeachProgramException(){} TeachProgramException(String message){ super(message); } } class Teacher{ private String name; private Computer computer; Teacher(){} Teacher(String name){ this.name=name; computer=new Computer(); } public void teach() throws TeachProgramException{ try{ System.out.println(name+"老师上课"); computer.run(); }catch(LanPingException e){ System.out.println(e.getMessage()); computer.reset(); }catch (MaoYanException ee){ System.out.println(ee.getMessage()); throw new TeachProgramException("上课进度受影响"); } } } class Computer { private int state=1; public void run() throws LanPingException,MaoYanException { if(state==1) System.out.println("电脑运行"); if(state==2) throw new LanPingException("电脑蓝屏"); if(state==3) throw new MaoYanException("电脑冒烟"); } public void reset(){ System.out.println("电脑重启"); } } class Demo6 { public static void main(String[] args) { Teacher teacher=new Teacher("张三"); try { teacher.teach(); } catch (TeachProgramException e) { System.out.println("老师休息"); System.out.println("学生自习"); } } }
try{
throw new Exception();
}catch(Exception e)
{
try{
throw e;
}catch(Exception ee)
{
throw new RuntimeException();
}
}
try-catch-finally
-
try { // 可能会发生异常的语句 } catch(ExceptionType e) { // 处理异常语句 } finally { // 必须执行的代码(清理代码块) }
-
try{//正常代码} finally{ //必须执行的代码(释放资源) }
-
使用 try-catch-finally 语句时需注意以下几点:
- 异常处理语法结构中只有 try 块是必需的,也就是说,如果没有 try 块,则不能有后面的 catch 块和 finally 块;
- catch 块和 finally 块都是可选的,但 catch 块和 finally 块至少出现其中之一,也可以同时出现;
- 可以有多个 catch 块,捕获父类异常的 catch 块必须位于捕获子类异常的后面;
- 不能只有 try 块,既没有 catch 块,也没有 finally 块;
- 多个 catch 块必须位于 try 块之后,finally 块必须位于所有的 catch 块之后。
- finally 与 try 语句块匹配的语法格式,此种情况会导致异常丢失,所以不常见。
一般情况下,无论是否有异常拋出,都会执行 finally 语句块中的语句:
finally{……}子句是异常处理的出口
finally与return的执行顺序
- 当 try 代码块和 catch 代码块中有 return 语句时,finally 仍然会被执行。
- 执行 try 代码块或 catch 代码块中的 return 语句之前,都会先执行 finally 语句。
- 无论在 finally 代码块中是否修改返回值,返回值都不会改变,仍然是执行 finally 代码块之前的值。
- finally 代码块中的 return 语句一定会执行。当 finally 有返回值时,会直接返回该值,不会去返回 try 代码块或者 catch 代码块中的返回值。