Java中的异常处理
1.1异常概述
在我们写的Java代码运行时产生的错误我们称之为--异常。异常分为二种一个是编译期异常(checked)、运行期异常(runtime)
Examples:算术异常 java.lang.ArithmeticException
public class Demo {
public static void main(String[] args){
int number = 3 / 0;
System.out.println(number);
}
}
//Exception in thread "main" java.lang.ArithmeticException: / by zeat Demo.main(Demo.java:4)
Examples: 空指针异常 java.lang.NullPointerException
public class Demo {
public static void main(String[] args){
String str = null;
System.out.println(str.toString());
}
}
//Exception in thread "main" java.lang.NullPointerException at Demo.main(Demo.java:4)
Examples: 数据类型转换异常 java.lang.NumberFormatException
public class Demo {
public static void main(String[] args){
String str = "2.3";
int number = Integer.parseInt(str);
System.out.println(number);
}
}
//Exception in thread "main" java.lang.NumberFormatException
Examples: 对象强制类型转换异常
public class Demo {
public static void main(String[] args){
Object o = new Test();
String str = (String)o;
System.out.println(str);
}
}
class Test{}
//Exception in thread "main" java.lang.ClassCastException
Examples: 控制台输入的值与期望值不匹配
import java.util.*;
public class Demo{
public static void main(String[] args){
Scanner input = new Scanner(System.in);
System.out.println("请输入一个数值:");
int number = input.nextInt();
System.out.println(number);
}
}
//运行代码,输入一个非数值
//InputMismatchException
1.2 捕捉处理异常
在Java代码中,使用try-catch-finally代码块来进玍捕捉异常。
try {
//程序代码块
} catch(Exceptiontype e) {
//对Exceptiontype的处理
} finally {
//无论如何都要执行的代码块
}
分析:
- try中的程序代码块指的是可能会产生异常的代码;
- catch中的Exceptiontype的作用是捕捉并处理与已产生的异常类型相匹配的异常对象e;
- finally中的代码埠是异常处理过程中最后被执行的部分,无论程序是否产生异常,finally中的代码块都将被执行。
Examples: 使用try-catch来演示顾客买东西付款场景
public class Demo {
public static void main(String[] args){
try {
String message = "西瓜:3.99元/500克";
//使用:分割字符串,方便得到单价
String[] strArr = message.split(":");
//单价
double price = Double.parseDouble(strArr[2].substring(0, 4));
double weight = 1878; //西瓜重量
//计算总价格
System.out.println((float)(weight / 500 * price) + "元");
} catch(Exception e){
e.printStackTrace();
}
System.out.println("结束");
}
}
//java.lang.ArrayIndexOutOfBoundsException
//结束
注意: 代码产生异常,不会影响程序的执行。「printStackTrace() =>输出异常信息」、「getMessage()=>获得有关异常事件的信息」、「toString()=>获得异常的类型与性质」
Examples: 多个catch代码块一起使用
public class Demo {
public static void main(String[] args){
try {
String message = "西瓜:3.99元/500克";
//使用:分割字符串,方便得到单价
String[] strArr = message.split(":");
//单价
double price = Double.parseDouble(strArr[2].substring(0, 4));
double weight = 1878; //西瓜重量
//计算总价格
System.out.println((float)(weight / 500 * price) + "元");
}catch(ArrayIndexOutOfBoundsException ex){
ex.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
System.out.println("结束");
}
}
注意: 在使用异常处理方法时,关于多个catch使用一定要知道先子类后父类。父类是Exception
public class Demo {
public static void main(String[] args){
int number[] = {1,2,3,4};
for(int i = 0; i < 5; i++){
try {
System.out.println("当 i = " + i + "," + i + " < 5 时,a[" + i + "] = " + a[i] + ";");
}catch(ArrayIndexOutBoundsException e){
System.out.println(e.toString());
e.printStackTrace();
System.out.println("超出数组索引");
}
}
}
}
import java.util.*;
public class Demo {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
try {
System.out.println("请输入第一个整数:");
int num1 = input.nextInt();
System.out.println("请输入一个运算符(+-*/)");
String sym = input.next();
System.out.println("请输入第二个整数:");
int num2 = input.nextInt();
int result = 0;
switch(sym){
case "*":
result = num1 * num2;
break;
case "-":
result = num1 - num2;
break;
case "/":
result = num1 / num2;
break;
case "+":
result = num1 + num2;
break;
}
System.out.println("result=" + result);
} catch(InputMismatchException e){
e.printStackTrace();
}
}
}
1.3 finally 代码块
完整的异常处理语句应该包含finally代码块,finally代码块在程序中有无异常产生,finally代码块中的代码都会被执行。
import java.util.*;
public class Demo {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
System.out.println("西瓜单位(格式为:2.99):");
String strPrice = input.next();
//判断长度是否等于4
if (strPrice.length() == 4){
try{
String message = "西瓜:" + strPrice + "元/500克";
String[] strArr = message.split(":");
String tmpPrice = strArr[2].substring(0,4);
double weight = 789;
double price = Double.parseDouble(tmpPrice);
System.out.println("总额为:" + (float)(weight / 500) * price + "元");
}catch(ArrayIndexOutOfBoundsException ex){
//打印异常信息
ex.printStackTrace();
}finally{
input.close();
System.out.println("窗口程序关闭");
}
}else{
System.out.println("输入价格有误!");
}
}
}
//输入3.99
//java.lang.ArrayIndexOutOfBoundsException: 2
//窗口程序关闭
分析:使用try-catch出现异常不会立马终止程序,代码会执行catch代码块,上面示例中会执行finnaly代码块。
Examples:模拟银行取款
import java.util.*;
public class Demo {
public static void main(String[] args){
double money = 14903.48; //账号默认金额
Scanner input = new Scanner(System.in);
System.out.println("请输入取款金额:");
try{
int outMoney = input.nextInt();
double result = money - outMoney;
if(result >= 0){
System.out.println("余额:" + (float)result + "元");
}else{
System.out.println("余额不足");
}
}catch(InputMismatchException e){
e.printStackTrace();
}finally{
input.close(); //关闭窗口程序
}
}
}
1.4 在方法中抛出异常
在上面的学习中,关于异常我们可以接经catch代码块来处理。但是在Java代码中,对于产生的异常,并不想处理这个异常,那么我们就可以使用throws和throw关键字来进行抛出。
1.4.1 使用throws关键字抛出异常
throw关键字一般被应用于方法上,表示方法可能会抛出异常;当方法抛出多个异常时,可用逗号分隔异常类型名。
返回值类型名 方法 (参数列表) throws 异常类型名 {
方法体
}
public class Demo {
public static void main(String[] args){
try{
Demo d = new Demo();
d.say();
}catch(ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}
}
public void say() throws ArrayIndexOutOfBoundsException{
String[] strArr = {"你好吗?", "来吧"};
System.out.println(strArr[2]);
}
}
//java.lang.ArrayIndexOutOfBoundsException: 2
多个异常抛出
public class Demo{
public static void main(String[] args){
try{
Demo d = new Demo();
d.say();
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("ArrayIndexOutOfBoundsException");
}catch(NullPointerException n){
System.out.println("NullPointerException");
}
}
public void say() throws ArrayIndexOutOfBoundsException,NullPointerException{
String[] strArr = {"你好吗?", "来吧"};
System.out.println(strArr[2]);
String tmp = null;
System.out.println(tmp.toString());
}
}
1.4.2 使用throw关键字抛出异常
在Java程序出现错误时,系统会自动抛出异常;除此之外,可使用关键字throw自行抛出异常。在使用throw自行抛出异常时,throw语句抛出的不是异常类,而是异常实例,而且每次只能抛出一个异常实例。
throw new 异常类型名(异常信息)
public class Demo {
public static void main(String[] args){
try{
throwChecked(-1);
}catch(Exception e){
System.out.println(e.getMessage());
}
throwRuntime(3);
}
//必须要在try-catch代码块里,或者在带有throws声明的方法中
public static void throwChecked(int a) throws Exception{
if(i > 0){
throw new Exception("a的值大于0");
}
}
public static void throwRuntime(int a){
if(i > 0){
throw new RuntimeException("a的值大于0");
}
}
}
//Exception in thread "main" java.lang.RuntimeException: a的会上大于0
1.4.3 自定义异常类
通俗的理解就是创建自己定义的异常类,但是自定义异常类通常需要提供两种构造器:一个是无参数的构造器;另一个是带一个字符串参数的构造器。
class CustomException extends Exception {
public CustomException(){}
public CustomException(String message){
super(message);
}
}
public class Demo {
public static void main(String[] args){
try{
Demo d = new Demo();
d.say();
}catch(CustomException e){
System.out.println(e.getmessage());
}
}
public void say() throws CustomException{
throw new CustomException("我是自定义的异常类customException");
}
}
1.4.4 catch和throw同时使用
class AuctionException extends Exception{
public AuctionException(String message){
super(message);
}
}
public class Demo{
private double number = 40.0;
public static void main(String[] args){
try{
Demo d = new Demo();
d.say("aa");
}catch(AuctionException e){
System.err.println(e.getMessage());
}
}
public void say(String str) throws AuctionException{
try{
double num = Double.parseDouble(str);
}catch(Exception e){
e.printStackTrace();
throw new AuctionException("只能是数字");
}
}
if(number < num){
throw new AuctionException("不于小于" + number);
}
}
1.4.5 throws关键字和throw关键字的区别
- throws用在方法声明后面,表示抛出异常,由方法的调用者处理,而throw用在方法体内,同来制造一个异常,由方法体内的语句处理
- throws是声明这个方法会抛出这种类型的异常,方便调用者知道要捕捉这个异常,而throw是直接抛出一个异常实例
- throws表示出现异常的一种可能性,并不一定会产生这些异常,如果直接使用throw,就一定会产生某种异常