异常以及处理机制

1)运行时异常: 程序运行的时候才出现的异常,什么空指针异常,数组越界,用try catch,主要是在运行的时候需要进行处理,点击运行按钮出现后的异常;

RuntimeException体系包括错误的类型转换,数组越界访问和尝试访问空指针等等,可以被try catch捕获,也可以交给JVM来进行处理(代码中什么也不写,最后程序继续向下执行)

尤其是运行时异常,最后不进行处理,那么最后会交给JVM来进行处理,最后就是程序异常终止

2)非运行时异常:没有运行的时候编译时期程序就会报错,有红线,用try catch捕获或者throws声明,主要是在编译的时候进行处理,没有运行程序的时候出现的异常

非runtimeException一般是外部错误,也就是受查异常,必须被try catch进行捕获cloneNotFoundException,所以说如果出现了受查异常,那么程序必须要进行处理掉这个异常才能够进行运行

一:异常的抛出

1)之前写的异常都是由程序运行或者是编译自动进行抛出的,当然也是可以通过自己写代码手动进行抛出异常

2)进行编写程序的时候,程序发生了错误,用户不想处理这个异常,那么此时就要将错误的信息告诉告诉方法调用者,这就叫做异常的抛出

3)可以通过throw关键字,抛出一个指定的异常对象,将错误信息告诉调用者:

throw new XXXException("异常产生的原因");

1)throw必须写在方法内部
2)抛出的对象必须是Exception或者是Exception的子类对象
3)如果抛出的是RunTimeException或者是RunTimeException的子类,那么可以不用处理,直接交给JVM处理
,程序会在这里面直接进行终止
4)抛出的是编译时异常,用户必须进行处理否则无法通过编译
5)异常一旦进行抛出,
后面的代码就不会执行

6)要是直接throw new Exception();默认是受查异常

二)异常的捕获:

异常的捕获,就是异常的具体处理方式,主要有两种:

异常声明throws以及try catch进行捕获处理

2.1)异常的声明:throws

1)它这种写法是处于方法声明时候在参数列表之后,当方法中出现抛出编译时异常的时候,用户不想要处理这个异常,那么就可以借助throws将异常抛给方法的调用者来进行处理,即使当前方法不处理异常,那么提醒方法的调用者来进行处理异常

2)但是throws并没有处理异常,最后想要进行处理异常还是要通过try catch

注意:

1)throws必须 在方法的参数列表之后

2)声明的异常必须是Exception以及Exception的子类

3)方法内部如果说抛出了多个异常,throws之间必须跟多个异常类型,之间用,进行分隔开,如果说抛出的多个异常类型具有具有父子类关系,那么直接声明父类就可以了

4)当我们进行调用抛出异常的方法的时候,调用者必须对该异常进行处理,或者说使用throws来进行声明,声明到到main方法之后,最后是交给JVM来进行处理的,程序会异常终止

2.2)用try catch来进行捕获异常:一旦出现异常,进入到对应的catch语句块里面,catch语句块后面的代码会立即执行

1)我们的throws其实本质上来说并没有针对异常来进行处理,而是将异常抛出给异常方法的调用者,由调用者来进行处理,如果说真是想要对异常来进行处理,那么就通过try-catch来进行真正的处理

2)try代码块中放的是可能出现异常的代码,catch代码块中存放的是出现异常后的处理行为,finally是用于代码块的善后处理工作,一般是在最后面执行;

3)所以说catch一定要有对应的异常类型

4)在JAVA中,所有抛出异常的类型都是一个类,这些类都是java.lang包底下的类,是不需要我们进行手动导入的,可以认为这是一个异常对象

1,不进行处理异常,就发现程序会终止在出现异常的地方,后面不会再继续执行
因为程序会把异常直接交给JVM来进行处理,这样的处理结果是,程序会抛出异常
并且不会再继续向下执行
  int[] arr1={1,2,3};
   System.out.println(arr1[0]);
   System.out.println(arr1[3]);
   System.out.println("hello");
2,但是此时当程序进行用try catch来进行包裹异常的时候程序会自己在catch中处理异常
这样处理的结果是程序会自动向下执行
但是一旦try中发现异常的语句,就会立即跳到catch语句里面
try之后代码块的语句不会执行,catch执行完毕之后会继续向下自动执行
程序并不会终止
      int[] arr1={1,2,3};
  try{
      System.out.println(arr1[0]);
      System.out.println(arr1[4]);//程序执行到这里,立即跳转到catch语句
      System.out.println("我爱我的家");
  }catch(ArrayIndexOutOfBoundsException e)
//这里面的ArrayIndexOutOfBoundsException不可以换成其他的异常
//否则还是会交给JVM进行处理
  {

  }
  System.out.println("我爱我的祖国");
最终我们打印的结果是1,我爱我的祖国
  try{
           System.out.println(10/0);
       }catch(NullPointerException e){
          System.out.println("这里面出现了空指针异常");
        }
    }
