JAVA-异常

JAVA-异常

1.什么是程序的异常

指的是程序在执行过程中,出现非正常情况,如果不处理最终会导致JVM的非正常停止。
异常指的并不是语法错误或逻辑错误。语法错了,编译不通过,不会产生字节码文件,根本不能运行。代码逻辑错误,只是没有得到想要的结果

2.异常的抛出机制

JAVA中把不同的异常用不同的类表示,一旦发生某种异常,就创建该异常类型的对象,并且抛出(throw)。然后程序员可以捕获(catch)到这个异常对象,并处理;如果没有捕获这个异常,那么这个异常对象将会异常终止。

3.如何对待异常

对于程序出现的异常,一般有两种解决方法;一就是遇到错误就终止程序的运行。另一种方法是程序员在编写程序时,就充分考虑到各种可能发生的异常和错误,极力预防和避免。实在无法避免,要编写相应的代码进行检测、以及异常处理,保证代码的健壮性。

4.异常体系结构

①java.lang.Throwable
异常体系的根父类
②Error和Exception
Error: JAVA虚拟机无法解决的严重错误。如:jvm系统内部错误、资源耗尽等严重情况。一般不编写针对性的代码进行处理。
例如:stackOverflowError(栈内存溢出)和OutOfMemoryError(堆内存溢出,简称OOM)
Exception: 其他因为编程错误或者偶然外在因素导致的一般性问题,需要使用针对性的代码进行处理,使程序继续运行。否则一旦发生异常,程序也会挂掉。例如:
空指针访问
试图读取不存在的文件
网络连接中断
数组角标越界

编译时异常和运行时异常:
常见的异常
编译时异常:ClassNotFoundException、FileNotFoundExc、IOException
运行时异常:ArrayIndexOutOfBoundException、NullPointerException、ClassCastException、NumberFormatException、InputMismactchException

5.异常的处理

①异常捕获(try-catch-finally)
过程一(抛):
程序在执行过程中,一旦出现异常,就会在出现异常的代码处,生成对应的异常类型,并将此对象抛出。一旦抛出,此程序就不执行其后的代码了。
过程二(抓):
针对过程一中抛出的异常进行捕获。此捕获处理过程,称为抓,一旦将异常进行了处理,代码就可以继续执行。
基本结构

try {
//可能产生异常的代码
}catch (异常类型 e){
//当产生异常时的处理措施
}finally {
//无论是否发生异常都会执行
}

提问:什么样的代码我们一定要申明在finally中呢?
我们在开发中,有一些资源(比如:输入流、输出流、数据库连接、socket等资源),在使用完以后,必须显式的进行关闭操作,否则,GC不会自动的回收这些资源,进而导致内存泄漏
为了保证这些资源在使用完以后,不管是否出现了未被处理的异常情况下,这些资源都被关闭。我们必须将这些操作声明在finally中!

②throws+异常类型

①格式:在方法的声明,使用“throws 异常类型1,异常类型2…”

②举例:

public void test() throws 异常类型1,异常类型2,...{
	//可能存在编译时异常
}

③是否真正处理了异常?
从变异的角度看,看成了是给出了异常万一是要出现的时候的解决方案,此方案就是继续向上抛。
但是throws的方式,仅仅是将可能出现的异常抛给此方法的调用者,此调用者仍然需要考虑如何处理相关异常。

④方法重写的要求
子类重写的方法抛出的异常类型可以与父类被重写的方法抛出的异常类型相同或是父类被重写的方法抛出的异常类型的子类。

⑤开发中,如何选择异常处理的两种方式?
1.如果程序代码中,涉及到资源的调用(流、数据库连接、网络连接等),则必须考虑使用try-catch-finally
2.如果父类被重写的方法中没有throws异常类型,则子类重写的方法中如果出现异常,只能考虑try-catch-finally
3.开发中,方法a中依次调用了方法b,c,d等方法,方法b,c,d之间是递进关系。此时,如果方法b,c,d中有异常,我们通常选择throws,而方法a中通常选择使用try-catch-finally

6.手动抛出异常

①为什么需要手动抛出异常
在实际开发中,如果出现不满足具体场景的代码问题,我们就有必要抛出一个指定类型的异常

public class OverrideTest {
    public static void main(String[] args) {
        Student s1=new Student();
        s1.regist(10);
        //抛出异常
        s1.regist(-10);
    }
}

class Student{
    int id;

    public void regist(int id){
        if(id>0){
            this.id=id;
        }else {
            throw new RuntimeException("输入的id非法");
        }
    }
}

②如何理解“自动 vs 手动”抛出的异常
过程1:“抛”
“自动抛”:程序在执行的过程中,一旦出现异常,就会在出现异常的代码处,自动生成对应异常的对象,并将此对象抛出
“手动抛”:程序在执行的过程中,不满足指定的情况下,我们主动的使用throw的方式抛出异常对象

过程2:“抓”
狭义上将:try-catch的方式捕获异常,并处理
广义将:把“抓”理解为“处理”。则此时对应着异常处理的两种方式:1.try-catch 2.throws

③如何实现手动抛出异常
在方法内部,满足指定条件的情况下,使用 throw异常类的对象的方式抛出

④注意点:throw后的代码不能被执行,编译不通过。

⑤面试题:throw 和 throws的区别
throws 是在使用在方法的申明出,表示把产生的异常向上抛出,属于异常处理的方式。
throw是使用在方法内部,表示把异常抛出。

7.自定义异常

①如何自定义异常类
1.继承于现在的异常体系。通常继承于RunTimeException\Exception
2.通常提供几个重载构造器
3.提供一个全局常亮,声明为:static final long serialVersionUID

public class BelowZeroException extends Exception{

    //唯一表示异常类
    static final long serialVersionUID=-1649496365964L;

    public BelowZeroException(){

    }

    public BelowZeroException(String name){
        super(name);
    }

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

②如何使用自定义异常
在具体的代码中,满足指定条件的情况下,需要手动的使用“throw + 自定义异常对象”方式,将异常抛出。
如果自定义异常类时非运行时异常,则必须考虑如何处理此异常类对象

③为什么需要自定义异常类?
我们其实更关心异常的名称就能判断此异常出现的原因。尽然如此,我们就有必要在实际开发场景中,不满足我们指定的条件时,指明我们自己特有的异常类,通过异常类的名称,就能判断出具体出现的问题(见名知意)

你可能感兴趣的:(java学习记录,java,开发语言,异常)