一、异常

1、异常结构图

java不能处理栈溢出异常类型 java异常堆栈_java不能处理栈溢出异常类型

 二、ERROR

堆栈异常:StackOverflowError

一般发生在方法递归调用(递归调用一般都有一个结束条件,否则就会发生无限递归调用,不停的发生压栈,导致堆栈溢出)

内存溢出:申请了太多内存,而没有释放导致溢出

三、Exception异常

异常的本质?:

1、异常模拟的是现实世界中的不正常的一类事件

2、异常在Java中采用类和对象的形式存在

例如:

java.lang.NullPointerException;一类空指针事件

java.lang.NullPointerException e=0x12;  真是发生在某个空指针异常事件(JVM会创建异常对象)

3、异常在Java中的作用,可以提高程序的健壮性。

 

======第一个异常:运算异常========

“Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.JavaStudy.studyYiChang0527.ExceptionTest01.main(ExceptionTest01.java:11)”

1、异常对象中肯定携带详细的异常信息

2、该程序由JVM将异常信息打印到工作台

3、异常信息很详细,程序员可以通过抛出的异常,修改自己的程序,达到程序的健壮性

package com.JavaStudy.studyYiChang0527;

/**
 java.lang.ArithmeticException(运算异常),此异常是运行时异常而非编译异常,如果是编译异常的话编译器就无法通过
 出现异常的运算条件时,才会抛出运算异常
 ArithmeticException是runtimeException的子类
 */
public class ExceptionTest01 {
    public static void main(String[] args){
//        int a = 5;
//        int b = 0;
//        System.out.println(a/b); //运行结果:Exception in thread "main" java.lang.ArithmeticException: / by zero
//

        int a = 5;
        int b = 0;
        if(b==0){
            System.out.println("b不能为0");
            return;
        }
        System.out.println(a/b);  //执行结果:b不能为0

    }
}

四、异常的详细分类

异常主要分为:错误ERROR,受控异常(编译异常),非受控异常(运行异常)。

错误(ERROR):如果应用程序出现ERROR,那么将无法恢复,只能重新启动应用程序,最典型的错误:OutOfMemaryError

受控异常(编译异常):出现这种异常必须显示的处理,不显示处理Java程序将无法通过

非受控异常(运行异常):此种异常可以不用显示处理。

 

编译时异常发生的几率较高。

要求程序在编译阶段就进行处理

如果不处理程序将无法通过。

五、异常的第一种处理方式:throws

throws(抛出):在方法声明位置上使用throws关键字,如果想让调用程序知道该异常发生了,被调用的程序应该使用throws关键字进行上抛

只要JVM知道了该异常发生了,则一定会打印异常信息,并且结束程序的运行。

========找不到文件异常========

package com.JavaStudy.studyYiChang0527;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/**
 * @Author wufq
 * @Date 2020/5/27 11:14

 */
public class ExceptionTest02 {
    public static void main(String[] args) throws FileNotFoundException {
        //创建一个文字节流
        FileInputStream file = new FileInputStream("/Users/wufq/Desktop/11.txt");

        /*
        因为11.txt文件不存在,在用到FileInputStream类的构造方法时就会抛出"找不到文件"异常,所以JVM在处理的时候就需要抛出此异常到控制台
         */
    }
}

执行结果:
Exception in thread "main" java.io.FileNotFoundException: /Users/wufq/Desktop/11.jpj (No such file or directory)
    at java.io.FileInputStream.open0(Native Method)

2、深入throws(逐层上抛)

package com.JavaStudy.studyYiChang0527;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class ExceptionTest02 {


    public static void main(String[] args) throws FileNotFoundException {
        ExceptionTest02 t = new ExceptionTest02();
        t.m3();
    }

    public  void m3() throws FileNotFoundException {
        m2();
    }

    public  void m2() throws FileNotFoundException {
        m1();
    }

    public  void m1() throws FileNotFoundException {
        FileInputStream file = new FileInputStream("/Users/wufq/Desktop/11.jpj");
    }

}

