Java基础之:异常及异常处理

JAVA学习网 2020-12-19 06:00:16

 

Java基础之:异常及异常处理

我们将java程序执行过程中出现的不正常现象称为异常,例如:之前遇到的数组下标越界异常,空指针异常等等

执行过程中发生的异常事件分为两类:

Error(错误):Java虚拟机无法解决的严重问题,如:JVM系统内部错误,资源耗尽等严重情况。比如:StackOverFlowError(栈溢出),Error是严重错误,程序会直接崩溃掉。

Exception:其他因为编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问等。Exception分为两大类:运行时异常(在程序运行过程中)、编译时异常(在程序编译过程中)

 

 

常见的运行时异常

NullPointerException:空指针异常
public class NullPointerException_ {
    private static String str;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println(str.length());
        System.out.println("hello~");
    }
​
}

 

ArithmeticException:数学运算异常

当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例, 例如:int i = 10 / 0

 

ArrayIndexOutOfBoundsException:数组下标越界异常
public class ArrayIndexOutOfBoundsException_ {
​
    public static void main(String[] args) {
​
        int[] arr = {1,2};
        System.out.println(arr[4]);
}

  

ClassCastException:类型转换异常

当试图将对象强制转换为不是实例的子类时,抛出该异常。例如,以下代码将生成一个 ClassCastException

public class ClassCastException_ {
​
    public static void main(String[] args) {
        
        Animal a = new Dog();
        Cat cat = (Cat)a;
    }
​
}
​
​
class Animal {
    
}
class Dog extends Animal {
    
}
class Cat extends Animal {
    
}
 
NumberFormatException:数字格式不正确异常

当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常 => 使用异常我们可以确保输入是满足条件数字.

public class NumberFormatException_ {
    public static void main(String[] args) {
        String name = "小范~";
        int num = Integer.parseInt(name);
    }
}

 

常见的编译时异常

  1. SQLException //操作数据库时,查询表可能发生异常

  2. IOException //操作文件时,发生的异常

  3. FileNotFoundException //当操作一个不存在的文件时,发生异常

  4. ClassNotFoundException //加载类,而该类不存在时,异常

  5. EOFException // 操作文件,到文件末尾,发生异常

  6. IllegalArguementException //参数异常

 

异常处理

异常处理就是当异常发生时,对异常处理的方式。

两种方式:

  1. try-catch-finally

    程序员在代码中捕获异常,并自行处理

  2. throws

    将发生的异常抛出给调用方,最顶级的调用方就是JVM

 

try-catch异常处理

Java提供try和catch块来处理异常。try块用于包含可能出错的代码。catch块用于处理try块中发生的异常。可以根据需要在程序中有任意数量的try...catch块。

基本语法:

try{

  //可能出现异常的代码

  //将异常生成对应的异常对象,作为参数传递给catch

}catch(异常对象){

  //异常处理

}

public class Exception_ {
​
    public static void main(String[] args) {
        String a = null;
        try {
            System.out.println(a.length());
            System.out.println(a);
        } catch (Exception e) {
            // TODO: handle exception
            System.out.println(e.getMessage());
        }
    }
}

注意事项

如果异常发生了,则异常发生那条语句后面的代码不会执行,直接进入catch块

如果异常没有发生,正常执行try块,不会进入catch块

可以使用多个catch块,捕获不同的异常(进行不同的业务处理),要求父类异常在后面,子类异常在前面。例如: RuntimeException在后面,NullPointerException在前面。如果发生异常只会匹配一个catch。

 

try-catch-finally异常处理

相较于try-catch而言,多了一个finally块,它的作用是:不管有没有出现异常,都一定会执行finally块中的代码。

当然也可以使用try-finally,但这种方法和不处理异常是一样的,最后会让JVM机来处理异常。而JVM机处理异常的方式,就是直接输出异常信息然后终止程序。所以不建议这样使用。

try-catch-finally案例

public class try_catch_finally{
    public static void main(String args[]){
        int[] a = {1,2,3};
        try{
            System.out.println(a[4]);
        }catch{
            System.out.println("数组下标越界异常");
        }finally{
            System.out.println("finally块执行....");
        }
    }
}

程序输出:

数组下标越界异常

finally块执行....

 

练习题

考虑下面程序输出:

package class_exception;
​
public class Test {
​
    @SuppressWarnings("finally")
    public static int method() {
        try {
            String[] names = new String[3];
            if (names[1].equals("john")) {// 空指针异常
                System.out.println(names[1]);
            } else {
                names[3] = "lucy";
            }
            return 1;
        } catch (ArrayIndexOutOfBoundsException e) {
            return 2;
        } catch (NullPointerException e) {
            return 3;
        } finally { // 一定要执行
            return 4;
        }
    }
​
    public static void main(String[] args) {
        System.out.println(method());
    }
}

练习题2

考虑程序输出:

package class_exception;
​
public class Test {
​
    public static int method() {
        int i = 1;
        try {
            i++; // 2
            String[] names = new String[3];
            if (names[1].equals("john")) { // 空指针异常
                System.out.println(names[1]);
            } else {
                names[3] = "lucy";
            }
            return 1;
        } catch (ArrayIndexOutOfBoundsException e) {
            return 2;
        } catch (NullPointerException e) {
            return ++i;     //提示:不是立即返回 记录 i= i+1 = 3 保存到 temp = 3
        } finally {
            ++i; 
            System.out.println("i=" + i);
        }
    }
​
    public static void main(String[] args) {
        System.out.println(method());   
    }
}

  

应用案例

如果用户输入的不是一个正整数,就提示他反复输入,直到输入一个正整数为止

import java.util.Scanner;
​
public class ClassWork {
​
    @SuppressWarnings("resource")
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int age;
        System.out.println("输入年龄:");
        for(;;) {
            try {
                age = new Scanner(System.in).nextInt();
                break;
            } catch (Exception e) {
                System.out.println("再次输入年龄(正整数):");
                continue;
            }
        }
        