System.out.println(1);
比如说这种情况,这里面没有捕捉到对应的异常,那么最后这个异常最终就会交给JVM来进行处理
所以这里面的1不会执行
try{
  // 将可能出现异常的代码放在这里
}catch(要捕获的异常类型 e){
    // 如果try中的代码抛出异常了,此处catch捕获时异常类型与
    try中抛出的异常类型一致时,或者是try中抛出异常的基类时就会被捕获到
    // 对异常就可以正常处理,处理完成后,跳出try-catch结构,继续执行后序代码
}[catch(异常类型 e){
    // 对异常进行处理
}finally{
    // 此处代码一定会被执行到
}]

// 后序代码
// 当异常被捕获到时,异常就被处理了,这里的后序代码一定会执行
// 如果捕获了,由于捕获时类型不对,那就没有捕获到,这里的代码就不会被执行

注意:
1. []中表示可选项,可以添加,也可以不用添加
2. try中的代码可能会抛出异常,也可能不会

  try {
            int[] array=null;
            System.out.println("我是中国人");
            array[9]=10;
        }catch(Exception e){
            System.out.println("此时发生了异常");
    }

此时发生了向上转型,父类引用引用子类对象,由于父类引用了不同的子类对象,调用一个异常打印栈,此时就发生了多态绑定,运用到了多态的思想

1)try语句块里面抛出异常位置之后的代码不会继续执行

2)如果说抛出的异常类型和catch中的异常类型不匹配,那么异常不会被成功捕获,也就不会被处理那么会继续往外抛异常,直到JVM进行终止程序

3)try语句块中可能会抛出多个不同的异常对象,况且必须用多个catch来进行捕获,即多个异常,多次捕获

4)我们在进行捕获异常的时候,如果说你捕获的不是你抛出的,那么最后就会直接交给JVM来进行处理,只要最后交给JVM来进行处理,那么最后就会立即终止程序

5)catch也可以有多个,finally常常用于最后的善后工作,例如释放资源,无论是否发生异常,finally的代码块最终一定会被调用到,一旦异常类型不匹配,catch是不可以进行捕获的

int[] arr1={1,2,3,4,5,6,7};
  try{
      arr1=null;
      System.out.println("hehe");
      System.out.println(arr1[5]);
      System.out.println("heihei");
  }catch(ArrayIndexOutOfBoundsException e)
  {
      e.printStackTrace();
      System.out.println("此时发生了数组越界异常·");
  }catch (NullPointerException e)
  {
      e.printStackTrace();
      System.out.println("此时发生了空指针异常");
  }
最终打印结果的值是hehe
此时发生了空指针异常

1)多个异常还可以同时进行捕获,但是这种写法不推荐,因为会影响代码的可读性

       String str1="hello world";
        try{
            File file=new File("D:/text.html");
        }catch(NullPointerException|ArrayIndexOutOfBoundsException e){
            System.out.println("此时程序中出现了异常");
        }finally {
            System.out.println("我是finally中的语句");
        }
    }
try{语句块}catch(异常1|异常2 e){

} 

2)在进行捕获异常的时候,如果说出现了父子类关系,在catch语句块出现异常的顺序就是子类异常在前面,父类异常在后面,否则就会导致父类异常可以进行捕获所有子类异常,子类异常后面永远也不会执行

1)因为此时的Exception是所有异常类的父类,那么如果说你此时都交给他了,那么后面的这些子类都没有存在意义了 

2)但是如果说把Exception放到最后面写,意思就是都解决不了再让我解决

Scanner scanner=new Scanner(System.in);
  try{
      int num= scanner.nextInt();
      System.out.println(10/num);
  }catch(InputMismatchException e)
  {
      e.printStackTrace();
      System.out.println("输入错误");
  }catch (ArithmeticException e)
  {
      e.printStackTrace();
      System.out.println("算数异常,可能0作为了除数");
  }finally{
      scanner.close();
      System.out.println("finally代码块最终执行了");
  }
0
算数异常,可能0作为了除数
finally代码块最终执行了

示例代码:用try回收资源

try(Scanner scanner=new Scanner(System.in)){
    int num= scanner.nextInt();
    System.out.println(10/num);
}catch(InputMismatchException e)
{
    System.out.println("此时发生了输入错误");
}catch(ArithmeticException e)
{
    System.out.println("此事发生了算数异常,可能0作为了分母");
}
    }

如果此方法中没有合适的处理异常的方式,异常就会沿着调用栈向上进行传递

public static void func(int n)
    {
        System.out.println(10/n);
    }
    public static void main(String[] args) {
   try{
       func(0);
   }catch(ArithmeticException e)
   {
       System.out.println("此时发生了算数异常");
   }
    }
最终交给了main函数来进行处理

但是如果说一直向上传递都没有合适的方法去处理异常(main函数里面都没有try Catch)那么最终就会交给JVM来进行处理(和我们最开始没有使用try catch是一样的)

 public static void func(int n)
    {
        System.out.println(10/n);
    }
    public static void main(String[] args) {
        func(0);
        System.out.println(123);
    }
