异常
一般异常代码:
public class Exception01 {
public static void main(String[] args) {
int n1 = 10;
int n2 = 0;
// n1 / n2 => 10 / 0
int res = n1/n2;
System.out.println("程序继续运行……");
}
}
设置了异常捕获(try-catch):
public class Exception01 {
public static void main(String[] args) {
try{
int n1 = 10;
int n2 = 0;
// n1 / n2 => 10 / 0
int res = n1/n2;
} catch (Exception e){
// TODO:handle exception
//e.printStackTrace();//打印异常堆栈,即将异常出错的代码和信息输出
System.out.println("异常信息=" + e.getMessage());
}
System.out.println("程序继续运行……");
}
}
异常介绍
基本概念
Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法
错误和逻辑错误不是异常)
异常事件可分为两类(Error,Exception)
-
Error(错误):Java虛拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如: * Error栈溢出]和ooM( out of
memory),Error是严重错误,程序会崩溃。 -
Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指访问,试图读取不存在的文件,网络连接中
断等等, Exception分为两大类:运行时异常[程序运行时,发生的异常]和编译时异常[编译时,编译器检查出的异常]。
类关系图:
常见运行时异常
-
NullPointerException空指针异常
String name = null; System.out.println(name.length());
-
ArithmeticException数学运算异常
int n1 = 10; int n2 = 0; int res = n1/n2;
-
ArrayIndexOutOfBoundsException数组下标越界异常
int[] arr = {1, 2, 4}; for (int i = 0; i <= arr.length; i++) { System.out.println(arr[i]); }
-
ClassCastException类型转换异常
public class ClassCastException_ { public static void main(String[] args) { A b = new B();//向上转型 B b2 = (B)b;//向下转型,OK的 C c2 = (C)b;//这里会抛出ClassCastException类型转换异常 } } class A {} class B extends A {} class C extends B {}
-
NumberFormatException数字格式不正确异常
String name = "Jack"; //将 String 解析成 int int num = Integer.parseInt(name);
常见编译时异常
- SQLException
- IOException
- FileNotFoundException
- ClassNotFoundException
- EOFException
- IlldgalArgumentException
异常处理
基本介绍
异常处理就是当异常发生时,对异常处理的方式。
异常处理的方式
- try-catch-finally
程序员在代码中捕获发生的异常,自行处理 - throws
将发生的异常抛出,交给调用者来处理,最*的处理者是JVM
try-catch-finally
try{
//代码/可能有异常
} catch (Exception e) {
//捕获异常
//1.当异常发生时
//2.系统将异常封装成Exception对象e,,传递给catch
//3.得到异常对象后,程序员自己处理
} finally {
//没有finally语法也是可以通过的
//不管有没有异常,finally一定要执行
}
throws
异常默认使用throws。
try-finally
直接使用try-finally进行配合,相当于没有捕获异常,因此程序会直接崩溃。应用场景,就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑。
try{
//代码......
} finally {
//总是执行的代码
}
Try机制
TryCatchDetail01.java
使用ctrl + alt + t
快捷键设置try-catch
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7aIbVacn-1644128312071)(.\image\image-20211007084308512.png)]
public class TryCatch01 {
public static void main(String[] args) {
try {
String str = "Jack";
int a = Integer.parseInt(str);
System.out.println("数字:" + a);
} catch (NumberFormatException e) {
System.out.println("异常信息 = " + e.getMessage());
}
System.out.println("程序继续......");
}
}
如果希望不管发生什么都执行某段代码,则使用finally。
可以有多个 catch语句,捕获不同的异常进行不同的业务处理),要求父类异常在后,子类异常在前,比如( Exception在后, NullPointerException在前),如果发生异常,只会匹配一个 catch。
TryCatchDetail02.java
public class TryCatchDetail02 {
public static void main(String[] args) {
try {
Person person = new Person();
person = null;
System.out.println(person.getName());//NullPointerException
int n1 = 10;
int n2 = 0;
int res = n1 / n2;//ArithmeticException
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
}
}
}
class Person{
private String name;
public String getName() {
return name;
}
}
改进后的多异常处理:
子类异常必须放在前面!!!
public class TryCatchDetail02 {
public static void main(String[] args) {
try {
Person person = new Person();
person = null;
System.out.println(person.getName());//NullPointerException
int n1 = 10;
int n2 = 0;
int res = n1 / n2;//ArithmeticException
} catch (NullPointerException e) {
System.out.println("空指针异常: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("算数异常: " + e.getMessage());
} catch (Exception e) {
System.out.println("一般异常: " + e.getMessage());
} finally {
}
}
}
class Person{
private String name;
public String getName() {
return name;
}
}
TryCatchDetail03.java
public class TryCatchDetail03 {
public static void main(String[] args) {
try{
int n1 = 10;
int n2 = 0;
System.out.println(n1 / n2);
} finally {
System.out.println("执行了finally...");
}
//不会继续运行,程序运行完finally后直接崩溃
System.out.println("程序继续运行...");
}
}
TryCatchExercise01.java
public class TryCatchExercise01 {
public static int method(){
try{
String[] names = new String[3];
if(names[1].equals("tom")){//NullPointerException
System.out.println(names[1]);
} else{
names[3] = "hspedu";
}
return 1;
}
catch (ArrayIndexOutOfBoundsException e){
return 2;
}
catch (NullPointerException e){
return 3;
}
//由于finally必须执行,则一定返回4
finally{
return 4;
}
}
public static void main(String[] args) {
System.out.println(method());
}
}
TryCatchExercise02.java
public class TryCatchExercise02 {
public static int method(){
int i = 1;
try{
i++;//2
String[] names = new String[3];
if(names[1].equals("tom")){//NullPointerException
System.out.println(names[1]);
} else{
names[3] = "hspedu";
}
return 1;
}
catch (ArrayIndexOutOfBoundsException e){
return 2;
}
catch (NullPointerException e){
return ++i;//3
}
//由于finally必须执行,则一定返回4
finally{
return ++i;//4
}
}
public static void main(String[] args) {
System.out.println(method());//4
}
}
TryCatchExercise03.java
public class TryCatchExercise03 {
public static int method(){
int i = 1;//1
try{
i++;//2
String[] names = new String[3];
if(names[1].equals("tom")){//NullPointerException
System.out.println(names[1]);
} else{
names[3] = "hspedu";
}
return 1;
}
catch (ArrayIndexOutOfBoundsException e){
return 2;
}
catch (NullPointerException e){
//返回3
return ++i;//3
}
finally{
++i;//4
System.out.println("i = " + i);//i = 4
}
}
public static void main(String[] args) {
System.out.println(method());//3
}
}
TryCatchExercise04 – 用异常捕获获取输入
public class TryCatchExercise04 {
/* 1.创建Scanner
* 2.使用无限循环去接受一个输入
* 3.然后将输入的值转化为int
* 4.如果在转化时抛出异常,则说明输入内容不能转化为int
* 5.如果没有抛出,则break该循环*/
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int num = 0;
while (true) {
System.out.println("请输入一个整数:\n");
try {
num = Integer.parseInt(scanner.next());
break;
} catch (NumberFormatException e) {
System.out.println("输入有误,请重新输入!\n");
}
}
System.out.printf("您的输入为: " + num);
}
}
Throws机制
如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对异常进行处理。
在方法中使用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
Throws01.java
public class Throws01 {
public static void main(String[] args) {
}
//public void f1() throws Exception 也可以
public void f1() throws FileNotFoundException, NullPointerException {
//创建了一个文件流对象
//这里的异常是一个FileNotFoundException
//可以使用try-catch
//也可以使用throws,抛出异常,让调用fi方法的调用者()处理
//throws关键字后也可以是列表
FileInputStream fis = new FileInputStream("dd.txt");
}
}
ThrowsDetail.java
-
对于编译异常,程序中必须处理,比如try-catch或者throws
-
对于运行时异常,程序中如果没有处理,默认是throws的方法处理
-
子类重写父类的方法时,对抛出异常的规定:子类重写的方法所抛出的异常类型要么和父类抛出的一致,要么为父类抛出异常类型的子类型。
class Father { public void method() throws RuntimeException{ } } class Son extends Father { //子类重写父类的方法时,对抛出异常的规定: // 子类重写的方法所抛出的异常类型要么和父类抛出的一致, // 要么为父类抛出异常类型的子类型。 @Override public void method() throws NullPointerException { } }
编译异常的处理
解决方法1:使用try-catch处理
解决方法2:throws抛出
运行异常的处理
自定义异常
当程序中出现了某些“错误”,但该错误没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述错误信息。
自定义异常步骤
- 定义类:自定义异常类名,继承
Expection
或RnntimeExpection
- 如果继承
Expection
,属于编译异常 - 如果继承
RuntimeExpection
,属于运行异常(一般继承RuntimeExpection
)
CustomException.java
public class CustomExpection {
public static void main(String[] args) {
int age = 800;
//要求年龄在18-120之间1,否则抛出一个异常
if (!(age >= 18 && age <= 120))
{
throw new AgeException("年龄需要在18~120之间!");
}
System.out.println("你的年龄范围正确!");
}
}
//自定义的一个异常
//1.一般情况,自定义异常都是继承RuntimeException,即运行时异常
//2.好处是,我们可以使用默认的处理机制
class AgeException extends RuntimeException {
//构造器
public AgeException(String message) {
super(message);
}
}
throw和throws的区别
意义 | 位置 | 后面跟的东西 | |
---|---|---|---|
throws | 异常处理的一种方式 | 方法声明处 | 异常类型 |
throws | 手动生成异常对象的关键字 | 方法体中 | 异常对象 |