Java 异常


第七章、异常

Java 语言中,将程序执行中发生的不正常情况称为“异常”。

1. 异常体系

image

Error(错误):

Java 虚拟机无法解决的严重问题,如:JVM 系统内部错误、资源耗尽等严重情况。比如:StackOverflowError[栈溢出]和OOM(out of memory),Error 是严重错误,程序会崩溃。

Exception:

其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问,试图读取不存在的文件,网络连接中断等待,Exception 分为两大类:运行时异常[程序运行时,发生的异常]和编译时异常[编译时,编译器检查出的异常]。

运行时异常,编译器检查不出来。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。对于运行时异常,可以不做处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。编译时异常,时编译器要求必须处理的异常。

2. 如何处理异常

在 Java 中,把异常信息封装成了一个类。当出现了问题时,就会创建异常类对象并抛出异常相关的信息(如异常出现的位置、原因等)。

处理异常的方式:

1)手动去修改有问题的代码

2)使用debug去调试代码

3)使用判断选择结构去修改代码:if...else

弊端:

1)手动改代码,不靠谱,你怎么知道哪里会发生异常?

2)使用选择结构,太繁琐,不好维护

解决问题:

使用 java 提供的异常处理机制,来处理和捕获异常,保证程序的正常运行,提高程序的健壮性和可维护性。

3. java常见异常分类

Throwable类: Throwable 类是Java语言中所有错误和异常的超

类。

​ |— 子类error : 一个 Error 是的子类Throwable 表示严重的问

题。该问题程序员是无法处理的,没有办法解决,一般不处理该问题。

|--- 子类 `Exception` : `异常` 及其子类是 `Throwable` 的形式,表示合理应用程序可能想要捕获的条件。该问题,程序员可以进行处理,捕获异常。

		| --- checked异常/检查异常/编译期异常:程序员可以在写代

码的时候,可以发现的异常,代码有红色波浪线

​ |—RuntimeException: 运行期异常/非检查异常:该异常在编

译期不报错的,只有在程序运行的时候,才会出现异常,该异常要捕获!

4. 常见异常处理机制有哪些?

1)jvm 默认有一套异常处理的方式。

2)使用 try – catch :异常捕获机制

使用 tay – catch 来捕获异常,来对异常进行处理

语法

try{
    //可能会发生异常的代码
}catch(异常类型 变量名){ //对异常进行处理
    
}

快捷键:先写代码,然后选中代码,按 ctrl+alt+T,再选 try…catch

3)多重 catch

通过多重 catch,可以捕获具体的异常。

注意问题:

1)使用多个 catch 来捕获异常

2)catch 执行是有顺序的,一般范围小的异常,放在最前,最后写Exception

3)异常捕获成功之后,只会捕获一次异常,会结束 try…catch,继续执行后面的程序

4)catch 中的异常的变量名,可以重复,没有影响

4)try-catch-finally

finally:可以写,也可以不写;如果写了,那么finally中的代码,会执行。

一般应用于:I/O流,jdbc操作,关闭流,关闭连接

语法:

try{
    //可能会发生异常的代码
}catch(异常类型 变量名){ //对异常进行处理
    
}finally{
    //默认自动执行
}

细节问题:

  1. 如果代码正常运行,那么程序一定会执行 finally 中的代码。
  2. 如果代码出现了异常,那么先执行 catch 中的代码,然后再执行 finally 中的代码。(try 中的发生异常位置之后的代码,不会再执行了)
  3. 如果代码正常运行,try 中有 return ,那么会先执行 finally 中的代码,然后再 return;
  4. 如果代码出现了异常,并且 try 中有 return ,那么遵循规则2;
  5. finally 唯一不会执行情况:System.exit(0):强制退出

案例

package com.xunfang.homework.topic03;

import java.util.InputMismatchException;
import java.util.Scanner;

public class NewDivide {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            System.out.print("请输入被除数:");
            int num1 = input.nextInt();
            System.out.print("请输入除数:");
            int num2 = input.nextInt();
            System.out.println("num1 / num2 = " + num1/num2);
//            System.exit(0);
//            return;
        } catch (InputMismatchException e){
            e.printStackTrace();
            System.err.println("被除数和除数必须是整数");
        }catch (ArithmeticException e){
            e.printStackTrace();
            System.err.println("除数不能为零");
        } catch (Exception e) {
            //打印异常的堆栈信息- 什么异常,异常发生的位置
            e.printStackTrace();
            //err:打印的颜色会变成红色
            System.err.println("程序发生了异常");
        }finally {
            System.out.println("感谢使用本程序!");
        }
        System.out.println("程序继续运行...");
    }
}

5)声明异常 throws

throws:抛出异常,表示该位置可能发生异常,但是不具体处理,让后面的程序去处理异常。

语法:

//表示当前的方法,抛出了什么异常!
...方法名() throws 异常类型1,异常类型2,...{
    
}

异常抛出的处理方式:

//1.main方法捕获异常 - 这种方式
//2.main也不想捕获,摆烂,抛出异常。(JVM的默认方式)

