Java异常总结

Throwable

Error:严重问题,通常出现重大问题如:运行的类不存在或者内存溢出,服务器宕机,数据库崩溃等等。出现了error,靠我们的异常处理方式 try{}catch(){}和throws是处理不了的,必须找出哪个地方犯了这么严重的错误,然后修改代码,改正确了之后,程序才能够运行起来,否则程序绝对运行不起来。

代码演示:

public class Test {
    public static void main(String[] args) {
		show();
	}

	private static void show() {			
        show();		//java.lang.StackOverflowError栈内存溢出,这种情况必须更改代码
	}
}	
Exception

Exception下面RuntimeException下面的儿子都是运行期异常。运行时期异常可以处理也可以不处理

1)不处理:如果不处理,也不会报错(eclipse报红线),java就会用jvm默认的的处理方式,它就把异常的类型、原因、位置直接显示在了控制台。并且退出当前线程(可以理解为退出虚拟机),同时后面的代码是不能执行的。

2)处理:为了让后面的代码继续执行,那么我们处理异常, 我们采用try{}catch(){}

try{	
	可能发生问题的代码。	
}catch(异常类名 变量名){
	变量名.printStackTrace();//异常处理代码。
}finally{
	释放资源代码。(数据库,IO)
}

代码演示:

public static void main(String[] args) {
    try{
        System.out.println(10/0);
    }catch(ArithmeticException a) {	//ArithmeticException a = new ArithmeticException();
        System.out.println("出错了,除数为零了");	//打印出:出错了,除数为零了
    }

    System.out.println("1111111111111111");	//打印出:1111111111111111,不会影响后面代码的运行
}

注意事项:

①一个try里面有多个异常怎么办?可以一个try后面跟多个catch,但是如果异常是平级关系,没有顺序问题。如果异常存在着子父关系,父一定要放在最后。

代码演示:

public static void demo1() {
    int a = 10;
    int b = 0;
    int[] arr = {11,22,33,44,55};
    try {
        System.out.println(a / b);	//运行时报错
        System.out.println(arr[10]);	//此代码不会执行
        arr = null;			//此代码不会执行
        System.out.println(arr[0]);	//此代码不会执行
    } catch (ArithmeticException e) {
        System.out.println("除数不能为零");
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println("索引越界了");
    } catch (Exception e) {			//Exception是父类  父类一定放在最后面 
        System.out.println("出错了");
    }
    System.out.println("over");	//不影响后面代码的运行
}

②:可以用一个catch, catch里面写一个Exception就可以了

代码演示:

public static void demo1() {
    int a = 10;
    int b = 0;
    int[] arr = {11,22,33,44,55};

    try {
        System.out.println(a / b);
        System.out.println(arr[10]);
        arr = null;
        System.out.println(arr[0]);
    } catch (Exception e) {			//多态
        System.out.println("出错了");
    }							
    System.out.println("over");
}

③了解JDK7的新特性。格式:try{}catch(异常1 | 异常2 | 异常3 … 变量名){}

代码演示:

public static void main(String[] args) {
    int a = 10;
    int b = 0;
    int[] arr = {11,22,33,44,55};

    //JDK7如何处理多个异常
    try {
        System.out.println(a / b);
        System.out.println(arr[10]);
    } catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
        System.out.println("出错了");
    } 
}

④我们一直在处理异常的时候都是打印的一句话,虽然提示了我们有错误,但是没有告诉开发人员是哪一行代码出错,没有告诉开发人员是哪个异常! 那这样的话,不利于开发人员对代码进行维护,所以我们就有了标准的异常catch代码,既能打印出异常消息,显示出哪一行出的错,又能不影响后面的代码执行。首先介绍:Throwable中的方法:

public String getMessage():返回的是异常的消息字符串。

public String toString():返回异常的简单描述信息。全路径类名 : 消息字符串

public void printStackTrace():把错误信息显示在控制台。

代码演示:

public static void main(String[] args) {
    try {
        System.out.println(1/0);
    } catch (Exception e) {			//Exception e = new ArithmeticException("/ by zero");
        System.out.println(e.getMessage());//	/ by zero
        System.out.println(e); 		//java.lang.ArithmeticException: / by zero
        e.printStackTrace();		
        /*java.lang.ArithmeticException: / by zero at 			com.heima.exception.Demo5_Throwable.main(Demo5_Throwable.java:18) 
													*/
    }
}