        System.out.println("END");
    }
}

 

throws异常处理

如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。

在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Throws01 {
    public static void main(String[] args) throws FileNotFoundException {
​
        // 1. 使用try
        // 2. 使用throws
        
        m1();
        System.out.println("ok");
    }
    public static void m1() throws FileNotFoundException {
        FileInputStream fis = new FileInputStream("d://aa.txt");// 编译异常
    }
}

使用细节:

  1. 对于编译异常,程序中必须处理,使用try-catch或throws

  2. 对于运行时异常,程序如果没有处理,默认就是throws方式处理,将其抛给最顶层调用方JVM

  3. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型

  4. 在throws 过程中,如果有方法 try-catch , 就相当于处理异常,就可以不必throws

细节3案例:

class Father {
    public void m1() throws RuntimeException{
        
    }
}
​
class Son extends Father{
    @Override
    public void m1() throws NullPointerException{
        
    }
}

 

自定义异常

  1. 定义类:自定义异常类名(程序员自己写) 继承Exception或RuntimeException

  2. 如果继承Exception,属于编译异常

  3. 如果继承RuntimeException,属于运行异常(一般来说,继承RuntimeException)

自定义异常应用案例

package class_exception.ClassCustomException;
import java.util.Scanner;
​
/**
 * 当我们接收Person对象年龄时,要求范围在 1 – 130 之间,否则抛出一个自定义异常(要求 继承自定义异常)
 */
public class ClassWork01 {
​
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Person p = new Person();
        
        System.out.println("请输入年龄:");
        for(;;) {
            
            try {
                int a = scanner.nextInt();
                p.setAge(a);
                break;
            } catch (Exception e) {
                // TODO: handle exception
                System.out.println(e.getMessage());
                System.out.println("请重新输入年龄:");
                continue;
            }
            
        }
    }
}
​
class Person{
    private int age;
​
    public Person(int age) {
        this.age = age;
    }
    
    public Person() {
    }
​
    //创建方法使用异常
    public void setAge(int a) throws AException{
        if(!(a>=0 && a<=130)) {
            throw new AException("异常 要求范围在 1 – 130 之间");
        }
    }
}
​
class AException extends RuntimeException{
    /**
     * 添加版本号,不用管
     */
    private static final long serialVersionUID = 1L;
​
    //使用构造器传入异常信息
    public AException(String name){
        super(name);
    }
}

 

自定义异常应用案例2

package class_exception.ClassCustomException;
import java.util.Scanner;
/**
 * 编写应用程序,接收一个数,要求不能输入负数,进行异常处理。要求使用继承 RuntimeException 来实现,
 */
public class ClassWork02 {
    public static void main(String[] args) {
        
        Scanner s = new Scanner(System.in);
        System.out.println("输入一个数:");
        try {
            int a = s.nextInt();
            //因为是运行时异常,也可以不使用try处理
            if(a<0) {
                throw new IntException("不能输入负数");
            }
        }catch(RuntimeException e){
            System.out.println("异常信息:" + e.getMessage());
        }
        
        System.out.println("END");
    }
}
​
class IntException extends RuntimeException{
    private static final long serialVersionUID = 1L;
    public IntException(String name) {
        super(name);
    }
}

 

throw 和 throws 的区别

 

 

阅读(703) 评论(0)