6)Exceptiion 的所有的异常类分类如何划分:

运行时异常:

RuntimeException – 父类

常见的运行时异常:

异常 解释
NullPointerException 空指针异常
ArithmeticException 算术异常
ClassCastException 类型强制转换异常
ArrayIndexOutOfBoundsException 数组下标越界异常
StringIndexOutOfBoundsException 字符串索引越界异常
InputMismatchException 控制台输入类型错误异常

编译时异常:

写代码的时候,红色波浪线。

常见的编译时异常:

异常 解释
FileNotFoundException 文件未找到异常
ClassNotFoundException 无法找到指定的类异常
SQLException 操作数据库异常
IOException 输入输出异常
NumberFormatException 字符串转换为数字异常
NoSuchMethodException 方法未找到异常

细节问题:

1、在代码的运行过程中,发生的异常,需要捕获

2、在代码的编写过程中,发生的异常,一般表现为红色波浪线

7)抛出异常 throw

表示 程序员 认为该位置 肯定会有异常,进行手动抛出异常。

语法:

throw new 异常类型("xxx")

8)throw 和 throws 有何区别???

  1. throws:声明异常,表示可能会有异常,写在方法名的后面,把异常抛出,后面代码处理。
  2. throw:手动抛出异常,表示肯定会员异常,写在带啊吗中,把异常抛出,后面代码处理
package com.xunfang.demo.demo2;

public class Person {
    private String name;
    private int age;
    private char sex;

    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 >= 16 && age <= 32){
            this.age = age;
        }else {
            throw new Exception("年龄不合法!!!");
        }
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) throws Exception {
        if (sex == '男' || sex == '女') {
            this.sex = sex;
        } else {
            throw new Exception("性别不合法!!!");
        }
    }
}


package com.xunfang.demo.demo2;

import java.util.Scanner;

public class PersonTest {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        Person person = new Person();
        System.out.print("请输入姓名:");
        person.setName(input.next());
        try {
            System.out.print("请输入年龄:");
            person.setAge(input.nextInt());
            System.out.print("请输入性别:");
            person.setSex(input.next().charAt(0));
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("程序继续执行");
    }
}

5. 程序强制退出的方式

System.exit(0)

6. 程序强制退出和 return 的区别?

程序强制退出:结束程序

return:方法返回

7. 异常在方法重写中细节

子类关系中,使用异常

1)如果父类方法抛出异常,子类可以不抛出异常

2)子类不能比父类抛出的异常范围大

3)子类可以比父类抛出的异常类型多

public abstract class Father {
    public abstract void show() throws NullPointerException, Exception;
}


public class Son extends Father{

    @Override
    public void show() throws Exception,ArithmeticException,RuntimeException,NullPointerException{
        System.out.println("重写");
    }
}

8. 自定义异常

自定义异常类,要继承Exception类,并重写构造方法

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

    public AgeException(String message){
        super(message);
        System.out.println("这是一个自定义的异常类");
    }
}

public class Person {
    private int age;
    public int getAge() {
        return age;
    }

    public void setAge(int age) throws Exception {
        if (age >= 16 && age <= 60){
            this.age = age;
        }else {
            throw new AgeException("年龄不合法!!!");
        }
    }
}

public class PersonTest {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        Person person = new Person();
        try {
            System.out.print("请输入年龄:");
            person.setAge(input.nextInt());
        } catch (AgeException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("程序继续执行");
    }
}

9. 扩展:Log4j 日志的使用

日志:记录代码操作

Log4j:是一个日志的框架,可以在控制台和日志文件中,体现出后端的代码输出信息,方便我们去查找代码的信息和错误,和日志分析

使用步骤:

1)导入第三方的 jar 包

2)在src目录下,去引入日志的配置文件log4j.properties

配置文件:便是可以实现一些项目的配置信息

配置文件的分类:xx.xml xx.properties xx.yaml xx.yml properties

配置文件的规则:属性1.属性2.xx.xx = 值

3)使用日志的类的对象,来使用日志的操作。

#根logger设置
log4j.rootLogger = INFO,console,file

### 输出信息到控制台###
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%p] %d{yyyy-MM-dd HH:mm:ss} method: %l----%m%n

###输出INFO 级别以上的日志文件设置###
log4j.appender.file = org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File = D:/2022.7.22_test.log
log4j.appender.file.Append = true
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} method: %l - [ %p ]----%m%n

用法:

导包:import org.apache.log4j.Logger;
创建日志对象
public Logger logger = Logger.getLogger(Person.class);
打印日志消息...
logger.info("年龄合法~");


public static Logger logger = Logger.getLogger(Person.class); //注意此处为static
再调用方法:报程序错误,和错误内容
logger.error("程序错误",e);

10. 总结

image

原创文章,作者:6024010,如若转载,请注明出处:https://blog.ytso.com/277668.html

(0)
上一篇 2022年7月29日
下一篇 2022年7月29日

相关推荐

发表回复

登录后才能评论