异常处理
Posted onepg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异常处理相关的知识,希望对你有一定的参考价值。
1 异常处理
1.1 传统处理异常的方式
public class Test01 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入第一个数:");
int num1 = 0; if(sc.hasNextInt()) { num1 = sc.nextInt();
System.out.println("请输入第二个数:"); int num2 = 0; if(sc.hasNextInt()) { num2 = sc.nextInt();
if(0 == num2) { System.out.println("除数不能为0!"); }else { int r = num1 / num2; System.out.println("num1/num2 = "+r); }
}else { System.out.println("第二个数输入不是数字"); }
}else { System.out.println("第一个数输入不是数字!"); } } } |
缺点:
[1] 通过判断影响执行效率。
[2] 判断逻辑和业务逻辑交织在一起,可维护性很差。
1.2 异常
异常是指在程序的运行过程中所发生的不正常的情况,它会中断正在运行的程序
异常处理机制
java中通过异常处理机制为程序提供异常处理的能力,保持程序继续运行而不中断!
|
1.3 异常处理
涉及异常处理的关键字有try…catch/try…catch…finally
1.3.1 try/catch
把有可能产生异常的代码放到try代码块中,catch代码块负责捕获并处理异常。
[1]正常执行,没出现任何异常
|
[2]出现异常,异常处理,正常结束
|
Exception是所有异常类的直接或者间接父类。
异常常见方法
printStackTrace:打印异常的执行堆栈信息
java.util.InputMismatchException at java.util.Scanner.throwFor(Scanner.java:864) at java.util.Scanner.next(Scanner.java:1485) at java.util.Scanner.nextInt(Scanner.java:2117) at java.util.Scanner.nextInt(Scanner.java:2076) at cn.sxt02.exception02.Test01.main(Test01.java:14) |
一般而言,异常堆栈信息很多,开发者只需要看懂
第一行:异常简单信息(异常类型,异常的描述等)
最后一行:异常出现的位置(类->方法->方法具体的行)
在控制台中异常堆栈信息输出位置不固定
getMessage:返回异常的描述信息
package cn.sxt02.exception02; import java.util.Scanner; public class Test01 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入第一个数:");
int num1 = 0; int num2 = 0;
try { num1 = sc.nextInt();
System.out.println("请输入第二个数:"); num2 = sc.nextInt();
int r = num1 / num2; System.out.println("num1/num2 = " + r); }catch (Exception e) { System.out.println("程序出现异常"); // 打印异常的信息 // System.out.println(e.toString());
// 打印异常堆栈信息 e.printStackTrace();
// 返回异常的描述信息,如果没有信息,返回null(InputMismatchException 没有描述信息) System.out.println(e.getMessage()); }
System.out.println("程序正常结束"); } }
|
[3]异常类型不匹配
|
[4] 多重catch
public class Test03 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入第一个数:");
int num1 = 0; int num2 = 0;
try { num1 = sc.nextInt();
System.out.println("请输入第二个数:"); num2 = sc.nextInt();
int r = num1 / num2; System.out.println("num1/num2 = " + r); }catch (ArithmeticException e) { System.out.println("数学计算异常:"+e.getMessage()); }catch(InputMismatchException e) { System.out.println("输入不匹配异常:"+e.getMessage()); }catch (Exception e) { System.out.println("发送异常:"+e.getMessage()); }
System.out.println("程序正常结束"); } } |
1.3.2 try/catch/finally
把有可能产生异常的代码放到try中,catch负责匹配并处理异常,finally块用于进行收尾工作(关闭数据库、关闭文件、释放内存等资源)
不管是否发生异常,finally都执行。
public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入第一个数:");
int num1 = 0; int num2 = 0;
try { num1 = sc.nextInt();
System.out.println("请输入第二个数:"); num2 = sc.nextInt();
int r = num1 / num2; System.out.println("num1/num2 = " + r); } catch (Exception e) { System.out.println("程序出现异常"); } finally { System.out.println("不管是否出现异常,finally都执行"); }
System.out.println("程序正常结束"); } |
finally 总是执行,常用进行收尾类工作。
特殊情况(B)
[1] finally不执行的情况。
System.exit(0) 正常推出jvm,finally不会执行。
[2]catch可以省略,变成try…finally块。
1.3.3 return
存在return的try/catch/finally执行顺序
package cn.sxt02.exception03;
/** * 存在return的情况 */ public class Test02 {
public static int div(int a, int b) {
try { int r = a / b; return r;
} catch (Exception e) { System.out.println("出现异常");
return 0;
} finally { System.out.println("我是finally"); }
}
public static void main(String[] args) {
int r = Test02.div(10, 0); System.out.println("r=" + r); System.out.println("程序正常结束"); } }
|
1.1 异常的分类
|
Throwable 类是 Java 语言中所有错误(Error)或异常(Exception)的父类,只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。
Error 类表示错误类。仅靠程序本身无法恢复的严重错误。jvm内存耗尽、jvm崩溃等。
Exception 类表示异常类,可以通过java 异常处理机制处理。
Exception 根据是否处理分为两种情况。
RuntimeException:运行时异常。不要求程序必须做出处理。是所有运行时异常的父类。
CheckedException:检查时异常。要求程序必须处理,不处理编译不通过。
public class Test01 { public static void main(String[] args) { // 运行时异常 Scanner sc = new Scanner(System.in); // runtime exception int r = sc.nextInt(); System.out.println("r = "+ r);
// 检查时异常 SimpleDateFormat df = new SimpleDateFormat(); try { Date date = df.parse("2019"); } catch (ParseException e) { e.printStackTrace(); } } } |
常见的运行时异常
ArithmeticException:数学计算异常。比如除数为0
InputMismatchException:输入不匹配异常
ArrayIndexOutofBoundsException:数组下标越界异常。
NullPointException:空指针异常,对象没有初始化就使用时,jvm会抛出该异常
IllegalArgumentException:非法参数异常。
ClassCastException:强制类型转换异常。
NumberFormatException:数字格式化异常。比如把“abc”格式化成数字。
常见的检查时异常:
ClassNotFoundException:类没有被发现异常。
SQLException:数据库相关异常
IOException:IO操作异常
ParseException:解析错误异常
FileNotFoundException:文件未发现异常。
运行时异常和检查时异常的区别
运行时异常:包括RuntimeException及其所有子类。不要求程序必须对它们作出处理,比如InputMismatchException、ArithmeticException、NullPointerException等。即使没有使用try-catch或throws进行处理,仍旧可以进行编译和运行。如果运行时发生异常,会输出异常的堆栈信息并中止程序执行。
Checked异常(非运行时异常):除了运行时异常外的其他异常类都是Checked异常。程序必须捕获或者声明抛出这种异常,否则出现编译错误,无法通过编译。处理方式包括两种:通过try-catch捕获异常,通过throws声明抛出异常从而交给上一级调用方法处理
1.4 声明异常
1.4.1 throws关键字
当一个方法可能存在异常,而此时自身又无法更好的处理,可以交给外界处理。此时用throws声明并抛出异常。
public class Test01 {
public static int div(int a, int b) throws ArithmeticException{ int r = 0; r = a / b; return r; }
public static void main(String[] args) { try { Test01.div(10, 0); } catch (ArithmeticException e) { System.out.println("除数不能为0"); } } } |
开发者可以根据需要声明检查时异常(Exception或者非运行时异常)和运行时异常(RuntimeException或其子类)
如果调用处也不知道如何处理异常,可选择继续声明异常,我们把这个过程称为异常上抛。
public class Test01 {
public static int div(int a, int b) throws Exception{ int r = 0; r = a / b; return r; }
public static void main(String[] args) throws Exception{
//【1】 调用处知道如何处理! /* try { Test01.div(10, 0); } catch (Exception e) { e.printStackTrace(); } */
// 【2】调用处也不知道如何处理 Test01.div(10, 0);
} } |
1.4.2 声明异常和重载的关系
声明异常和重载没有任何关系
public class Test01 {
public static int div(int a, int b) throws Exception{ int r = 0; r = a / b; return r; }
public static int div(int a, int b) { int r = 0; r = a / b; return r; } } |
方法重载
[1]方法名相同
[2]参数列表不同(个数、类型、顺序)
[3]和返回值、修饰符、声明异常无关。
1.4.3 声明异常和重写的关系
声明一个和方法重写有关系。
[1]父类方法声明了异常(检测时或运行时),子类可以不声明任何异常。
public class Father {
public void showInfo() throws Exception{
} }
|
public class Son extends Father{
@Override public void showInfo(){
}
} |
可以认为:父类方法抛出异常,子类在重写过程中把该异常处理掉了,所以子类方法不用声明异常。
[2] 父类方法声明没有声明任何异常(检测时或运行时),子类也不声明异常或者声明运行时异常。
public class Father {
public void showInfo(){
} } |
public class Son extends Father{
@Override public void showInfo() throws Exception{
}
} |
[3] 父类声明了异常(检测时或运行时),子类声明完全一样的异常。
public class Father {
public void showInfo() throws Exception{
} } |
public class Son extends Father{
@Override public void showInfo() throws Exception {
}
} |
1.5 手动抛出异常
1.5.1 throw
除了系统自动抛出异常外,有些问题需要开发者手动抛出异常。使用关键字throw
package cn.sxt02.exception06;
public class Student { private String name; private String gender;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getGender() { return gender; }
public void setGender(String gender) throws Exception{ if(gender.equals("男") || gender.equals("女")) { this.gender = gender; }else { throw new Exception("性别不合法!"); } }
public Student(String name, String gender) { super(); this.name = name; this.gender = gender; }
public Student() { super(); }
}
|
public class Test01 { public static void main(String[] args){ Student stu = new Student(); stu.setName("二狗"); try { stu.setGender("xxx"); } catch (Exception e) { System.out.println(e.getMessage()); } } } |
1.5.2 自定义异常
如果开发者需要手动抛出的异常在系统不存在,可以自定义异常。
如果要自定义异常,首先要确定异常类型,如果异常是运行时异常,必须继承RuntimeException或其子类;如果异常是检查时异常,必须继承Exception或其子类。
异常的命名方式,参考系统命名方式,以Exception结尾。
public class AgeException extends Exception{
public AgeException() { super(); }
public AgeException(String message) { super(message); }
} |
以上是关于异常处理的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin 协程Flow 流异常处理 ( 收集元素异常处理 | 使用 try...catch 代码块捕获处理异常 | 发射元素时异常处理 | 使用 Flow#catch 函数捕获处理异常 )
Kotlin 协程Flow 流异常处理 ( 收集元素异常处理 | 使用 try...catch 代码块捕获处理异常 | 发射元素时异常处理 | 使用 Flow#catch 函数捕获处理异常 )