⑤finally的程序除了虚拟机挂掉,其他的时候都会执行的,所以把一些必须要执行的重要代码放在finally里面执行。比如释放资源代码。
⑥final,finally和finalize的区别:

  • final可以修饰类,不能被继承;修饰方法,不能被重写;修饰变量,只能赋值一次
  • finally是try语句中的一个语句体,不能单独使用,用来释放资源
  • finalize是一个方法,当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法
面试题

如果catch里面有return语句,请问finally的代码还会执行吗?如果会,请问是在return前还是return后。

public static void main(String[] args) {
    System.out.println(method());		//30
}
public static int method() {
    int x = 10;
    try {
        x = 20;
        System.out.println(1/0);
        return x;
    } catch (Exception e) {
        x = 30;
        return x;	//当程序执行到这儿,内存中已经生成了一条"return 30"的路径,
        //但是发现finally还没有执行呢,就又去执行了finally里面的内容让x变成了40,
        //但是"return 30"的路径已经生成了,即使x变成了40也是没用的!
        //接着还是会继续执行"return 30" 然后结束方法。
    } finally {
        x = 40;							
    }
}

⑦如果处理运行期异常,我们还可以采用Throws 声明异常,但是我们一般不用(为什么?请看下面解释)。编译期异常:Exception下面非RuntimeException 的异常;运行期异常:RuntimeException下的异常。如果是运行期异常的话我们声明和不声明是一样的。而且只要运行时出现异常的话,声明和不声明异常,后面的代码都不会再继续执行了,那么我们为什么有个声明异常这种处理方式呢?这就引出了编译期异常,编译期异常就是在开发人员编写代码的时候,程序提示你这儿以后可能会出现一些常见的问题,让咱们在写代码的时候就要针对这常见的问题采取措施,不要等运行的时候出错了再去解决,因为这个问题很常见,可以预防,所以java呢为了这样提示开发人员就让开发人员在编写的时候都不让开发人员编译通过,必须要采取措施,而开发人员采取的措施一个就是用try{}catch(){} ,另一个就是不用管这个异常啦,直接抛给虚拟机(throws声明一下),这两种方式都证明开发人员知道这儿可能会出现异常,并采取措施了。 所以声明异常是给编译期异常准备的。 运行期异常虽然能用,但是没啥实际意义,所以运行期异常我们一般还是用try{}catch(){}。

自定义异常

有时候需要我们自己定义一些异常,很简单,只需要建一个类(类名见名知意) 继承这个异常体系(继承Exception或者其儿子),写一个有参构造方法用来传入异常信息,遇到特定业务的时候throw就可以了。

代码演示:

//建一个类(类名见名知意)继承这个异常体系(继承Exception或者其儿子)
class AgeOutOfBoundsException extends Exception {	
  
    public AgeOutOfBoundsException() {
        super();
    }
    public AgeOutOfBoundsException(String message) {//写一个有参构造方法,用来传入异常信息
        super(message);				
    }		
}

public class Demo_Exception {

    public static void main(String[] args) throws Exception {//p.setAge(-17);main方法中调用setAge方法的时候,因为setAge方法体上声明了一个编译期异常 所以main方法的方法体上也要声明该编译期异常
        Person p = new Person();
        p.setAge(-17);
        System.out.println(p.getAge());
    }

}

class Person {
    private String name;
    private int age;
    public Person() {
        super();
    }
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) throws Exception{	
        //方法体内如果有 "throw 编译期异常对象" ,则方法体上必须用throws声明该编译期异常
        if(age >0 && age <= 150) {
            this.age = age;
        }else {
            throw new AgeOutOfBoundsException("年龄非法");	//遇到特定业务的时候throw就可以了
        }
    }


}
throw和throws的区别:

throw 写在方法里面,后面跟对象,只能跟一个对象

throws 写在方法声明上,后面跟异常类型,可以跟多个异常类型并用逗号隔开

字符类关系中的异常

a:子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)

class Fu{
    public void show() throws IOException{	//父类方法声明 IOException 

    }
}
class Son extends Fu{
  
    public void show() throws IOException{	//这样是可以的 声明和父类相同的IOException

    }
  
    public void show() throws FileNotFoundException{
        //这样是可以的,声明父类异常的儿子,也就是IOException的子类FileNotFoundException

    }

    public void show() throws Exception{
        //这样是不行的 声明父类异常的父类,也就是IOException的父类Exception
    }
			
} 

b:如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常。

class Fu{
    public void show() throws IOException,NoSuchMethodException{

    }
}
class Son extends Fu{
    public void show() throws IOException{//这样写可以 子类只能抛出相同的异常或者是他的子集

    }
   