六、处理异常的第二种方式

捕捉:try...catch...如果不想让调用程序知道该异常发生,被调用的程序应该使用try...catch...进行捕捉异常

语法格式:

try{

  可能出现异常的语句

  Java语句1;//如果该语句出现异常,则try语句块停止执行,直接进入catch语句块执行。

  Java语句2;

}catch(异常类型1  变量名){

  处理异常的Java语句

}catch(异常类型2 变量名){

  处理异常的Java语句

}

1、catch语句是可以编写多个的

2、catch语句只执行一次,整个try...catch...就结束了

3、catch可以捕捉多个异常,但是必须从上到下,从小到大捕捉

package com.JavaStudy.studyYiChang0527;

/**
 * @Author wufq
 * @Date 2020/5/27 17:23
 */
public class ExceptionTest03 {
    public static void main(String[] args){
        int a = 5;
        int b = 0;

        try{
            //try里面是出现异常的代码,不出现异常的代码最好不用放到try里面
            int c =a/b;
            //当0被除异常,程序流会执行到catch(ArithmeticException e)语句,被0除的表达式永远不会被执行
            System.out.println(c);


            //e是一个引用,数据类型为ArithmeticException(继承运行异常)
        }catch(ArithmeticException e){
            System.err.println(e.getMessage()); //getMessage()是ArithmeticException类的方法,用于返回详细的字符串
        }

        System.out.println(a);
    }
}
package com.JavaStudy.studyYiChang0527;

/**
 * @Author wufq
 * @Date 2020/5/28 09:42
 */
public class ExceptionTest04 {
    public static void main(String[] args){
        int a = 10;
        int b = 0;

        try{
            int c = a/b;
            System.out.println(c);
        }catch(ArithmeticException e){
            e.printStackTrace();
        }

        System.out.println(a);
    }
}java.lang.ArithmeticException: / by zero
    at com.JavaStudy.studyYiChang0527.ExceptionTest04.main(ExceptionTest04.java:13)


=====执行结果====
java.lang.ArithmeticException: / by zero
    at com.JavaStudy.studyYiChang0527.ExceptionTest04.main(ExceptionTest04.java:13)

七、自定义异常

1、自定义非受控异常(即:编译异常)

package com.JavaStudy.studyYiChang0527;

