Java学习笔记--异常知识笔记

结合学习和菜鸟笔记整理~附菜鸟教程中关于异常的网址
https://www.runoob.com/java/java-exceptions.html


我们为什么要处理异常?当程序执行过程中,遇到某一个异常(该异常通常难以解决,例如拔网线产生的断网异常)将会直接中止执行,这对用户的体验是非常不好的。为了保证之后的程序能够正常顺利的执行,我们引入面向对象异常机制。
遇到错误系统抛出异常,我们捕获异常,处理输出错误提示,继续执行程序其他部分

异常的分类

  • 检测性异常:可检测性异常经编译器验证,对于声明抛出异常的任何方法,编译器将强制执行处理或声明规则,不捕捉这个异常,编译器就不通过,不允许编译。编译器要检查这类异常,检查的目的一方面是因为该类异常的发生难以避免,另一方面就是让开发者去解决掉这类异常,所以称为必须处理(try …catch / throws)的异常。
    如果不处理这类异常,集成开发环境中的编译器一般会给出错误提示。

例如:FileInputStream fis=new FileInputStream("./src/io/BRDemo.java");
该语句必须try…catch或者throws 来规避IOException

  • 非检测性异常/运行时异常:简单说是都属于可以通过逻辑来纠正的错误,可以称之为bug。类似于空指针异常,我们完全可以通过if分支判断来避免这类异常,亦或那种十分常见的语句。
    如果不处理这类异常,集成开发环境中的编译器也不会给出错误提示。

例如:空指针异常NullPointerException即使我们有,系统也不会提示我们必须捕获,可以进行修改程序进行处理,避免。
只有RuntimeException类属于非检测异常,因为普通JVM在操作时候引起的异常随时可能发生,此类异常一般是由特定操作引发。但这些操作在java应用程序中会频繁出现,因为他们不受编译器检查与处理或者声明规则的限制

常见的RuntimeException的子类型

image

  • **错误:**错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

Exception的层次关系

所有的异常类是从 java.lang.Exception 类继承的子类。
Exception 类是 Throwable 类的子类。除了Exception类外,Throwable还有一个子类Error 。
异常类有两个主要的子类:IOException 类和 RuntimeException 类。

Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。
Error 用来指示运行时环境发生的错误。
例如,JVM 内存溢出。一般地,程序不会从错误中恢复。
image

捕获异常:try—catch—finally

基础语法
try{
   可能出现异常的代码片段
}catch(XXXException e){try中出现XXXException后的解决办法
}finally{
   无论try中是否发生异常,finally中代码始终执行
   可以存放清理类型等收尾善后性质的语句
   比如IO操作后的close()调用。
}
//举例:
public class Demo {
   public static void main(String[] args) {
       System.out.println("程序开始了");
       try {
           String str = null;
           System.out.println(str.length());
           return;//方法实际返回前也要先执行完finally
       }catch(Exception e){
           System.out.println("出错了!");
       }finally {
           System.out.println("finally中的代码执行了!");
       }
       System.out.println("程序结束了");
   }
}
扩展:
  • 多重捕获块:一个 try 代码块后面跟随多个 catch 代码块。

    注意 :多重捕获一定是子类型的异常在上,超类型/大范围的异常在下

try{

}catch(){

}catch(){

}catch(){

}...
  • 可以合并捕获异常,当不同异常处理手段相同时,可以用这种方式。
try{
	  需要检查的语句块
}catch(NullPointerException|StringIndexOutOfBoundsException e){
     System.out.println("出现了空指针或下标越界的处理!");
}catch(Exception e){
     System.out.println("反正就是出了个错!");
}
注意:
  • try语句块不能独立存在,后面必须跟catchfinally。

  • try, catch, finally 块之间不能添加任何代码。

IO中的异常处理:

我们先来看以下代码

