文章目录
1.异常概述
1.1异常和错误
API中标准异常的顶级父类是Throwable类;
Throwable类有两个子类:Exception和Error;所有异常都是Exception类的直接或间接子类;所有错误都是Error的直接或间接子类;
异常(Exception):异常指的是程序运行时发生的不正常事件;异常能够被程序处理,保证程序继续运行下去;例如除数为0、文件没有找到、输入的数字格式不对
错误(Error):错误程序没法处理,例如内存泄漏。发生错误后,一般虚拟机会选择终止程序运行,程序员需要修改代码才能解决相关错误;
1.2 运行期异常和非运行期异常
Exception有很多子类;这些子类又可以分为两大类;
即运行时异常和非运行时异常;RuntimeException的子类都是运行时异常,其他的都是非运行时异常;
运行时异常:也称为非检测异常(unchecked Exception), 这些异常在编译期不检测,程序中可以选择处理,也可以不处理。如果不处理运行时会中断,但是编译没问题;
非运行时异常:也称为检测异常(checked Exception), 是必须进行处理的异常,如果不处理,将发生编译期错误;
下面我介绍几个常见的异常
1.1 常见异常
1.1.1 ArithmaticException 算术异常
当除数为0时会发生
public static void main(String[] args) {
int a=1,b=0;
System.out.println(a/b);
}
1.1.2 NullPointerException 空指针异常
当对一个空对象,即没有初始化,依然为null的对象调用属性或方法时
1.1.3 IndexOutOfBoundsException 索引越界异常
IndexOutOfBoundsException:索引越界异常,包括字符串索引StringIndexOutOfBoundsException和数组索引ArrayIndexOutOfBoundsException两种;
发生前提:当访问字符串中的字符或者数组中的元素,超过了其长度时;
1.1.4 NumberFormatException 数字格式异常
发生前提:当把一个字符串转换成数字时,字符串内容不是数字时发生;
1.1.4 ClassCastException 类型转换异常
发生前提:把父类对象转换成不相关的子类类型时;
2. 异常处理流程
2.1 try-catch语句
当我们有异常需要处理的时候,我们可以使用try-catch语句,将异常捕捉。如一下代码
public static void main(String[] args) {
try{
int x=100;
int y=0;
System.out.println("x/y="+x/y);
System.out.println("x/y计算结束");
}catch(ArithmeticException e){
System.out.println("发生了数学异常,注意除数不能为0.");
}
System.out.println("main方法运行结束");
}
运行结果
当系统捕捉到try语句块中的ArithmeticException,会在catch语句中查找相应的处理语句,然后执行。如果将ArithmeticException改为其他的异常(不包括它的父类异常),那么无法捕捉,就会抛出异常,不会执行最后的打印语句
注意:catch语句可以有多个,但是类型从子类到父类顺序,不能颠倒
2.2 finally语句
如果希望不管什么情况,有一些代码都必须被执行,那么就可以把这些代码写到finally块中;
public static void main(String[] args) {
try{
int x=100;
int y=0;
System.out.println("x/y="+x/y);
System.out.println("x/y计算结束");
}catch(ArithmeticException e){
System.out.println("发生了数学异常,注意除数不能为0.");
}finally{
System.out.println("finally代码块");
}
System.out.println("main方法运行结束");
}
运行结果
就算异常没有被处理,但是finally语句块依然会执行(包括return;还是会执行)
除了(System.exit(0))
3. 抛出异常
抛出异常时,我们需要通过throw和throws关键字
public class Calculator {
public void div(int x,int y){
//当除数为0时,抛出异常
if(y==0){
throw new Exception();//编译错误,需要使用throws关键字
}
System.out.println("x/y="+x/y);
}
}
//修改后
public class Calculator {
public void div(int x,int y) throws Exception{
//当除数为0时,抛出异常
if(y==0){
throw new Exception();//编译错误,需要使用throws关键字
}
System.out.println("x/y="+x/y);
}
}
一个方法如果使用了throws,那么调用该方法时,编译期会提醒必须处理这些异常,否则编译错误;
所以我们回到FileInputStream类的源码
我们可以发现它的源码代码中有throws FileNotFoundException 所以他就变为非运行期异常异常,需要处理。
一个方法如果使用了throws,那么调用该方法时,编译期会提醒必须处理这些异常,否则编译错误;
4. 自定义异常
4.1 自定义异常概述
抛出的异常不一定是使用系统定义好的,为了更好地来识别异常,我们也可以自己定义异常。
自定义异常类非常简单,只要继承API中任意一个标准异常类即可;
多数情况下,继承Exception类;也可以选择继承其他类型异常;
一般自定义异常类中不写其他方法,只重载必要的构造方法;
public class DataValueException extends Exception {
public DataValueException() {
}
public DataValueException(String message) {
super(message);
}
public DataValueException(Throwable cause) {
super(cause);
}
public DataValueException(String message, Throwable cause) {
}
4.1 自定义异常作业
题目:
模拟实现用户购买商品的功能,使用数组模拟商品列表,当购买的商品不存在或者商品库存为0时,抛出自定义异常。用户购买某一个商品时,对异常进行处理,并对库存进行改变。
考点:自定义异常、异常处理、throw/throws关键字
import java.util.Scanner;
public class ShopException {
String[] goods_name={"苹果","西瓜","香蕉","梨","火龙果"};
int[] num = {1,2,0,1,0};
public void buy(int index) throws Exception{
if(index>=num.length)
throw new OutgoodException();
if(num[index]==0)
throw new NogoodException();
}
public void select(ShopException s){
for(int i=0;i<s.num.length;i++){
System.out.print(s.goods_name[i]+"\t");
}
System.out.println();
for(int i=0;i<s.num.length;i++){
System.out.print(s.num[i]+"\t");
}
System.out.println();
}
public void gobuy(ShopException s){
Scanner in = new Scanner(System.in);
System.out.println("请选择你要购买的东西");
int type=in.nextInt();
try {
s.buy(type);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
s.num[type]--;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
ShopException s = new ShopException();
System.out.println("欢迎来到包子侠客的水果店!");
System.out.println("1.查看店铺 2.购买水果 3.退出");
int type = in.nextInt();
while(type!=3){
if(type==1)
s.select(s);
else if(type==2)
s.gobuy(s);
else if(type==3)
break;
else
System.out.println("请输入正确的选项");
System.out.println("1.查看店铺 2.购买水果 3.退出");
type = in.nextInt();
}
}
}
5 断言
断言使用关键字assert表示,语法非常简单,
assert <布尔表达式> : <错误信息>
当布尔表达式的值是true时,忽略assert;
当布尔表达式的值是false时,发生AssertionError错误,程序中断;如果用第二种形式,同时显示错误信息;
Eclipse默认没有开启断言功能,要使用需要开启;
开启Eclipse中的断言功能;-
preferences->Installed JRES ->右边的edit
选择JRE 改变Default VM arguements
enableassertions 或者-ea
public class TestAssertion {
private static void test(int i){
assert i!=1:"输入值不能为1";
System.out.println("i="+i);
}
public static void main(String[] args) {
test(2);
test(1);
}
}