第七章、异常
Java 语言中,将程序执行中发生的不正常情况称为“异常”。
1. 异常体系
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{
//默认自动执行
}
细节问题:
- 如果代码正常运行,那么程序一定会执行 finally 中的代码。
- 如果代码出现了异常,那么先执行 catch 中的代码,然后再执行 finally 中的代码。(try 中的发生异常位置之后的代码,不会再执行了)
- 如果代码正常运行,try 中有 return ,那么会先执行 finally 中的代码,然后再 return;
- 如果代码出现了异常,并且 try 中有 return ,那么遵循规则2;
- 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 有何区别???
- throws:声明异常,表示可能会有异常,写在方法名的后面,把异常抛出,后面代码处理。
- 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. 总结
原创文章,作者:6024010,如若转载,请注明出处:https://blog.ytso.com/277668.html