深入浅出详细介绍Java异常,让你茅塞顿开般的感觉

深入浅出详细介绍Java异常,让你茅塞顿开般的感觉,第1张

深入浅出详细介绍Java异常,让你茅塞顿开般的感觉

零基础学习之Java异常
    • 概述
    • 基本介绍
      • Error
        • 代码示例
      • Exception
        • 代码示例
    • 异常的处理
      • throw
        • 代码示例
      • throws
        • 代码示例
      • try…catch
        • 代码示例
    • finally块
      • 代码示例
      • finally与return(面试)
        • 形式一:从try回来
        • 形式二:从catch回来
        • 形式三:从finally回来
    • 自定义异常
      • 基本介绍
      • 代码示例
    • 异常注意事项

概述

正如“人无完人”一样,程序也不是完美的,它总会存在这样那样的问题,而有些问题并不是能够通过程序员开发更好的代码来解决的,如果我们忽视它,可能就会造成程序的终止,甚至是系统的崩溃。因此,我们需要想办法来合理的解决它,这就是Java中异常的由来。

异常是指程序在执行过程中,出现的非正常情况。比如:空的引用、数组下标越界、内存溢出错误、读取文件不存在、网络断开等

一般来说有两种方法来处理异常:

  • 遇到错误就终止程序运行;
  • 开发人员在编写程序的时候考虑到可能出现的非正常情况,提前做好处理(这个是最好的,不过也是不容易的);

那究竟异常有哪些?常见的处理方法是什么?我想通过下面的文章,你一定可以得到想要的答案!

基本介绍

在Java这样一个面向对象的语言中,异常被当成了一个对象来处理。其根类是java.lang.Throwable类,Throwable类有分成了两个类,即Error和Exception。这是异常的两个大类,他们分别代表了两种情况:

  • Error:不能处理的错误,这是系统内部的错误,运行时报错,属于系统问题。一般发生这种异常,JVM会选择终止程序,开发人员需要提前避免。
  • Exception:可以处理的异常,这是比较常见的异常,开发人员可以根据Java提供的类和问题对这类异常进行处理。


Error和Execption包括很多种情况,这才是我们需要考虑的,下面对它们进行分别介绍。

Error

对于严重错误Error,没有办法处理,只能做到提前避免。常见的Error有:StackOverflowError(内栈溢出错误)和OutOfMemoryError (内存溢出错误)。

代码示例

OutOfMemoryError

Java中堆是用来存储对象实例的,,因此如果我们不断地创建对象, 并且对象没有被垃圾回收, 那么当创建的对象过多时, 会导致 heap 内存不足, 进而引发 OutOfMemoryError 异常.


public class Heap{

    public static void main(String[] args){

		//创建数组list,用来保存对象
        List list = new ArryList<>();
        int i=0;
        while(true){
        	//不断创建对象
            list.add(i++);
        }
    }
}

StackOverflowError
JVM 的运行时数据区中有一个叫做栈的内存区域, 此区域的作用是: 每个方法在执行时都会创建一个栈帧, 用于存储局部变量表、 *** 作数栈、方法出口等信息。因此当创建一个无限递归的递归调用, 当递归深度过大时, 就会耗尽栈空间, 进而导致了 StackOverflowError 异常.


public class Stack{

    public static void main(String[] args){
    	//调用方法
        new Stack().test();
    }

	//创建测试方法
    public void test() {
    //自己调用自己(递归调用)
        test();
    }
}
Exception

一般来说,我们所说的异常就是指Exception,因为这类异常一旦出现,我们就要对代码进行更正,修复程序进行处理。根据在编译时期还是运行时期去检查异常,可以将Exception分为:

  • 编译时期异常:checked异常。在编译时期,就会检查,如果没有处理异常,则编译失败(开发工具会提示),如文件找不到异常等。
  • 运行时期异常:runtime异常。在运行时期,检查异常.在编译时期,运行异常不会被编译器检测到(不开发工具不会提示),如空指针异常,类型转换异常,数字 *** 作异常,类型不匹配异常等。
