异常处理

一、为什么有异常

在使用计算机语言进行项目开发的过程中,即使程序员把代码写得尽善尽美,在系统运行的时候仍然会出现很多靠代码不能规避的错误,比如:用户的输入格式,读取文件是否存在,网络是否保持畅通等。

二、异常

异常:在java中,将程序执行中发生不正常情况称为“异常”。(语法和逻辑的错误不是异常)

异常可以分为两类:

Error:java虚拟机无法解决的严重问题。JVM内存错误,资源耗尽等严重问题。比如:StackOverflowError。一般不编写针对性的代码进行处理。

Exception:其他因编程或者外在因素导致的一般性问题,可以用针对性的代码进行处理。比如:空指针访问,数组下标越界,数组不匹配等。

常见的异常:

*********下面是编译时异常*************
File file = new File("hello.text");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while(data != -1){
    System.out.println((char)data);
    data = fis.read();
}
fis.close();

*********下面是运行时异常*************
//NullPointerException  空指针异常
String str = "abc";
str = null;
System.out.println(str.charAt(0));

//ArrayIndexOutOfBoundsException  数组越界
int[] a = new int[10];
System.out.println(a[10]);

//ClassCastException   类型转换异常
Object obj = new Date();
String str1 = (String)obj;

//NumberFormatException  数值转换异常
String str2 = "abc";
int b = Integer.parseInt(str2);

三、异常的处理(自动抛出)

在编写程序的时候,经常要在可能出现错误的地方加上检测代码,比如if-else,太多的这样的语句可能会导致代码的加长,臃肿,可读性差。因此常采用异常处理机制。Java采用异常处理机制,是将异常处理的程序代码集中在一起,与正常的代码分开,使得程序简洁、优雅、并且容易维护。

程序正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象,将次对象抛出,进行异常处理。

异常处理的两种方式:1.try-catch-finally   2.throws

1.try-catch-finally

try{
    //可能会出现异常的代码
}catch(异常类型1 变量1){
    //处理异常方式1
}catch(异常类型2 变量2){
    //处理异常方式2
}
....
finally{
    //必须执行的代码
 }

说明:

1.finally是可选的,finally中声明的语句一定会被执行,即使catch中又出现异常,在try中又有return语句依然会执行。在一些时候finally必须写:向数据库连接、输入输出流、网络编程Socket等资源,JVM不能自动回收,我们需要在finally中手动回收。

2.使用try将可能出现异常的代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常的对象的类型,去catch中进行匹配。

3.一旦try中的异常对象匹配到某个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出结构,继续执行代码。

4.catc中的异常类型如果没有子父类关系,则谁上谁下没有关系;如果有,子类一定要在父类的上面。

5.常用的异常对象处理方式(1)String getMessage() (2)printStackTrace()。

6.try-catch-finally可以嵌套。

7使用try-catch-finally处理编译时异常,让程序在编译的时候不报错,但是运行的时候仍可能报错。相当于让编译时异常延时到运行时。

8开发种由于运行时异常比较常见,通常不针对运行时异常编写try-catch-finally语句。但是编译时异常一定要考虑。

2.throws

“throws + 异常类型”写在方法声明处,指执行此方法时,可能会抛出异常类型。一旦方法体执行出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后面的异常类型就被抛出。异常代码后的部分不执行。

    public void method2(){
        try {
            method1();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public void method1() throws IOException {
        File file = new File("hello.text");
        FileInputStream fis = new FileInputStream(file);
        int data = fis.read();
        while(data != -1){
            System.out.println((char)data);
            data = fis.read();
        }
        fis.close();
    }

注意:

try-catch-finally是真正将异常处理掉,

throws的方式只是将异常抛给方法的调用者,并没有真正的处理掉。

子类重写的方法抛出的异常不大于父类被重写方法抛出的异常。

public class Main {
    public static void main(String[] args) {
        Main test = new Main();
        test.display(new SubClass());
    }
    public void display(SuperClass s){
        try {
            s.method();//子类重写的方法
        }catch (IOException e){//子类的异常 要小于它
            e.printStackTrace();
        }
    }
}
class SuperClass{
    public void method() throws IOException{//父类没有抛异常,子类就不能抛异常
    }
}
class SubClass extends SuperClass{
    @Override
    public void method() throws FileNotFoundException {//这里抛出的异常要比,不然 上面的catch无法接受
    }
}

try-catch-finally 和 throws 的选择(处理和抛出的选择)

如果父类被重写的方法没有抛出异常,如果子类重写的方法要抛出异常的话,必须用try-catch-finally。

在执行方法a种,又调用了另外几个方法,并且这几个方法是递进的关系执行。建议这几个方法用throws的方式处理。而a方法考虑用try-catch-finally。​​​​​​处理。

如果是因为传参导致的异常(想要int型,缺填的其他类型),应该通过throws抛出

四、手动抛出异常

上面的异常都是系统自动生成异常对象。这里手动生成一个异常对象,并抛出throw, 区分上面的throws。throw只是一种异常的产生方式,不是异常的处理方式。

public class Main {
    public static void main(String[] args) {
        Student student = new Student();
        try {
            student.regist(-1);
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }
}
class Student{
    private int id;
    public void regist(int id) throws Exception {
        if(id > 0) this.id = id;
        else {//输入数据非法

            运行时异常可以不用异常处理,直接这亚子就完了
            //throw new RuntimeException("输入数据非法");

            //这个异常既包括运行时异常,和编译时异常。所以要进行异常处理
            throw new Exception("输入数据非法");//括号里面时异常信息,可以用getMessage
        }
    }
}
输入数据非法

throw和throws的区别:

throw :是产生一个异常类,是异常的生成方式,声明在方法体内

throws :是异常的处理方式,声明在方法的声明处

五、用户自定义异常类

1.继承现有的异常结构,RuntimeException,Exception

2.提供全局常量serialVersionUID

3.提供重载的构造器

class MyException extends RuntimeException{
    static final long serialVersionUID = -1561651561561L;

    public MyException() {
    }
    public MyException(String msg) {
        super(msg);
    }
}

练习:

public class Main {
    public static void main(String[] args) {
        try {
            int i = Integer.parseInt(args[0]);
            int j = Integer.parseInt(args[1]);
            int result = ecm(i,j);
            System.out.println(result);
        }catch (NumberFormatException e){
            System.out.println("数据类型不一致");
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println("缺少命令行参数");
        }catch (ArithmeticException e){
            System.out.println("除 0");
        }catch (EcDef e){
            System.out.println(e.getMessage());
        }
    }

    public static int ecm(int i,int j) throws EcDef {//非运行时异常,要处理
        if(i < 0 || j < 0){
            throw new EcDef("分子或分母为负数");
        }
        return i/j;
    }
}

class EcDef extends Exception{
    static final long serialVersionUID = -15616511561561L;

    public EcDef() {}

    public EcDef(String msg) {
        super(msg);
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值