public class ExceptionTest05 {
    public static void main(String[] args){
        try{
            m(10,0);
        }catch (Mexception e){
            e.printStackTrace();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //自定义子类的异常
    /*
    throws是方法声明处的关键字,抛出的是异常类型
    方法体异常的抛出用的是throw,抛出的是异常对象
     */
    public static void m (int value1,int value2) throws Mexception{
        if(value2 == 0){
            throw new Mexception("除数为0");
        }

        int value3 = value1/value2;
        System.out.println(value3);
    }
}

//自定义非受控异常
class Mexception extends RuntimeException{
    //缺省构造器
    Mexception(){
        super(); //super()子类调用父类的构造方法并给父类赋值
    }
    Mexception(String message){
        super(message);
    }
}

2、自定义受控异常(即:编译异常)

package com.JavaStudy.studyYiChang0527;

/**
 * @Author wufq
 * @Date 2020/5/28 14:54
 */
public class ExceptionTest06 {

    public static void main(String[] args){
        //受控异常(编译异常)和非受控异常(运行异常)的区别就在于:编译异常不加异常的抛出或者捕捉时,是编译不成功的,
        // 但是运行异常就算是不加异常抛出或者捕捉也是可以编译成功的
        try {
            mothod(10,0);
        } catch (MyException e) {
            e.printStackTrace();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static void mothod(int value1,int value2) throws Exception {
        if(value2 == 0 ){
            throw new Exception("除数为0");
        }
        int value3 = value1/value2;
        System.out.println(value3);
    }
}

//自定义受控异常(编译异常)
class MyException extends Exception{
    MyException(){
        super();
    }

    MyException(String message){
        super(message);
    }
}

举例:结合业务场景自定义异常

package com.JavaStudy.studyYiChang0527;

/**
 * @Author wufq
 * @Date 2020/5/28 17:28
 * 判断一个name长度是否满足6位来进行异常的抛出
 */
public class ExceptionTest07 {
    public static void main(String[] args){
        String name = "复仇者联盟4";//执行结果:注册成功
//        String name = "复仇者联盟";//执行结果:IllegalNameException: 长度不足6位,注册失败!
        UserService user = new UserService();
        try {
            user.register(name);
            System.out.println("注册成功,欢迎"+name+"登录");
        } catch (IllegalNameException e) {
            e.printStackTrace();
        }
    }


}
class UserService{
    public void register(String name) throws IllegalNameException {
        if(name.length()<6){
            //方法体内的异常抛出用throw,并且抛出的是对象
            throw new IllegalNameException("长度不足6位,注册失败!");
        }
    }
}

//自定义一个名字无效异常,编译异常
class IllegalNameException extends Exception{
    IllegalNameException(){
        super();
    }

    IllegalNameException(String message){
        super(message);
    }
}

八、finally语句

异常处理机制中的finally语句块

在finally语句块中的程序是一定会执行的

package com.JavaStudy.studyYiChang0527;

/**
 * @Author wufq
 * @Date 2020/5/29 14:36
 */
public class ExceptionTest08 {
    public static void main(String[] args){
        int a=10;
        int b = 0;

        try{
            int c = a/b;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            System.out.println("------finally语句--------");
        }
        
        //异常被处理了,可以执行到此语句
        System.out.println("test");
    }
}

====执行结果====
java.lang.ArithmeticException: / by zero
------finally语句--------
test
    at com.JavaStudy.studyYiChang0527.ExceptionTest08.main(ExceptionTest08.java:13)

 

通常会在finally语句里面写一些关闭流的语句 或者释放资源的语句

1)try和finally可以连用,如果有异常并不会处理异常,但是finally里面的语句一定会被执行

package com.JavaStudy.studyYiChang0527;

/**
 * @Author wufq
 * @Date 2020/5/29 14:50
 */
public class ExceptionTest09 {
    public static void main(String[] args){
        int a=10;
        int b = 0;

        try {
            int c = a / b;
        }finally {
            System.out.println("finally.....");
        }

        //不会执行到此语句,因为异常没有被处理
        System.out.println("test");
    }
}

====执行结果====
finally.....
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.JavaStudy.studyYiChang0527.ExceptionTest09.main(ExceptionTest09.java:13)

2)遇到return后方法停止执行后,finally仍然会执行

package com.JavaStudy.studyYiChang0527;

/**
 * @Author wufq
 * @Date 2020/5/29 14:59
 */
public class ExceptionTest10 {

    public static void main(String[] args){

        try{
            return;
        }finally {
            System.out.println("finally.....");
        }
    }
}

====执行结果=====
finally.....

Process finished with exit code 0

3)退出JVM虚拟机,finally就不会被执行了

package com.JavaStudy.studyYiChang0527;

/**
 * @Author wufq
 * @Date 2020/5/29 15:04
 */
public class ExceptionTest11 {

    public static void main(String[] args){

        try{
            System.exit(0);//退出jvm虚拟机
        }finally {
            System.out.println("finally.....");
        }
    }
}

====执行结果====

Process finished with exit code 0

4)多个异常的处理方式

try调出的快捷方式:option+commond+t

package com.JavaStudy.studyYiChang0527;

import java.io.FileInputStream;
import java.io.IOException;

/**
 * @Author wufq
 * @Date 2020/5/29 15:14
 */
public class ExceptionTest12 {
    public static void main(String[] args){

        //FileInputStream流被称为文件字节输入流,意思指对文件数据以字节的形式进行读取操作
        FileInputStream file = null;

        try {
            file = new FileInputStream("/Users/wufq/Desktop/abcd"); //文件找不到异常
            int a =file.read();//输入输出流异常
            System.out.println(a);//97--->ACSII中a==97
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}