代码示例

编译时异常这里就不举例了,在开发工具里会标红提示。下面是常见的运行时异常代码示例。

package com.atguigu.demo;

import org.junit.Test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class Demo1 {

    
    //文件找不到
    @Test
    public void test07()  {
   		 //这里FileInputStream报红,编译异常,需要处理
        FileInputStream fis = new FileInputStream("Java异常学习笔记.txt"); 
    }

    
    public static void main(String[] args) {
          //类型不匹配异常
            Scanner input = new Scanner(System.in);
            System.out.print("请输入一个整数:");
            //这个时获取控制台的输入,如果输入的不是整数,则报类型不匹配异常
            int num = input.nextInt();

    }
    //空指针异常
    @Test
    public void testNullPointerException() {
        String[] names = new String[5];
        System.out.println(names[0].length());//字符串的长度
    }

    //类型转换异常
    @Test
    public void testClassCastException() {
        Object obj = new Object();
        String str = (String) obj;
    }

    //数学 *** 作异常异常
    @Test
    public void testArithmeticException(){
        int i = 1/0;
    }

}

异常的处理

既然Java程序异常是非常常见的,那我们该如何处理它呢。由于Java将异常作为对象来处理,因此我们可以将Java异常的处理分成三个部分:

  • Java程序出现异常时会生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。
  • Java程序出现异常时将问题标识出来,报告给调用者,让调用者去处理。这个过程通过throws进行声明。
  • Java程序出现异常时,在方法中使用try-catch的语句块来处理异常。
throw

Java程序出现异常时会生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。异常对象的生成有两种方式:

  • 自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例对象并抛出——自动抛出
  • 手动创建:Exception exception = new ClassCastException();——创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样,但是一旦throw抛出,就会对程序运行产生影响了。

使用格式:

throw new 异常类名(参数);
代码示例
package com.atguigu.demo;

public class Demo2 {

    public static void main(String[] args) {
        //定义数组和访问的角标
        int[] arr = {1,2,3,4};
        int index = 4; //测试数组越界异常
//        int[] arr = {1,2,3,4}; //为null,测试空指针异常
        
        //调用方法测试
        int element = getElement(arr, index);
        System.out.println(element);
    }

    public static int getElement(int[] arr, int index) {
        
        //判断数组为空异常
        if (arr == null){
            throw new  NullPointerException("数组为空!");

        }

        //判断数组越界异常
        // 数组最大下标 arr.length-1
        if (index < 0 || index > arr.length -1){
            throw new ArrayIndexOutOfBoundsException("角标越界!");
        }
        int element = arr[index];
        return element;
    }
}

throws

Java程序出现异常时将问题标识出来,报告给调用者,让调用者去处理。这个过程通过throws进行声明。关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(如果调用者不处理,则接着抛出异常).(不主动处理的方式,甩锅给别人)

声明异常格式:

修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{   }	//可以声明多个异常(也可直接一个Exception)
代码示例
package com.atguigu.demo;

public class Demo4 {
		//声明一个Exception 
    public static void main(String[] args) throws Exception {
        method();//不能直接调用,必须接着声明异常或者处理异常,否则编译不通过
    }

	//声明多个异常
    public static void method() throws 
    NullPointerException,ArrayIndexOutOfBoundsException{
        System.out.println("声明异常!");
    }
}
try…catch

Java程序出现异常时,在方法中使用try-catch的语句块来处理异常。try-catch的方式就是捕获异常:Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理。(主动处理的方式,不甩锅给别人)

捕获异常语法如下:

