java异常相关内容

8

1.什么是异常?

程序在运行过程中出现的特殊情况

2.异常处理的必要性

任何程序都可能存在大量的未知问题、错误;如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。

3.异常分类

Throwable:可抛出的,一切错误或异常的父类,位于java.lang包中。

第一类:Error:JVM、硬件、执行逻辑错误、不能手动处理。

  • 栈溢出 StackOverFlowError
  • 堆(内存空间)溢出 OutOfMemoryError
    public static void main(String[] args) {
        //1 StackOverFlowError 栈空间溢出
        method1();
        byte[] arr=new byte[1024*1024*210];
    }
    public static void method1(){
        System.out.println("helloworld");
        method1();
    }

程序运行设置堆大小当小于创建的数组时,出现堆溢出

    public static void main(String[] args) {
        //2 OutOfMemoryError  堆空间溢出
        byte[] arr=new byte[1024*1024*210];
    }

第二类:Exception:程序在运行和配置中产生的问题,可处理

[wppay]

  • 运行时异常(不受检异常):RunntimeException及其子类:一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。
  • 编译异常(受检异常):Exception中除RuntimeException极其子类之外的异常。如果程序中出现此类异常,比如说IOException,必须对该异常进行处理,否则编译不通过。在程序中,通常不会自定义该类异常,而是直接使用系统提供的异常类。

RunntimeException的主要异常:

运行时异常:

public class Demo2 {
    public static void main(String[] args) {
        //NullPointerException 空指针异常
        String s=null;
        System.out.println(s.hashCode());
        //ArrayIndexOutOfBoundsException 数组越界异常
        //ClassCastException 类型转换异常
        Object integer1=new Integer("111");
        String s2=(String)integer1;
        //NumberFormatException
        int n=Integer.parseInt("abc");
    }
}

ArithmeticException

public class Demo3 {
    public static void main(String[] args){
        Scanner input=new Scanner(System.in);
        System.out.println("请输入第一个数字");
        int num1=input.nextInt();
        System.out.println("请输入第二个数字");
        int num2=input.nextInt();
        int result=num1/num2;//ArithmeticException
        System.out.println("结果是:"+result);
    }
}

检查时异常

//SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
//sdf.parse("2020-10-5");//ParseException 可以抛出去或try-catch

4.异常的产生

  • 自动抛出异常:当程序在运行时遇到不符合规范的代码或结果,会产生异常
  • 手动抛出异常:语法: throw new 异常类型("实际参数")
  • 产生异常结果:相当于遇到return语句,导致程序因异常而终止

5.异常的传递

  • 按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(可打印堆栈跟踪信息)并中断程序。
  • 检查时异常:throws声明异常、修饰在方法参数列表后端
    • 声明异常,向上抛出异常,由调用者去解决异常
    • 调用者也可继续向上抛到JVM,没有处理
  • 运行时异常:可处理可不处理,无需声明异常

6.异常的处理关键字

  • try:可能出现异常的代码
  • catch:捕获异常
  • finally:异常最终处理,释放资源
  • throw:抛出异常
  • throws:声明异常

num++相当于另外开辟了一个变量存储

7.常见异常处理结构

7.1 try_catch(Ctrl+Alt+T)

  • try{}catch{}
    • try住可能出现异常的代码、catch异常处理的相关代码
      • getMessage():获取异常信息,返回字符串
      • printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void
    • 三种情况
      • 正常执行
      • 出现异常并处理
      • 异常类型不匹配
