Java中的异常和处理
Java异常
目录
- 异常概述
- 异常处理
- 抛出异常
什么是异常:
那么究竟什么是异常?当面对异常时,该如何有效处理呢?
异常就是程序在运行中所发生的不正常事件,如所需文件找不到、网络连接不通或中断、算术运算出错(如被除零数)、数组下标越界、装载了一个不存在的类、对null对象操作、类型转换异常等。异常会中断运行中的程序。
异常处理:
什么是异常处理?异常处理机制就像我们对平时可能会遇到的意外情况、预先想好的一些处理方法、也就是说在程序执行代码的时候,万一发生了异常,程序会按照预定的处理方法对异常进行处理。异常处理完成后程序继续运行。
java异常是通过五个关键字来处理的:try、catch、finally、thorw和thorws下面将依次讲解。
try-catch块
采用java的异常处理机制进行处理,把可能发生异常的代码放入try语句块中,并使用catch语句块捕获异常,下面使用简单的示例代码:
import java.util.Scanner;
/**
* 使用try-catch进行异常处理
*/
public class testException {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入被除数");
/*把容易出错的代码发入try中*/
try {
int num = scanner.nextInt();
System.out.println("请输入除数");
int num2 = scanner.nextInt();
System.out.println(String.format("%d/%d=%d",num,num2,num/num2));
/*用catch来捕捉异常*/
}catch (Exception e){
System.out.println("出现错误,被除数和除数必须是整数或被除数不能为零");
e.printStackTrace();
}
}
}
try-catch程序块执行流程比较简单,首先是执行try语句块中的代码,这时可能会有三种情况;
一:如果try语句块中所有语句正常执行完毕,不会发生异常,那么catch块中的所有语句将会全部被忽略,我们输入正确的如下:
二:如果try语句块在执行过程中遇到异常,并且这个异常在catch中声明的异常类型匹配,那么在tey块中其余的代码将被忽略,而相应的catch块将会被执行、匹配是指catch所处理的异常类型与所生成的异常类型完全一致或是它的父类。
错误的:
三:如果try语句块在执行过程中遇到异常,并且这个异常在catch中没有被声明,那么程序将会立刻退出。
列出一些常见的异常及其用途;
异常 | 说明 |
---|---|
Exception | 异常层次结构的根类 |
ArithmeticException | 当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例 |
ArrayIndexOutOfBoundsException | 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引 |
ArrayStoreException | 试图将错误类型的对象存储到一个对象数组时抛出的异常 |
ClassCastException | 当试图将对象强制转换为不是实例的子类时,抛出该异常。 |
illegalArgumentException | 抛出的异常表明向方法传递了一个不合法或不正确的参数。 |
illegalMonitorStateException | 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。 |
illegalStateException | 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。 |
illegalThreadStateException | 线程没有处于请求操作所要求的适当状态时抛出的异常。 |
IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 |
NegativeArraySizeException | 如果应用程序试图创建大小为负的数组,则抛出该异常。 |
NullPointerException | 当应用程序试图在需要对象的地方使用 null 时,抛出该异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。 |
SecurityException | 由安全管理器抛出的异常,指示存在安全侵犯。 |
StringIndexOutOfBoundsException | 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。 |
UnsupportedOperationException | 当不支持请求的操作时,抛出该异常。下面的表中列出了 Java 定义在 java.lang 包中的检查性异常类。 |
ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常。 |
CloneNotSupportedException | 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常 |
IllegalAccessException | 拒绝访问一个类的时候,抛出该异常。 |
InstantiationException | 试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。 |
InterruptedException | 一个线程被另一个线程中断,抛出该异常 |
NoSuchFieldException | 请求的变量不存在 |
NoSuchMethodException | 请求的方法不存在 |
try-catch-finally块
在try-catch代码后面加上finally里面放入一些语句,无论发生什么异常,finally中的代码总被执行,如下:
import java.util.Scanner;
/**
* 使用try-catch-finally进行异常处理
*/
public class testException {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入被除数");
/*把容易出错的代码发入try中*/
try {
int num = scanner.nextInt();
System.out.println("请输入除数");
int num2 = scanner.nextInt();
System.out.println(String.format("%d/%d=%d",num,num2,num/num2));
/*用catch来捕捉异常*/
}catch (Exception e){
System.out.println("出现错误,被除数和除数必须是整数或被除数不能为零");
System.out.println(e.getMessage());
}finally {
System.out.println("感谢使用哦");
}
}
}
try-catch-finally程序块执行流程大概分为两种情况:
一:如果try语句中的所有代码正常执行完毕,那么finally块就会被执行。catch块不会被执行。
二:如果tey块中代码出现异常,就会执行catch块中的代码,不管catch有没有匹配类型finally块中的代码都会被执行
finally唯一不被执行情况是,在异常处理catch代码中执行System.exit(1),将退出java虚拟机。
多重catch块
一段代码可能会引发多种类型异常,这时,可以在一个try语句后面跟多个catch语句块,分别处理不同的异常。但排列顺序必须是从子类到父类,最后一个一般都是Exception类,因为所有异常子类都继承Exception类,所以如果将异常父类放在前面,那么所有的异常都将被捕获,后面的catch中的子类将得不到执行的机会。
但运行时,系统从上倒下对每个catch块语句处理的异常类型进行检测,并执行第一个与异常类型匹配的catch块,其他的catch块全部会被忽略。
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* 多重catch块
*/
public class testException {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入被除数");
/*把容易出错的代码发入try中*/
try {
int num = scanner.nextInt();
System.out.println("请输入除数");
int num2 = scanner.nextInt();
System.out.println(String.format("%d/%d=%d",num,num2,num/num2));
/*用多重catch来捕捉异常*/
}catch (InputMismatchException e){
System.out.println("被除数和除数必须是整数");
}catch (ArithmeticException e){
System.out.println("除数不能为零");
}catch (Exception e){
System.out.println("其他未知错误");
}finally {
System.out.println("感谢使用哦");
}
}
}
被除数不是整数,就会抛出InputMismatchException这个异常:
被除数为0,就会抛出ArithmeticException 这个异常:
在使用多重catch块时,catch块的排列顺序必须是从子类到父类,最后一个一般是Exception类;
声明异常——throws:
如果在一个方法体中抛出了异常,我们希望调用着能够及时的捕获异常,那么如何通知调用着呢?java语言中通过关键字throws声明某个方法可能抛出的各种异常throws可以同时声明多个异常中间用逗号隔开。
把执行代码放在divide()方法中,并在方法的参数列表后通过throws声明异常,然后在main()方法中调用该方法,此时main()方法就知道divide()方法中抛出了异常,可以采取以下两种方式进行处理。
- 通过try-catch捕获并处理异常
- 通过throws继续声明异常,如果调用者不打算处理该异常,这可以继续通过throws声明,让上一级调用者处理异常,main()方法声明的异常将由java虚拟机来处理。
通过try-catch捕获并处理异常
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* 使用throws声明异常
*/
public class testException {
public static void main(String[] args) {
/*通过try-catch捕获并处理异常*/
try {
divide();
/*用catch来捕捉异常*/
}catch (Exception e){
System.out.println("出现错误,被除数和除数必须是整数或被除数不能为零");
}finally {
System.out.println("感谢使用哦");
}
}
/*把执行代码放在divide()方法中*/
public static void divide() throws Exception{
Scanner scanner = new Scanner(System.in);
System.out.println("请输入被除数");
int num = scanner.nextInt();
System.out.println("请输入除数");
int num2 = scanner.nextInt();
System.out.println(String.format("%d/%d=%d",num,num2,num/num2));
}
}
通过throws继续声明异常
import java.util.Scanner;
/**
* 使用throws声明异常
*/
public class testException {
/*通过throws继续声明异常*/
public static void main(String[] args) throws Exception {
divide();
}
/*把执行代码放在divide()方法中*/
public static void divide() throws Exception{
Scanner scanner = new Scanner(System.in);
System.out.println("请输入被除数");
int num = scanner.nextInt();
System.out.println("请输入除数");
int num2 = scanner.nextInt();
System.out.println(String.format("%d/%d=%d",num,num2,num/num2));
}
}
抛出异常throw
既然可以捕获到各种类型的异常,那么这些异常是在那些地方抛出的呢?
出来系统自动抛出异常外,在编程过程中,我们往往遇到这样的情形,有些异常是系统无法发现的并解决的,如年龄不在正常范围内,性别不是男或女等,此时需要程序猿而不是系统抛出异常,把问题提交给调用者去解决。
在java语言中,可以使用throw关键字来自行抛出异常,示例代码:
/**
* 使用throw抛出异常
*/
public class testException {
String name = "小明";//姓名
int age = 0;//年龄
String sex = "男"; //性别
public static void main(String[] args){
/*捕获throw抛出的异常*/
testException testException = new testException();
try {
testException.setSex("Male");
testException.print();
/*用catch来捕捉异常*/
}catch (Exception e){
e.printStackTrace();
}
}
/*设置性别*/
public void setSex(String sex) throws Exception{
if("男".equals(sex) || "女".equals(sex)){
this.sex = sex;
}else {
/*使用throw抛出异常*/
throw new Exception("性别必须是男或女");
}
}
/*输出基本信息*/
public void print(){
System.out.println(this.sex+this.age+"岁");
}
}
throw和throws的区别表现在以下三个方面:
- 作用不同:throw用于在程序中抛出异常,throws用于声明在该方法内抛出了异常。
- 使用的位置不同:throw位于方法体内部,可作为单独语句使用、throws必须跟在方法列表参数后面,不能单独使用。
- 内容不同:throw抛出一个异常对象,而且只能是一个,throws跟异常类,而且可以跟多个异常类。
异常的分类:
java的异常体系包括许多异常类,他们之间存在继承关系。如图:
- Throwable是 Java 语言中所有错误或异常的超类。下一层分为Error和Exception
- Error类是指java运行时系统的内部错误和资源耗尽错误。应用程序不会抛出该类对象。如果出现了这样的错误,除了告知用户,剩下的就是尽力使程序安全的终止。
- Exception又有两个分支,一个是运行时异常RuntimeException,如:NullPointerException、ClassCastException;一个是检查异常CheckedException,如I/O错误导致的IOException、SQLException。
总结:
异常是由java应用程序抛出和处理的非严重错误Checked异常和运行时异常两大类。
Checked异常必须捕获或者声明抛出否则无法通过编译。运行时异常不要求必须捕获或者声明抛出。
java的异常处理是通过五个关键字来实现的:
try、catch、finally、thorw和thorws
即使在try块、catch块中存在return语句,finally块中的语句也会被执行,finally块中的语句不被执行的唯一情况是在在异常处理代码中执行System.exit(1)。
可以在同一个try块语句后面跟多个catch语句块,分别处理不同的异常,但排序顺序必须是从特殊到一般,最后一个一般为Exception类。