public class FinallyDemo2 {
   public static void main(String[] args) {
       FileOutputStream fos = null;
       try {
           fos = new FileOutputStream("fos.dat");
           fos.write(1);
       }catch(IOException e){
           System.out.println("出错了!在这里解决了!");
       }finally{
           try {
               if(fos!=null) { //防止空指针异常
                   fos.close();
               }
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
   }
}

我们可以发现十分的麻烦,因为finally中的也要进行捕获。JDK1.7引入了自动关闭特性,使得我们在源代码中异常处理机制在IO应用中得到了简化:AutoCloseable

需要注意,该特性依然是编译器认可的,而非虚拟机认可。只是编译器帮我们做了上面麻烦的事情

AutoCloseable是一个接口,实现该接口的类将具有自动关闭的特性。
具体我们如何去实现呢?

public class AutoCloseableDemo {
    public static void main(String[] args) {
        //在try后面有个括号(),里面装相关的语句
        try(
                /*
                    只有实现了AutoCloseable接口的类才可以在这里定义并初始化。
                    编译器在编译时会将在这里定义的变量在finally中调用close将其关闭。
                    最终编译器会将当前代码改为FinallyDemo2的样子。
                 */
                FileOutputStream fos = new FileOutputStream("fos.dat");
        ){
            String line = "hello";
            fos.write(1);
        }catch(IOException e){
            System.out.println("出错了");
        }
    }
}

throw和throws

throw

引入:Java处理异常的方式,在Java代码中如果发生异常的话,jvm会抛出异常对象,导致程序代码中断,这个时候jvm在做的操作就是:创建异常对象,然后抛出:这是jvm自动帮我们操作的,如下:

int i=1; int j=0; int res=0;
res=i/j; //发生除零错误,系统运行到这里的时候会中断并自动抛出异常

但是!对于一些特殊的应用需求,比方用户程序自定义的异常和应用程序特定的异常就需要借助于throw语句来主动抛出,举例:

public void setAge(){
    int age = 0 ; 
	age = -100 ; 
	if(age<0 ) 
 	{ 
   		throw new Exception("IllegalAgeException");//创建异常对象 
	}  
	System.out.println(age);
}

这里当调用setAge方法的时候,系统就会知道这里可能会产生异常,需要处理。他要求我们必须进行try…catch或者throws

throws

当该方法/语句throw了一个方法时,我们需要进行处理。如果不想亲自try…catch此异常。我们可以在方法声明后抛出异常类名。这样当别人通过类调用该方法的时候,就知晓我需要处理这种异常(当然我可以继续抛出,知道main方法)

语法注意点:throws表示抛出异常,由该方法的调用者来处理;可以跟多个异常类名,用逗号隔开;throws表示出现异常的一种可能性,并不一定会发生这些异常

举例:

void fun()throws  IOException,SQLException { 
 	xxx;
} //表示如果执行fun()方法时候,可能会产生IO,SQL异常,并且fun方法内部并没有进行处理

main(){//main方法调用,就需要进行处理该两个异常
    try{
        fun();
	}catch(IOException){
        
    }catch(SQLException){
        
    }
}
小结

throw:则是用来抛出一个具体的异常类型。用在方法体内,跟的是异常对象名,只能抛出一个异常对象名。表示抛出异常,由方法体内的语句处理,throw则是抛出了异常,执行throw则一定抛出了某种异常。

throws:用来声明一个方法可能产生的所有异常,不做任何处理而是将异常往上传,谁调用我我就抛给谁。用在方法声明后面,跟的是异常类名。可以跟多个异常类名,用逗号隔开throws表示出现异常的一种可能性,并不一定会发生这些异常。

子类重写父类方法时throw的规则

配合例子来解释:
我们令父类如下:

public class ThrowsDemo {
    //dosome方法抛出两个异常
    public void dosome()throws IOException, AWTException {}
}

子类重写父类的方法

  • 以下写法可以

    class SubClass extends ThrowsDemo{
        //抛出相等的异常
        public void dosome()throws IOException, AWTException {}
    
        //允许仅抛出部分异常
        public void dosome()throws IOException{}
    
        //允许不再抛出任何异常
        public void dosome(){}
    
        //允许抛出超类方法抛出异常的子类型异常
        public void dosome()throws FileNotFoundException {}
    
    }
    
    
  • 以下写法是不允许的

    class SubClass extends ThrowsDemo{
        
        //不允许抛出额外异常(超类方法没有声明抛出的,或和超类声明抛出的异常没有继承关系的)
        public void dosome()throws SQLException {}
    
        //不允许抛出超类方法抛出异常的超类型异常
        public void dosome()throws Exception {}
    }
    
    

Java常见异常–篇幅过长单独写一篇~


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值