1、异常
(1)概念:异常就是程序运行时出现不正常情况,是对问题的描述,将问题进行对象封装。
示例:
运行结果:
说明:上述程序运行过程中由于出现除数为零的情况,所以抛出ArithmeticException异常,当程序出现异常后程序中断,所以程序后面的语句不会执行。
(2)异常由来:问题也是现实生活中一个具体的事物,也可以通过JAVA的类的形式进行描述并封装成对象,其实就是JAVA对不正常情况进行描述后的对象体现。
(3)对于问题的划分:
-严重的问题:JAVA通过Error类进行描述,对于Error一般不编写针对性的代码对其进行处理。
-非严重的问题:JAVA通过Exception类进行描述,对于Exception可以使用针对性的处理方式进行处理。
(4)异常的体系:
-Error:通常出现重大问题如运行的类不存在或内存溢出等。
-Exception:在运行时出现的一起情况。
Exceptin和Error的子类名都是以父类名作为后缀。
(5)异常的处理:JAVA提供了特有的语句进行处理:
格式:
try
{
//需要被检测的 代码
}
catch(异常类 变量)
{
//外理异常的代码(处理方式)
}
finally
{
// 一定会执行的语句
}
示例:
class Demo
{
publicint div(int a,int b)
{
returna/b;
}
}
public class ExceptionDemo
{
publicstatic void main(String[] args)
{
Demod=new Demo();
//将可能出现异常的代码放在try块中
try
{
intx=d.div(4,0);
System.out.println(x);
}
//catch捕捉异常并对异常进行处理
catch(Exceptione)
{
System.out.println(e.getMessage());
}
System.out.println("over");
}
}
运行结果:
说明:上述程序中对将可能发生异常的语句写在try语句内,并用catch语句对产生的异常进行捕抓,在catch语句内对捕抓到的异常进行处理后,程序继续执行后面的语句。
(6)对捕获到的异常对象进行常见方法操作:
-String getMessage():获取异常信息。
-String toString():获取异常名称和异常信息。
-void printStackTrace():打印异常名称、异常信息和异常出现的位置。其实JVM默认的异常处理机制就是在调用printStackTrace方法,打印异常的堆栈的跟踪信息。
(7)throwsException:在功能上通过throws的关键字声明了该功能有可能会出现问题。在函数上声明异常,便于提高安全性,让调用者进行处理,不处理编译失败。
示例:
class Demo
{
//定义方法时声明该方法可能会发生异常
publicint div(int a,int b)throws Exception
{
returna/b;
}
}
public class ExceptionDemo1
{
publicstatic void main(String[] args)
{
Demod=new Demo();
//调用可能发生异常的方法时没有对异常进行处理
intx=d.div(4,1);
System.out.println(x);
System.out.println("over");
}
}
运行结果:
说明:上述程序中在div方法定义时将可能发生的异常用throws语句抛出,所以该功能的调用者必须对该异常进行处理或者同样用throws将其抛出,否则编译失败。
(8)对多异常的处理:
-在声明异常时,建议声明更为具体的异常,这样处理的可以更具体。
-对方声明几个异常,就对应有几个catch块,不要定义多余的catch块。如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。
-建议在进行catch处理时,catch中一定要定义具体处理方式。不要简单定义一句e.printStackTrace(),也不要简单的书写一条输出语句。
示例:
class Demo
{
int div(int a,int b) throws ArithmeticException,ArrayIndexOutOfBoundsException //在定义方法是声明了多个可能会发生的异常
{
int[] arr=new int[a];
System.out.println(arr[4]);
return a/b;
}
}
classExceptionDemo
{
public static void main(String[] args)
{
Demo d=new Demo();
//将可能会发生异常的语句放在try块中
try
{
int x=d.div(4,1);
System.out.println(x);
}
//对ArithmeticException异常处理的catch块
catch(ArithmeticException e)
{
System.out.println(e.toString());
}
//对ArrayIndexOutOfBoundsException异常处理的catch块
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println(e.toString());
}
}
}
说明:上述程序中,在定义div方法时将两种可能发生的异常抛出,所以在调用该方法的地方定义了两个catch块对相应的异常进行针对性的处理。
(9)自定义异常
自定义异常定义:因为项目中会出现特有的问题,而这些问题并未被JAVA所描述并封装对象,所以对于这些特有的问题可以按照JAVA的对问题封装的思想,将特有的问题进行自定义的异常封装。
自定义异常的处理:JAVA的异常可以自动封装成对象并抛出,而自定义的异常只能手动建立对象并且只能手动抛出。当在函数内部出现了throw抛出异常对象,那么就必须要给出典对应的处理动作,要么在内部try catch处理,要么在函数上声明让调用者处理。一般情况下,函数内出现异常,函数上需要声明。
示例:
//自定义一个异常类
class FuShuException extends Exception
{
FuShuException(Stringmessage)
{
super(message);
}
}
class Demo
{
//定义可能会抛出FuShuException异常的方法
publicint div(int a,int b)throws FuShuException
{
//当b小于0时抛出FuShuException异常
if(b<0)
thrownew FuShuException("/by FuShu");
returna/b;
}
}
public class ExceptionDemo2
{
publicstatic void main(String[] args)
{
Demod=new Demo();
//将可能发生异常的代码放在try块中
try
{
//调用可能发生异常的方法
intx=d.div(4,-1);
System.out.println(x);
}
//对FuShuException异常进行捕捉和处理的catch块
catch(FuShuExceptione)
{
System.out.println(e.toString());
}
}
}
运行结果:
说明:上述程序中自定义了一个FuShuException异常,当div方法中除数为负数时就会发生该异常,此时需要在可能发生该自定义异常的div方法内部用throw手动抛出该异常,并且在函数上用throws声明,在调用该方法的地方需要对该异常进行处理。
注意:因为自定义异常的父类中已经把异常信息的操作都完成了,所以子类只要在构造时将异常信息通过super语句传递给父类,那么就可以直接通过getMessage方法获取自定义的异常信息。
注意:对于自定义异常,必须是自定义类继承Exception。因为异常体系有一个特点,异常类和异常对象都被抛出,他们都具备可抛性,这个可抛性是Throwable这个体系中的独有特点,只有这个体系中的类和对象才可以被throws和throw操作。
(10)throws和throw的区别:
-throws使用在函数上,throw使用在函数内。
-throws后面跟的是异常类,可以跟多个,异常类之间用逗号隔开,throw后面跟的是异常对象。
(11)RuntimeException:RuntimeException(运行时异常)是Exception中的一个特殊的子类异常,如果在函数内抛出该异常,函数上可以不用声明,编译一样通过,如果在函数上声明了该异常,调用者可以不用进行处理,编译一样通过。之所以不用在函数声明,是因为不需要让调用者处理,当该异常发生后,希望程序停止,因为在运行时,出现了无法继续运算的情况,希望停止程序后对代码进行修正。
示例:
//定义自定义异常FuShuException
class FuShuException extends RunTimeException
{
FuShuException(String message)
{
super(message);
}
}
class Demo
{
//定义一个可能会抛出FuShuException异常的方法
public int div(int a,int b)
{
//当b小于零时抛出FuShuException异常
if(b<0)
throw newFuShuException("/by FuShu");
return a/b;
}
}
public classExceptionDemo2
{
public static void main(String[] args)
{
Demo d=new Demo();
//由于FuShuExceptionextends 继承RuntimeException,所以可以不用try进行处理
int x=d.div(4,-1);
System.out.println(x);
}
}
说明:上述程序中,自定义异常FuShuException继承了RuntimeException,所以在div方法内抛出FuShuException异常时,可以不用在函数上声明,并且在调用该方法的地方也不用对该异常处理,编译一样可以通过,当发生程序中发生除数为负数即发生了FuShuException异常时,程序会停止。
注意:自定义异常时,如果该异常的发生,无法再继续进行运算,就让自定义异常继承RuntimeException。
对于异常分两种:
-编译时被检测的异常。此种异常可以被调用者处理。需要在函数上声明。
-编译时不被检测的异常(运行时异常,RuntimeException以及其子类)。此种异常不希望被调用者处理,希望出现异常时停止程序进行代码修正,不需在函数上声明。
(12)finally:finally中放的是一定会被执行的语句。finally只有一种情况不会执行,即当执行到System.exit(0)的时候,finally不会执行。finally代码块通常用于定义关闭资源的代码。
(13)异常在子父类覆盖中的体现:
-子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或者该异常的子类或者不抛出异常。
-如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
-如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时也不可以抛出异常。如果子类方法发生了异常,就必须要进行try处理,绝对不能抛。
(14)练习:获取一个长方形的面积,如果面积出现非法值,视为是获取面积出现问题,问题通过异常来表示。
//自定义一个异常类
class NoValueException extendsRuntimeException
{
NoValueException(Stringmessage)
{
super(message);
}
}
class Rec
{
privateint len,wid;
publicRec(int len,int wid)
{
//当len或wid小于0时抛出NoValueException异常
if(len<=0|| wid<=0)
thrownew NoValueException("wrong value");
this.len=len;
this.wid=wid;
}
publicvoid getArea()
{
System.out.println(len*wid);
}
}
public class ExceptionDemo3
{
publicstatic void main(String[] args)
{
//由于自定义异常NoValueException是RuntimeException类的子类,所以可以不用处理
Recr=new Rec(4,-3);
r.getArea();
}
}
运行结果:
(15)异常的好处:
-将问题进行封装。
-将正常流程代码和问题处理代码相分离,方便于阅读。
(16)异常的处理原则:
-处理方式有两种:try或throws。
-调用到抛出异常的功能时,抛出几个,就处理几个,一个try处理多个catch。
-多个catch时,父类的catch放到最下面。
-catch内,需要定义针对性的处理方式,不要简单定义printStackTrace,也不要不写,当捕获到的异常本功能处理不了时,可以继续在catch抛出。如果该异常处理不了,但并不属于该功能处理的异常,可以将异常转换后,再抛出和该功能相关的异常。或者异常可以处理,当需要将异常产生的和本功能相关的问题提供出去,当调用者知道并处理,也可以将捕获的异常处理后,转换新的异常抛出。
2、包
(1)作用:
-对类文件进行分类管理。
-给类提供多层命名空间。
-写在程序文件的第一行。
-类名的全称是包名.类名。
-包也是一种封装形式。
(2)格式:
package 包名;
编译时:javac -d 包目录路径 源文件,会自动在包目录路径下建立一个以包名命名的文件夹,编译后的class文件会保存在该文件夹下。
(3)包与包之间的访问:
-被访问的包中的类以及类中的成员需要public修饰。
-不同包中的子类可以直接访问父类中被protected修饰的成员。
-包与包之间可以使用的权限只有两种,即public和protected。
(4)import关键字:import关键字可以导入不同包中的类。
格式:import 包名.类名
import 包名.*
建议不要写通配符*,需要用到包中的哪个类就导入哪个类。
当导入的多个包中有相同名字的类名,在调用这些类时需要加包名,建立包名不要重复,建议定义包名时不要重复,可以使用url来完成定义,因为url是唯一的。