异常的概念:
异常是一种导致程序中断的指令流,如果不对异常进行正确的处理,则可能导致程序的中断指向,造成不必要的损失
异常的分类:
Throwable是所有异常的父类
Error:
严重问题,这个问题发生后,一般不针对编写的代码进行处理,通常都是有Jvm抛出的问题。
Exception:
RuntimeException:
运行时异常,该类及其子类都是,这种异常不处理,是可以编译通过的,但是运行时就会出错。
除了RuntimeException:
这类异常被称为编译时异常,这类异常必须要处理,不处理就运行不了。
异常的结构:
这是异常常见的一种结构写法:
try{
可能出现异常的代码:
}catch(异常名称){
处理方案:
}finally{
关闭资源
}
代码案例:
public class ExceptionTest {
public static void main(String[] args) {
int a =10;
int b =0;
// System.out.println(a/b);//分母不能为0,运行时异常,算数异常ArithmeticException。
// System.out.println("end");
try {
System.out.println(a/b);
}catch (RuntimeException e){
System.out.println("除数不能为0");
}finally {
System.out.println("end");
}
}
}
注意事项:
try:
里面代码越少越好,因为被try包裹着代码执行时要走异常处理机制,需要Jvm给该机制分配额外资源。
catch:
里面至少有一行代码
多个异常处理:
代码案例:
public class ExceptionTest {
public static void main(String[] args) {
int a =10;
int b =0;
int c[]={1,2,3};
// System.out.println(c[3]);//ArrayIndexOutOfBoundsException
try {
System.out.println(a / b);
System.out.println(c[3]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("数组索引越界");
}
catch (RuntimeException e){
System.out.println("除数不能为0");
}
finally {
System.out.println("end");
}
}
}
三种处理方法:
1.一个try多个catch
2.多个try对应多个catch,同时将多个异常抛出
3.一个try…catch,但是cath中异常写Exception,它可以匹配所有的子类异常
优缺点:
优点:省略了一些代码
缺点:try块中,如果前面的出现异常,则不会执行后面的代码。
注意:
1.同时存在多个异常时,当捕捉到第一个异常时,则直接跳转到finally,后续异常则不会再处理。
2.如果你不知道try中将会出现哪种异常,则可以使用父类的异常名称去捕获它(当然,能具体尽量具体)
3.多个异常中,存在等级关系,由小到大的捕获
异常新特性(jdk7以后):
public class ExceptionDemo3 {
public static void main(String[] args) {
int a =10;
int b =0;
int c[]={1,2,3};
try {
System.out.println(a / b);
System.out.println(c[3]);
}catch (ArrayIndexOutOfBoundsException|ArithmeticException e){//同级异常可以通过|写在一起
System.out.println("不好!有情况!");
}
finally {
System.out.println("end");
}
}
}
Throwable:
概述:
Throwable
类是 Java 语言中所有错误或异常的超类。
只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw
语句抛出
常见方法:
①返回此 throwable 的详细消息字符串。
public String getMessage()
②返回此 throwable 的简短描述。
public String toString()
③将此 throwable 及其追踪输出至标准错误流。
public void printStackTrace()
④将此 throwable 及其追踪输出到指定的输出流。
public void printStackTrace(PrintStream s)
代码案例:
/**
* Throwable
*
*/
public class ExceptionDemo4 {
public static void main(String[] args) {
int a=0;
int b=10;
try{
System.out.println(b/a);
}catch (Exception e){
System.out.println(e.getMessage());//返回此 throwable 的详细消息字符串。
System.out.println(e);//调用toString方法,打印异常类名和异常信息。
e.printStackTrace();//获取异常类名和异常信息,还有异常在程序中出现的问题,返回值void
}
}
}
throws与throw:
throws:
概述:
定义功能方式时,需要把出现的问题暴露出来,让调用者去处理。那么就需要通过throws在方法上标识。
格式:
权限修饰符 返回值类型 方法名()形参列表)throws 异常类型1,异常类型2…{}
注意:
1.throws必须跟在方法括号后面
2.一般情况下,throws别在main后面
编译时与运行时异常:
编译时的异常:以后谁调用该方法,一定要处理该异常。
运行时的异常:以后谁调用该方法,可以不一定处理该异常。
代码案例:
public class throwsTest {
public static void main(String[] args) {
try {
method();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void method()throws Exception {
int a =0;
int b =10;
System.out.println(b/a);
}
}
throw
概述:
在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。
代码案例:
public class throwDemo {
public static void main(String[] args) {
method();
}
public static void method(){
int a=10;
int b=0;
if(b==0){
throw new ArithmeticException();
}else {
System.out.println(a/b);
}
}
// public static void method() throws Exception {
// int a=10;
// int b=0;
//
// if(b==0){
// throw new Exception();
// }else {
// System.out.println(a/b);
// }
// }
}
区别:
throws
①用在方法声明后面,跟的是异常类名
②可以跟多个异常类名,用逗号隔开
③表示抛出异常,由该方法的调用者处理
④throws表示出现异常的一种可能性,并不一定会发生这些异常
throw
①用在方法体内,跟的是异常对象名
②只能抛出一个异常对象名
③表示抛出异常,由方法体内的语句处理
④throw则抛出了异常,执行throw则一定抛出了某种异常
异常的使用:
使用异常区别:
如果该功能可以将问题处理,就要try……catch处理
如果处理不了,就交给调用者处理,使用throws
区别:
如果程序还需要继续运行,就使用try……catch
如果程序不需要继续运行,就使用throws
finally:
特点:
被finally控制的语句体一定会执行
特殊情况下:在执行到finally之前jvm停止运行了,如System.exit(0)
public class finallyDemo {
public static void main(String[] args) {
int a=10;
int b=0;
try {
System.out.println(a/b);
}catch (Exception e){
System.out.println("分母不能为0");
//System.exit(0);有这句则不执行finally
}
finally {
System.out.println("结束啦");
}
}
}
作用:
用于释放资源,在IO流操作和数据库操作中会见到。
面试题:
①final、finally、finalize区别?
final:最终的意思,可以修饰类,成员变量,成员方法
修饰类:类不能被继承
修饰变量:变量不能被修改
修饰方法:方法不能被重写
finally:
它是异常的一部分,用于释放资源。一般来说,无论异常是否发生,finally都执行。
finalize:
Object的一个方法,用于垃圾回收
②如果catch里面有return语句,请问finally的代码会执行吗?如果会,顺序是在return前还是后?:
会,并且在return之前执行。
准确来说,是在finally是在return运行中执行,先让 return 200,但是还没返回走,这时候发现还有finally语句,在执行finally语句,此时a=400,改变的是变量值,但是return 200 的这个路径已经形成,不能改变,因此返回200
public class finallyDemo2 {
public static void main(String[] args) {
System.out.println(method());
}
public static int method(){
int a=100;
try {
System.out.println(a/0);
}catch (Exception E){
a=200;
return a;
}finally {
a=400;
System.out.println(a);
}
return 0;
}
}
自定义异常:
概述:
虽然java中有很多个异常类型,但是它只是我们常见的类型,并不能涵盖所有的异常。而我们在开发过程中,会遇到各种各样的异常,这时候我们就要使用自己定义的异常类的。
书写方式:
我们只需要写一个普通类,继承Exception,或者RuntimeException
①继承自Exception
②继承自RuntimeException
代码案例:
public class MyException extends Exception {
public MyException(){
}
public MyException(String s){
super(s);//一定要访问父类的有参构造,这样才能把异常信息打印到控制台
}
}
class Teacher{
public void check(int score) throws MyException {
if(score>100 || score<0){
throw new MyException("成绩只能在0-100之间");
}else {
System.out.println("你输入的成绩没问题");
}
}
}
class Student{
public static void main(String[] args) throws MyException {
System.out.println("请输入一个成绩:");
Scanner input =new Scanner(System.in);
int score = input.nextInt();
Teacher t = new Teacher();
t.check(score);
}
}
注意事项:
①子类覆盖父类方法时,子类的方法必须抛出相同的异常或者父类异常的子类(父亲坏了,儿子不能比父亲更坏)
②如果父类抛出了多个异常,子类覆盖父类时,只能抛出相同的异常或者是它的子集,子集不能抛出父类没有的异常
③如果被覆盖的方法没有编译异常的抛出,那么子类的方法绝对不可以抛出编译异常,如果子类方法内有编译异常发生,那么子类只能try不能throws
public class MyException2 {
public static void main(String[] args) {
zi z = new zi();
z.show();
z.method();
}
}
class fu{
public void show() throws ArrayIndexOutOfBoundsException{
}
public void method(){
}
}
class zi extends fu{
@Override
public void show() throws ArrayIndexOutOfBoundsException{
super.show();
}
@Override
public void method() throws ArithmeticException{
int a =10;
int b =0;
System.out.println(a/b);
}
}