    public void show() throws ParseException{//这样做是不行的 子类不能抛出父类没有的异常

    }

}

c:如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常;如果子类方法内有异常发生,那么子类只能try,不能throws

class Fu{
    public void show(){

    }
}
class Son extends Fu{
    public void show(){//这样做可以 如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常

    }

    public void show() throws Exception{//这样做 不可以

    }

    public void show() {
        //如果被重写的方法没有异常抛出,而且子类方法内有异常发生,那么子类只能try,不能throws	
        try {
            FileInputStream fis = new FileInputStream("xxx.txt");  
            //new FileInputStream("xxx.txt");这句话有个编译期异常
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

}

好了今天就先说到这了,明天继续。想了解更多学习知识,请关注微信公众号“阿Q说”,获取更多学习资料吧!你也可以后台留言说出你的疑惑,阿Q将会在后期的文章中为你解答。每天学习一点点,每天进步一点点。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
其他还有很多异常,我就不一一列举了,我要说明的是,一个合格的程序员,需要对程序中常见的问题有相当的了解和相应的解决办法,否则仅仅停留在写程序而不会改程序的话,会极大影响到自己的开发的。关于异常的全部说明,在api里都可以查阅。 算术异常类:ArithmeticExecption 空指针异常类:NullPointerException 型强制转换异常:ClassCastException 数组负下标异常:NegativeArrayException 数组下标越界异常:ArrayIndexOutOfBoundsException 违背安全原则异常:SecturityException 文件已结束异常:EOFException 文件未找到异常:FileNotFoundException 字符串转换为数字异常:NumberFormatException 操作数据库异常:SQLException 输入输出异常IOException 方法未找到异常:NoSuchMethodException java.lang.AbstractMethodError 抽象方法错误。当应用试图调用抽象方法时抛出。 java.lang.AssertionError 断言错。用来指示一个断言失败的情况。 java.lang.ClassCircularityError 循环依赖错误。在初始化一个时,若检测到之间循环依赖则抛出该异常java.lang.ClassFormatError 格式错误。当Java虚拟机试图从一个文件中读取Java,而检测到该文件的内容不符合的有效格式时抛出。 java.lang.Error 错误。是所有错误的基,用于标识严重的程序运行问题。这些问题通常描述一些不应被应用程序捕获的反常情况。 java.lang.ExceptionInInitializerError 初始化程序错误。当执行一个的静态初始化程序的过程中,发生了异常时抛出。静态初始化程序是指直接包含于中的static语句段。 java.lang.IllegalAccessError 违法访问错误。当一个应用试图访问、修改某个的域(Field)或者调用其方法,但是又违反域或方法的可见性声明,则抛出该异常java.lang.IncompatibleClassChangeError 不兼容的变化错误。当正在执行的方法所依赖的定义发生了不兼容的改变时,抛出该异常。一般在修改了应用中的某些的声明定义而没有对整个应用重新编译而直接运行的情况下,容易引发该错误java.lang.InstantiationError 实例化错误。当一个应用试图通过Java的new操作符构造一个抽象或者接口时抛出该异常. java.lang.InternalError 内部错误。用于指示Java虚拟机发生了内部错误java.lang.LinkageError 链接错误。该错误及其所有子指示某个依赖于另外一些,在该编译之后,被依赖的改变了其定义而没有重新编译所有的,进而引发错误的情况。 java.lang.NoClassDefFoundError 未找到定义错误。当Java虚拟机或者装载器试图实例化某个,而找不到该的定义时抛出该错误java.lang.NoSuchFieldError 域不存在错误。当应用试图访问或者修改某的某个域,而该的定义中没有该域的定义时抛出该错误java.lang.NoSuchMethodError 方法不存在错误。当应用试图调用某的某个方法,而该的定义中没有该方法的定义时抛出该错误java.lang.OutOfMemoryError 内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误java.lang.StackOverflowError 堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误java.lang.ThreadDeath 线程结束。当调用Thread的stop方法时抛出该错误,用于指示线程结束。 java.lang.UnknownError 未知错误。用于指示Java虚拟机发生了未知严重错误的情况。 java.lang.UnsatisfiedLinkError 未满足的链接错误。当Java虚拟机未找到某个的声明为native方法的本机语言定义时抛出。 java.lang.UnsupportedClassVersionError 不支持的版本错误。当Java虚拟机试图从读取某个文件,但是发现该文件的主、次版本号不被当前Java
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿Q说代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值