public class Demo4 {
    public static void main(String[] args) {
        //(1)try{ } catch{ }
        //出现三种清空
        //1 没有异常发生
        //2 发生异常
        //3 异常类型不匹配(捕获的时候不匹配)
        Scanner input=new Scanner(System.in);
        int result=0;
        try {
            //可能发生异常的代码
            System.out.println("请输入第一个数字");
            int num1=input.nextInt();
            System.out.println("请输入第二个数字");
            int num2=input.nextInt();
            result=num1/num2;
        }catch (Exception e){
            //捕获异常
            //getMessage()获取异常信息
            System.out.println(e.getMessage());
            //打印栈的追踪信息
            //e.printStackTrace();
        }
        System.out.println("结果是:"+result);
    }
}
  • try{}catch{}finally{}
    • finally{}发生异常都会执行、可以释放资源等
    • finally代码块不会被执行的情况
      • 不执行的唯一情况,退出java虚拟机,System.exit(0);//退出jvm
      • 程序所在的线程死亡或者cpu关闭
      • 如果在finally代码块中的操作又产生异常,则该finally代码块不能完全执行结束,同时该异常会覆盖前边抛出的异常。
    • try捕获到异常时,如果没有与之匹配的catch子句,则该异常交给JVM处理。如果存在finally,则其中的代码仍然被执行,但是finally之后的代码不会被执行。
    • try没有捕获异常时,try代码块中的语句依次被执行,跳过catch。如果存在finally则执行finally代码块,否则执行后续代码。
    • try捕获到异常时,如果存在与之匹配的catch,则跳到该catch代码块执行处理。如果存在finally则执行finally代码块,执行完finally代码块之后继续执行后续代码;否则直接执行后续代码。另外注意,try代码块出现异常之后的代码不会被执行。
public class Demo2 {
    //try{ } catch{ } finally{ 不管有没有发生都会执行,释放资源 }
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int result = 0;
        try {
            System.out.println("请输入第一个数字");
            int n1=input.nextInt();
            System.out.println("请输入第二个数字");
            int n2=input.nextInt();
            result = n1/n2;
            //System.exit(0);//退出jvm
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } finally {//不管有没有发生异常都会执行。特殊情况,jvm提前退出
            System.out.println("释放资源");
        }
        System.out.println("结果:"+result);
    }
}
  • try{}catch{}catch{}….
    • 子类异常在前,父类异常在后
    • 发生异常时按顺序逐个匹配
    • 只执行第一个与异常类型匹配的catch语句
    • finally{}根据需要可写或不写
public class Demo3 {
    //try{ } catch{ } catch{ } 注意:子类异常在前,父类异常在后
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int result = 0;
        try {
            System.out.println("请输入第一个数字");
            int n1=input.nextInt();
            System.out.println("请输入第二个数字");
            int n2=input.nextInt();
            result = n1/n2;
            //System.exit(0);//退出jvm
        } catch (ArithmeticException e) {
            System.out.println("算术异常");
        } catch (InputMismatchException e){
            System.out.println("输入有误");
        } catch (Exception e){
            System.out.println("未知异常");
        } finally {
            System.out.println("释放资源");
        }
        System.out.println("结果:"+result);
    }
}
  • try{}catch{}catch{}finally{} 见面试题
  • try{}finally{}
    • 不能捕获异常、仅仅用来当发生异常时,用来释放资源。
    • 一般用在底层代码,只释放资源不做异常处理,把异常向上抛出。

多重catch,遵循从小到大的顺序,父类异常在最后

public class Demo4 {
    //try{...} finally{...} 不能处理异常,如果发生异常时,资源释放,同时异常向上抛出
    public static void main(String[] args) {
        try {
            divide();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        System.out.println("程序结束了");
    }
    public static void divide(){
        Scanner input=new Scanner(System.in);
        int result = 0;
        try {
            System.out.println("请输入第一个数字");
            int n1=input.nextInt();
            System.out.println("请输入第二个数字");
            int n2=input.nextInt();
            result = n1/n2;
            //System.exit(0);//退出jvm
        }  finally {
            System.out.println("释放资源");
        }
        System.out.println("结果:"+result);
    }
}

面试题

try、catch、finally都可以包含return。但finally不建议使用,导致返回结果不正确。

在try中添加return方法,finally会不会执行? 会执行

