1.异常概述与异常体系结构
在使用计算机语言进行项目开发的过程中,即使程序员把代码写的尽善尽美,在系统的运行过程中仍然会遇到一些问题,因为很多问题不是靠代码就可以避免的。比如:客户输入数据的格式
,读取文件是否存在
,网络是否始终保持通畅
等。
1.1 异常
再Java语言中,将程序执行过程中发生的不正常情况称为“异常”。(在开发过程中的语法错误和逻辑错误不是异常啊)
1.2.异常分类
1.2.1 Error
Java虚拟机无法解决的问题。如:JVM系统内部错误、资源耗尽等严重情况。
比如:StackOverflowError 和 OOM。一般不编写针对性的代码处理
1.2.2 exception
其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。比如:
空难指针访问;
试图读取不存在的文件;
网络连接中断;
数组角标越界
2.常见异常
在Java中,常见的异常包括运行时异常和非运行时异常。
2.1.运行时异常
运行时异常是指在程序运行过程中可能出现的异常,编译器不会强制要求处理这些异常。常见的运行时异常包括:
- NullPointerException(空指针异常):当一个对象引用为null时,调用该对象的方法或访问其属性会抛出该异常。
- ArrayIndexOutOfBoundsException(数组越界异常):当访问数组中不存在的索引时,会抛出该异常。
- ArithmeticException(算术异常):当进行除法运算时,除数为0会抛出该异常。
- ClassCastException(类转换异常):当试图将一个对象强制转换为不是其子类的类型时,会抛出该异常。
2.2.非运行时异常
非运行时异常是指在程序运行过程中可能出现的异常,编译器会强制要求处理这些异常。常见的非运行时异常包括:
- IOException(输入输出异常):当发生输入输出错误时,会抛出该异常。
- FileNotFoundException(文件未找到异常):当试图打开一个不存在的文件时,会抛出该异常。
- ClassNotFoundException(类未找到异常):当试图加载不存在的类时,会抛出该异常。
- SQLException(SQL异常):当操作数据库发生错误时,会抛出该异常。
这些是Java中常见的异常,根据具体的情况,我们可以使用try-catch语句来捕获并处理这些异常。
3.异常处理机制一:try-catch-finally
3.1.try
try:尝试
将有可能出现异常的代码 使用try包括起来
try不能单独出现,必须结合catch或者finally来使用
package com.yc.test1;
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* 使用Java异常处理机制来处理异常
* try:尝试
* 将有可能出现异常的代码 使用try包括起来
* try不能单独出现,必须结合catch或者finally来使用
* catch:捕获
* 表示出现异常并且捕获到该异常将会执行的代码块
*
* 处理异常情况1:
* 使用try-catch捕获到出现的异常
*/
public class Test2 {
public static void main(String[] args) {
try {
Scanner in = new Scanner(System.in);
System.out.print("请输入被除数:");
int num1 = in.nextInt();
System.out.print("请输入除数:");
int num2 = in.nextInt();
System.out.println(num1+"/"+ num2 +"="+ num1/ num2);
}catch(ArithmeticException e) {
System.err.println("出现了输入不匹配异常");
e.printStackTrace();
System.out.println(e.getMessage());
}
System.out.println("感谢使用本程序!");
}
}
2.catch:捕获
表示出现异常并且捕获到该异常将会执行的代码块
处理异常情况2:
使用try-catch
捕获多种异常
我们可以定义一个父类Exception来捕获到所有的异常,但是这样书写不利于代码阅读
我们推荐使用精确的异常类型来catch,书写多个catch 先子类 再父类
package com.yc.test1;
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test3 {
public static void main(String[] args) {
try {
Scanner in = new Scanner(System.in);
System.out.print("请输入被除数:");
int num1 = in.nextInt();
System.out.print("请输入除数:");
int num2 = in.nextInt();
System.out.println(num1+"/"+ num2 +"="+ num1/ num2);
}catch(ArithmeticException e) {
System.err.println("出现了算数运算异常");
e.printStackTrace();
}catch(InputMismatchException e) {
System.err.println("出现了输入不匹配异常");
e.printStackTrace();
}
System.out.println("感谢使用本程序!");
}
}
3.3.finally
finally :最终
用于表示不管是否出现异常,不管异常是否被捕获到,都将执行的代码finally不能单独出现 必须结合try或者 try-catch
package com.yc.test2;
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test2 {
public static void main(String[] args) {
try {
Scanner in = new Scanner(System.in);
System.out.print("请输入被除数:");
int num1 = in.nextInt();
System.out.print("请输入除数:");
int num2 = in.nextInt();
System.out.println(num1+"/"+ num2 +"="+ num1/ num2);
System.exit(1); // 退出JVM虚拟机
}catch(InputMismatchException e) {
System.exit(0); // 退出JVM虚拟机
e.printStackTrace();
}finally {
System.out.println("感谢使用本程序!");
}
}
}
3.4 finally面试题
- 不要在finally内 对返回值做操作
- 不要在finally内 return值
- finally中对返回值的操作 不会改变catch或者try中的return值
package com.yc.test3;
public class Test2 {
public static void main(String[] args) {
System.out.println(getNum());
}
public static int getNum() {
int num = 10;
try {
num++;
System.out.println(num / 0);
return num; // 这里return值 num为11 表示返回值已经固定了
} catch (Exception e) {
num ++;
}finally {
num++;
}
return num;
}
}
4. 手动抛出异常:throw
throw用于表示抛出异常,可以作为一条语句单独使用,抛异常之后不能再写代码,每一句只能抛出一个异常
package com.yc.test4;
import java.io.FileNotFoundException;
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* 运行时异常和检查异常
* RuntimeException和其子类 称之为运行时异常,方法声明了运行时异常,调用者不是必须处理;
* 除了RuntimeException和其子类 其他的都称之为检查异常。方法声明了检查异常,调用者必须处理。
*/
public class Test1 {
public static void main(String[] args) {
try {
m1();
} catch (InputMismatchException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ArithmeticException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
m2();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static void m1() throws ArithmeticException,InputMismatchException {
Scanner in = new Scanner(System.in);
System.out.print("请输入被除数:");
int num1 = in.nextInt();
System.out.print("请输入除数:");
int num2 = in.nextInt();
System.out.println(num1+"/"+ num2 +"="+ num1/ num2);
System.out.println("欢迎使用程序");
}
/**
* CheckedException 检查异常
* @throws ClassNotFoundException
*/
public static void m2() throws ClassNotFoundException,FileNotFoundException {
}
}
5.异常处理机制二:throws
throws表示声明异常,书写在形参列表之后,可以声明多个异常,多个异常使用逗号分隔,表示本方法有可能出现的异常
throws : 抛的复数形式。用于表示声明本方法可能会出现的异常 通知给调用者;
调用者可以:
1. 使用try-catch处理
2. 继续声明给JVM虚拟机
- throw和throws的区别:
throw用于表示抛出异常,可以作为一条语句单独使用,抛异常之后不能再写代码,每一句只能抛出一个异常;
throws表示声明异常,书写在形参列表之后,可以声明多个异常,多个异常使用逗号分隔,表示本方法有可能出现的异常。
package com.yc.test4;
public class Test2 {
public static void m1(int a) {
if(a % 2 == 0) {
System.out.println("条件成立");
}else {
throw new ArithmeticException("毫无意义的算数运算异常");
}
}
public static void m2(int a) throws ClassNotFoundException {
if(a % 2 == 0) {
System.out.println("条件成立");
}else {
throw new ClassNotFoundException("毫无意义的类找不到异常");
}
}
}
6.用户自定义异常
JDK提供的异常有时候不能满足开发需求,我们可以自己定义异常。
我们可以自定义类继承Exception或者RuntimeException来实现异常定义
package com.yc.test5;
public class InputAgeException extends RuntimeException{
private static final long serialVersionUID = 1L;
public InputAgeException(String message) {
super(message);
}
}
package com.yc.test5;
public class SetAgeException extends Exception{
private static final long serialVersionUID = 1L; // 序列化ID
public SetAgeException(String message) {
super(message);
}
}
package com.yc.test5;
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge1(int age) throws SetAgeException {
if(age >= 0 && age <= 130) {
this.age = age;
}else {
throw new SetAgeException("年龄必须在1~130之间");
}
}
public void setAge2(int age) {
if(age >= 0 && age <= 130) {
this.age = age;
}else {
throw new InputAgeException("年龄必须在1~130之间");
}
}
public static void main(String[] args) {
Student stu1 = new Student();
stu1.setName("赵四");
try {
stu1.setAge1(-112);
} catch (SetAgeException e) {
e.printStackTrace();
}
stu1.setAge2(-220);
}
}