异常类
异常与错误:
异常:即程序运行时可能出现的一些错误。会导致程序异常终止(为保证出现异常时,程序不因异常而终止,必须要对异常进行处理)。异常本身使用类描述,在产生异常时就产生一个异常对象。
错误:描述的是java运行系统内部错误和底层资源耗尽的错误,一般就是JVM错误。与异常相比比较严重,仅仅靠应用层通过代码进行修改也不能恢复正常执行,是致命性的异常。
异常类的分类:
异常类(Exception)可以分为运行时异常和非运行时异常。
运行时异常(RuntimeException):程序运行时发生的异常,编译期可以不处理。
非运行时异常:即编译时异常,在编译时必须处理。
常见异常类:
ArithmeticException:算术异常,比如除数为0
IndexOutOfBoundsException:下标越界,比如数组或字符串下标超出数组或字符串长度。
NullPointerException:空指针异常。比如:Student s = null;s.name = “jack”;
InputMismatchException:欲得到的数据类型与实际输入类型不匹配,比如:int a = nextInt();在接收控制台的输入语句时,定义的是int类型的,但是输入的是非int类型(如string类型)。
程序中的异常处理:
1. 默认的异常处理方式:在控制台打印异常信息,程序异常终止。
2. 五个关键字:try,catch,finally,throw,throws(前三个是捕获异常,自行处理异常,后两个是抛出异常,由调用者处理异常)
捕获异常的格式:
格式一:
try{
//可能会发生异常的代码,和发生异常后不能执行的代码
}catch(异常类型 ex){//异常处理函数:异常类型限定该函数所能处理的异常类型
//对异常所进行的处理
}
特点:1.发生异常时,程序会执行catch代码块。程序会正常运行,catch代码块之后的代码也会运行。
3. 当发生异常的类型和catch函数所能处理的异常类型不匹配时,catch函数不能处理该异常,即catch指定哪个异常,就只能处理哪个异常。
代码示例:
packagelianxi;
importjava.util.Scanner;
publicclass Lianxi1 {
public static void main(String[] args) {
System.out.println(“请输入第一个数”);
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
System.out.println(“请输入第二个数”);
int b = sc.nextInt();
try{//try代码块写的是可能会出现异常的代码以及出现异常后就不能再执行的代码
System.out.println(“后面的代码”);//下一行代码可能会有异常,但是不影响异常出现前的代码执行,虽然也是在try代码块中。
int result = a/b;//可能会出现异常。
System.out.println(result);//如果前面出现异常,那么这条语句就不会再执行了。
}catch(ArithmeticException ex){//与之匹配的try中出现该catch函数里的异常类型时执行该代码块,如果try里面出现的异常在catch中没有相匹配的异常类型,那么就是默认异常处理的方式,在控制台输出异常并终止程序。如果在控制台输入的是字符串不是int类型的数字,这里的catch不能处理该异常,因为catch在这里定义的是处理算术异常。
System.out.println(“除数不能是0”);//发生相匹配的异常类型时执行的代码块
}
System.out.println(“捕获异常后可以正常执行后面的代码”);//即便上述地方出现了异常,但是已经对异常进行处理,所以trycatch之后的代码还可以运行。
}
}
格式二:
try{
//可能会发生异常的代码和发生异常后不能执行的代码
}catch(异常类型 参数名){//定义了该处理函数所能处理的异常类型
//异常发生后,对异常的处理
}finally{
//不管代码是否发生异常,都会被执行的语句
}
代码示例
:
packagelianxi;
importjava.util.Scanner;
publicclass Lianxi2 {
public static void main(String[] args) {
System.out.println(“请输入第一个数”);
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
System.out.println(“请输入第二个数”);
int b = sc.nextInt();
try{
int result = a/b;
System.out.println(“结果是”+result);
}catch(ArithmeticException ex){
System.out.println(“除数不能是0”);
}finally{
System.out.println(“无论有没有异常都会执行finally里面的代码块”);//无论try catch有没有发生异常,finally的代码块都能执行
}
}
}
格式三:
try{
//可能会发生异常的代码和发生异常不能执行的代码
}finally{
//不管异常是否发生都会被执行的代码
}
这种格式相当于是没有对异常进行处理,还是会以默认的方式处理异常。程序异常终止,finally
之后的代码不会执行。
代码示例:
packagelianxi;
importjava.util.InputMismatchException;
importjava.util.Scanner;
publicclass Lianxi3 {
public static void main(String[] args) {
System.out.println(“请输入数字”);
Scanner sc = new Scanner(System.in);
try{
int a = sc.nextInt();
System.out.println(“您输入的数字是”+a);
}finally{
System.out.println(“总是执行”);//无论有没有异常,都会执行
}
System.out.println(“顺利执行”);//如果出现异常,就不执行该语句,程序异常终止。
}
}
特别注意:
1.
try
不能单独使用,必须和catch
或finally一起使用。
2.
Catch
只能处理与他的参数异常类型一致的异常。
3.
多重异常处理的,try
中出现的异常按照顺序依次和catch的异常类型比对,如果比对成功,后面的catch就忽略,所以一般把子类类型的异常类型(具体的异常类型)写在前面,父类的异常类型(Exception)写在后面。
多重异常:
方法一:分别捕获,分别处理。
代码示例:
package lianxi;
import java.util.InputMismatchException;
import java.util.Scanner;
public class Lianxi4 {
publicstatic void main(String[] args) {
System.out.println(”
请输入第一个数”);
Scannersc = new Scanner(System.in);
inta = 0;
intb = 0;
try{
a= sc.nextInt();//12
System.out.println(”
请输入第二个数”);
b= sc.nextInt();//a
}catch(InputMismatchExceptionex){
System.out.println(”
输入不匹配异常”);
}
try{
intresult = a/b;
System.out.println(”
结果是”+result);
}catch(ArithmeticExceptione){
System.out.println(”
算术异常”);
}
System.out.println(”
执行完毕”);
}
}
//
测试:第一个数是12
,第二个数是a—->输入不匹配异常 算术异常 执行完毕(当第二个数出现InputMismatchException异常时,执行与之匹配的异常类型的catch代码块,即输出“输入不匹配异常”,第二个数出现异常,那么在执行第二个try的时候,相当于b的值没有赋值成功,那执行的时候还是按照初始化的值即0来执行,然后由于被除数不能为0,所以就触发了第二个异常,输出“算术异常”,最后执行catch 之后的语句”执行完毕”)
方法二:一个try
对应多个catch
try{
//
发生多个异常的代码和发生异常不能执行的代码
}catch(
异常类型1 ex){
//
对发生异常类型1
的处理
}catch(
异常类型2 ex){
//
对发生异常类型2
的处理
}
….
finally{
}
多重异常处理的,try
中出现的异常按照顺序依次和catch的异常类型比对,如果比对成功,后面的catch就忽略,所以一般把子类类型的异常类型(具体的异常类型)写在前面,父类的异常类型(Exception)写在后面。
代码示例:
package lianxi;
import java.util.InputMismatchException;
import java.util.Scanner;
public class Lianxi5 {
publicstatic void main(String[] args) {
System.out.println(”
请输入第一个数”);
Scannersc = new Scanner(System.in);
try{
inta = sc.nextInt();
System.out.println(”
请输入第二个数”);
intb = sc.nextInt();
intresult = a/b;
System.out.println(”
结果是”+result);
}catch(ArithmeticExceptionex){
System.out.println(”
除数不能是0″);
}catch(InputMismatchExceptionex){
System.out.println(”
输入的必须是数字”);
}catch(Exceptionex){
System.out.println(”
出现异常”);//
用于处理其他异常
}
}
}
抛出异常:
当前环境下,无法解决这个异常,将该异常抛出,把他交给调用者处理。throw
和throws两种方法。
thorw
:抛出的是异常对象。有throw
一定要有throws,throws是在方法声明处写,表明可能会出现的异常类型。throws可以写多个异常类型,用逗号隔开。
try…catch
里面产生异常时会自动产生异常对象,在throw
里面必须要自己new一个异常对象。
异常类常用的三种方法:
toString():
返回该 throwable
的字符串表示形式。
getMessage():
返回此 Throwable
实例(可以为 null)的详细消息字符串。
printStackTrace();
堆栈输出。
代码示例:
package lianxi;
public class Student {
privateString sex;
publicString getSex() {
returnsex;
}
@Override
publicString toString() {
return”Student [sex=” + sex + “]”;
}
publicvoid setSex(String sex) throws RuntimeException{//
如果这里声明的异常类型是Exception
,即包含了编译时异常,会导致编译是必须处理才能正常编译,所以这里写一个运行时异常
if(sex.equals(”
男”) ||sex.equals(”
女”)){
this.sex= sex;
}
else{
thrownew RuntimeException(”
性别错误”);//
自己不做处理,抛出异常对象,由调用者处理。该异常对象的构造方法的参数是message信息,即出现异常时的信息。如果调用者不对该异常作出处理,那么异常抛给虚拟机,虚拟机就按照默认的异常处理方式打印该异常信息。即输出该异常对象。
}
}
}
package lianxi;
import java.util.Scanner;
public class Lianxi6 {
publicstatic void main(String[] args) {
Students = new Student();
//s.setSex(“nann”);//
输入的性别不是男和女,触发异常。抛出异常后并没有对异常做出处理,所以就是按照默认的处理方式,在控制台打印异常信息,程序异常终止。
//
为了不让异常终止,我们要对异常进行处理。
try{
s.setSex(“nann”);
}catch(RuntimeExceptione){
//System.out.println(”
出错啦,性别异常”);//
出现异常时,程序就不会异常终止了。
//
System.out.println(e);//
重写toString
方法
,默认输出该异常对象。//java.lang.RuntimeException:
性别错误。//前面是类的信息,后面是错误信息。
//System.out.println(
e.getMessage
());//
输出:性别错误。该message
就是在new对象的时候传入的参数。
e.printStackTrace()
;//java.lang.RuntimeException:
性别错误
//atlianxi.Student.setSex(Student.java:16)
//atlianxi.Lianxi6.main(Lianxi6.java:14)
//
堆栈输出,虚拟机默认输出异常时就是调用了这种方法,堆栈输出时包含了toString
方法。
}
//System.out.println(s);//Student[sex=null](
在Student
类中重写toString方法),输出的结果是sex=null,因为性别异常,所以就是默认值
}
}
子类继承父类重写父类方法时,子类throws
的异常类型如果是编译时异常,必须是父类中声明的编译时异常类型的子集。
代码示例:
class Fu{
publicvoid test() throws SQLException{//
父类的异常类型是编译时异常。
}
}
class Zi extends Fu{
publicvoid test() throws InputMismatchException{}//
重写父类方法,声明的异常类型是运行时类,编译不会出错
}
class Fu1{
publicvoid test() throws InputMismatchException{//
父类的异常类型是运行时异常。
}
}
class Zi1 extends Fu1{
publicvoid test() throws SQLException{}//
重写父类方法,声明的异常类型是编译时异常,编译会出错,因为子类声明的编译时异常必须是父类编译时异常的子集。
}
class Fu2{
publicvoid test() throws InputMismatchException,TimeoutException{//
父类的异常类型有运行时异常,也有编译时异常,编译时仍然会报错,因为子类中的编译时异常类型(SQLException
)不是父类编译时异常类型(TimeoutException)的子集。
}
}
class Zi2 extends Fu2{
publicvoid test() throws SQLException{}//
子类声明的编译时异常类型不是父类编译时类型的子集,所以编译出错。
}
class Fu3{
publicvoid test() throws InputMismatchException,SQLException{//
父类中的异常声明也可以直接写Exception
,这样就包含了任何异常,子类中无论什么编译时异常类型在编译时都不会出错。
}
}
class Zi3 extends Fu3{
publicvoid test() throws SQLException{}//
子类声明的编译时异常类型是父类编译时类型的子集,所以编译正常。
}