try{
     //可能会出现异常的代码放在这里
}catch(异常类型  e){
     //处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}catch(异常类型  e){
     //处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}
...

注意: try和catch都不能单独使用,必须连用(除非有finally,后面说)。
catch可以有好几个,即可以捕获几个异常

代码示例
package com.atguigu.demo;


public class Demo5 {
    public static void main(String[] args) {

            //获取方法异常信息
            try {
                //正常执行代码
                add();
            } catch (Exception e) {
                //捕获异常
                System.out.println("异常.......");
//            String message = e.getMessage();
//            System.out.println(message);
                e.printStackTrace();
            }
            //多个异常捕获
//        catch(ArrayIndexOutOfBoundsException a) {
//
//        }
        }

        //声明异常
        public static void add() throws Exception {
            //System.out.println("add......");
            int i = 1 / 0;
        }
}

finally块

在上述的try中,如果出现了异常,则异常后面的语句就不执行,但有些特定的语句是需要必须执行的。因此就需要finally块就是解决这个问题的,这是因为在Java中finally代码块中存放的代码都是一定会被执行的。

当在try语句块中打开了一些物理资源(磁盘文件/网络连接/数据库连接等),我们都得在使用完之后关闭打开的资源。

finally的语法:

 try{
     
 }catch(...){
     
 }finally{
     //无论try中是否发生异常,也无论catch是否捕获异常,也不管try和catch中是否有return语句,都一定会执行
 }
 
 或
  try{
     
 }finally{
     //无论try中是否发生异常,也不管try中是否有return语句,都一定会执行
 } 
代码示例
package com.atguigu.demo;

public class Demo6 {
    public static void main(String[] args) {
        try{
            System.out.println("程序开始执行了");
            int i = 1/0;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            System.out.println("这段代码总会执行");//这里没有写前面说的资源情况,主要为了方便理解
        }
    }
}

finally与return(面试) 形式一:从try回来
public class TestReturn {
	public static void main(String[] args) {
		int result = test("12");
		System.out.println(result);
	}

	public static int test(String str){
		try{
			Integer.parseInt(str);
			return 1;
		}catch(NumberFormatException e){
			return -1;
		}finally{
			System.out.println("test结束");
		}
	}
}
形式二:从catch回来
public class TestReturn {
	public static void main(String[] args) {
		int result = test("a");
		System.out.println(result);
	}

	public static int test(String str){
		try{
			Integer.parseInt(str);
			return 1;
		}catch(NumberFormatException e){
			return -1;
		}finally{
			System.out.println("test结束");
		}
	}
}
形式三:从finally回来
public class TestReturn {
	public static void main(String[] args) {
		int result = test("a");
		System.out.println(result);
	}

	public static int test(String str){
		try{
			Integer.parseInt(str);
			return 1;
		}catch(NumberFormatException e){
			return -1;
		}finally{
            System.out.println("test结束");
			return 0;
		}
	}
}
自定义异常 基本介绍

异常的情况有非常多,因此Java内部并不能把这些都包含进去,这就需要开发人员根据自己的实际业务情况进行自定义异常。比如年龄负数问题,考试成绩负数问题等等。

异常类如何定义:

  • 自定义一个编译期异常::自定义类 并继承于 java.lang.Exception。
  • 自定义一个运行时期的异常类:自定义类 并继承于 java.lang.RuntimeException。
代码示例
package com.atguigu.demo;

public class Demo7 {
    public static void main(String[] args){
        try {
            new Input().method();
        }
        catch(WrongInputException wie) {
            System.out.println(wie.getMessage());
        }
    }
}
// 自定义的类继承Exception
class WrongInputException extends Exception {  
    WrongInputException(String s) {
        super(s);
    }
}
class Input {
    void method() throws WrongInputException {
     // 抛出自定义的类
        throw new WrongInputException("Wrong input");
    }
}

异常注意事项

多个异常使用捕获又该如何处理呢?

  1. 多个异常分别处理。
  2. 多个异常一次捕获,多次处理。(推荐)
  3. 多个异常一次捕获一次处理。

注意:多个异常一次捕获,多次处理的方式,要求多个catch中的异常不能相同,并且若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。

  • 运行时异常被抛出可以不处理。即不捕获也不声明抛出。

  • 如果finally有return语句,永远返回finally中的结果,避免该情况.

  • 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。

  • 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5691186.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存