  • 即使try{}里有return语句,finally{}都会执行
  • 没有异常发生先执行完finally(若finally里面有return语句直接返回,若没有再返回try的return)
  • 有异常发生,先执行catch,再执行finally(若finally里面有return语句直接返回,若没有再返回catch的return)

7.2 throws

声明此类在有异常,自己不解决向上抛出异常,由调用者去解决异常,调用者也可继续向上抛到JVM,没有处理。

public static void divide() throws Exception

声明的是运行时异常,调用方可以处理也可以不处理,编译时异常,必须处理

public class Demo6 {
    public static void main(String[] args) throws Exception{
//        try {
//            divide();
//        }catch (Exception e){
//            System.out.println(e.getMessage());
//        }
        divide();
        System.out.println("程序结束了...");
    }
    public static void divide() throws Exception{ //声明异常:告诉调用者有异常
        Scanner input=new Scanner(System.in);
        System.out.println("请输入第一个数字");
        int n1=input.nextInt();
        System.out.println("请输入第二个数字");
        int n2=input.nextInt();
        int result=n1/n2;
        System.out.println("结果是:"+result);
    }
}

7.3 throw

除了系统自动抛出异常外,有些问题需要程序员自己抛出异常,throw new Exception();
throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。只要没有被try-catch就会一直向上抛出由JVM处理。

public class DemoThrow {
  public static void main(String[] args) {
    try {
      int a = DemoThrow.div(4, 0);
      System.out.println(a);
    } catch (Exception e) {
      System.out.println(e.getMessage() + "  main");
    }
  }

  public static int div(int a, int b) {
    if (b == 0) {
      throw new ArithmeticException("异常信息:除数不能为0"); // 抛出具体问题,编译时不检测
    }
    return a / b;
  }
}
class Person {
    private String name;
    private int age;
    private String sex;

    public Person(String name, int age, String sex) throws Exception {
        this.name = name;
        this.setAge(age);
        this.setSex(sex);
    }

    public Person() {
    }

    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 {
        if (age <= 0 || age > 120) {
            //手动抛出异常
            throw new AgeException("年龄不符合要求");
        } else {
            this.age = age;
        }
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) throws Exception {
        if (sex.equals("男") || sex.equals("女")) {
            this.sex = sex;
        } else {
            throw new SexException("性别不能符合要求");
        }
    }

    @Override
    public String toString() {
        return "Person{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", sex='" + sex + '\'' +
            '}';
    }

    public void eat() {
        System.out.println("开始吃饭了...");
    }
}

public class TestPerson {
    public static void main(String[] args) {
        try {
            Person cancan = new Person("灿灿", 200, "神");
            System.out.println(cancan.toString());
        } catch (Exception e) {
//            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        System.out.println("程序结束了");
    }
}

7.4 自定义异常

  • 需要继承Exception或Exception的子类,代表特定问题
  • 异常类型名称望文生义,可在发生特定问题时抛出对应异常
  • 生成全部的Exception重写方法
  • 右击生成里的Override - java.lang.Exception

案例同throw:抛出明确的异常

public class AgeException extends Exception{
    public AgeException() {
        super();
    }

    public AgeException(String message) {
        super(message);
    }

    public AgeException(String message, Throwable cause) {
        super(message, cause);
    }

    public AgeException(Throwable cause) {
        super(cause);
    }

    protected AgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
public class SexException extends Exception {
    public SexException() {
    }

    public SexException(String message) {
        super(message);
    }

    public SexException(String message, Throwable cause) {
        super(message, cause);
    }

    public SexException(Throwable cause) {
        super(cause);
    }
    public SexException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

7.5 带有异常声明的方法重写

  • 子类继承父类
  • 方法名、参数列表、返回值类型必须和父类相同
  • 子类的访问修饰符符合父类相同或是比父类更宽
  • 子类中的方法,不能抛出比父类更多,更宽的检查时异常
  • 父类不抛,子类也不能抛
class Person {
    public void eat()  throw Exception{
        System.out.println("开始吃饭了...");
    }
}
public class Student extends Person {
    @Override
    public void eat() throw Exception(或其子类、不抛) {
        System.out.println("学生开始吃北京烤鸭...");
    }
}

[/wppay]