这个程序最终什么结果都不会进行打印,咱们的func处理不了这个异常,J就会向上传递,让main方法来进行处理,此时main方法也没有办法处理这个异常,那么直接交给JVM来进行处理,程序会终止
 public static int func()
    {
        int a=10;
        try{
            return a;
        }catch(ArithmeticException e)
        {
            e.printStackTrace();
        }finally{
            System.out.println("1");
            return 20;
        }
    }
    public static void main(String[] args) {
        int num=func();
        System.out.println(num);

    }
最终打印结果是1 20,此时异常有func方法交给了main方法,main方法捕获了这个异常并进行了处理
  public static int func(int x)
    {
        if(x==0)
        {
            throw new ArithmeticException("hh");
        }
        return 1;
        //return x/10;
    }
    public static void main(String[] args) {
        int x=func(0);
        System.out.println(x);
    }
无论返回多少,程序啥都不会进行打印

当一个代码中出现了受查异常,必须显式进行处理,如果一段代码可能会出现受查异常,那么也需要进行处理;

  public static void main(String[] args) throws FileNotFoundException {
        File file=new File("d:/22");
        Scanner scanner=new Scanner(file);
        System.out.println(scanner.nextLine());
    }

1)使用try catch进行包裹

  public static String readFile() {
     Scanner scan=null;
        try{
            File file=new File("d:/22");
            scan=new Scanner(file);
        }catch(FileNotFoundException e)
        {
            e.printStackTrace();
        }
        return scan.nextLine();

    }
    public static void main(String[] args) {
        String str=readFile();
        System.out.println(str);

    }

2)在方法名后面加上异常说明,相当于将处理动作交给上级调用者

 public static String readFile() throws FileNotFoundException {
        File file=new File("d:/22");
        Scanner scanner=new Scanner(file);
        return scanner.nextLine();
    }
    public static void main(String[] args) throws FileNotFoundException {
        String str=readFile();
    }
三)异常总结:

四)自定义异常:

1)针对于自定义异常来说,可以快速定位到程序所出现的错误

2)一个自定义异常继承了Exception就被称为受查异常,继承于RuntimeException就被称为非受查异常

   static class MyException extends Exception{       
       public MyException(String message) {          
           super(message); //不提供构造方法默认就是用不带有参数的                          
       }                                             
   }                                                 
   static class MyException1 extends RuntimeException
       public MyException1(String message) {         
           super(message);                           
       }                                             
   }                                                 
   public static void func1(int x){                  
       if(x==0)                                      
       {                                             
           try {                                     
               throw new MyException("这是我自己抛出的异常");
//也可以在方法后面加上MyException验证异常调用栈交给向上处理
           } catch (MyException e) {                 
               e.printStackTrace();                  
           }                                         
       }                                             
                                                     
   }                                                 
   public static void func2(int x)                   
   {                                                 
       if(x==0){                                     
           throw new MyException1("x==0");//不需要进行try catch进行包裹         
       }                                             
   }                                                 

实例1:实现一个简单的用户登录功能

static  class NameException extends RuntimeException{
      public NameException(){
      }
      public NameException(String message)
      {
         super(message);
      }
   }
 static  class PasswordException extends RuntimeException
   {
      public PasswordException(){
      }
      public PasswordException(String message)
      {
         super(message);
      }
   }
   private static final String name="李佳伟";
   private static final String password="12503487";
   public static void login(String name, String password) throws NameException, PasswordException {
      if(!test.name.equals(name))
      {
         throw new NameException("您输入的用户名错误");
      }
      if(!test.password.equals(password))
      {
         throw new PasswordException("您输入的密码是错误的");
      }
      System.out.println("登陆成功");
   }
   public static void main(String[] args) {
      try {
         login("李佳伟","12503487");
      } catch (NameException e) {
         e.printStackTrace();
      } catch (PasswordException e) {
         e.printStackTrace();
      }
   }

示例2:使用while循环来进行类似于恢复异常的处理行为,它将不断重复,直到程序不在抛出异常

 public static void main(String[] args) {
      int i = 0;
      while (i < 15) {
         try {
            if (i < 10) {
               throw new UnsupportedOperationException("i现在还小于10");
            }
         } catch (UnsupportedOperationException e) {
            e.printStackTrace();
            System.out.println("第" + i + "次");
            i++;
         }
      }
   }
import java.io.FileNotFoundException;
import java.io.IOException;
public class HelloWorld {
    public static void TestDemo()
    {
        System.out.println("执行这个方法");
    }
    public static void main(String[] args) {
        ((HelloWorld)null).TestDemo();
    }
    public static void run()
    {
        try{
            //这里面做了一些事情
        } catch(FileNotFoundException e)
        {
            System.out.println("发生文件找不到异常");
        }
        catch (IOException ex)
        {
            System.out.println("发生了IOException");
        }catch (java.lang.Exception e)
        {
            System.out.println("发生了异常");
        }
    }
    //这里面无论语句发生了什么异常,最终只能有一个catch语句快执行,他们是构成父子类关系的,只能抛出一个异常,只能捕获一个异常  
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值