您的位置:首页 > 职场人生

黑马程序员——异常

2015-06-11 11:44 525 查看
——- android培训java培训、期待与您交流! ———-

什么是异常?

就是程序运行时出现不正常情况。

异常由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述。并封装成对象。

其实就是java对不正常情况进行描述后的对象体现

对于问题的划分:两种:一种是严重的问题,一种是非严重的问题。

对于严重的:java通过Error类进行描述。

对于Error一般不编写针对性的代码对其进行处理。

对于非严重的:java通过Exception类进行描述。

对于Exception可以使用针对性的处理方式进行处理。

无论Error或者Exception都具有一些共性内容。

比如:不正常情况的信息,引发原因等。

异常中的体系结构:

Throwable

+++++|—Error

+++++|—Exception

+++++++++++|—RuntimeException

异常的语法:

java特供了特有的语句进行处理。

try{

需要被检测的代码;

}

catch(异常类 变量){

处理异常代码:(处理方式)

}

finally{

一定会执行的语句;

}

代码示例:

/*
异常的使用:
*/
class ExceptionDemo {
int div(int a, int b){

return a / b;   //此处抛出new ArithmeticException()异常,算数异常
}
}
public class Demo {
public static void main(String[] args) {
ExceptionDemo d = new ExceptionDemo();
try{
//此处检测是否有new ArithmeticException()异常,将异常传给catch
int x = d.div(5,0);
System.out.println(d.div(5, 0));
}
//此处捕获异常,相当于Exception e = new ArithmeticException();
catch(Exception e){
System.out.println("被除数不能为零");
//System.out.println(e.getMessage());   //    /by zero
//System.out.println(e.toString());//异常名称:异常信息

//e.printStackTrace();// 异常名称,异常信息,出现异常的位置。
//jvm默认的异常处理机制,就是在调用printStackTrace()方法
//打印异常的堆栈的跟踪信息
}
System.out.println("over");
/*
结果:
被除数不能为零
over
*/
}
}


throws关键字:

在编写程序时,如果某个函数在功能上可能会出现问题,

那么就在函数上通过throws声明该功能可能会出现问题,

这样做的好处是,让使用这个函数的方法必须try

如:

int div(int a, int b) throws Exception{//在功能上通过throws的关键字声明了该功能可能会出现问题
return a / b;   //  因为a/b,如果b的值为0,那么会出问题,所以得在函数上声明此函数可能出问题
}


代码示例:

/*
在函数上声明异常。
便于提高安全性,让调用者进行处理,不处理则编译失败
*/
class ExceptionDemo {
int div(int a, int b) throws Exception{//在函数上通过throws的关键字声明了该功能有可能会出现异常
return a / b;
}
}
public class Demo {
public static void main(String[] args) //throws Exception
{
ExceptionDemo d = new ExceptionDemo();
try {//因为已经知道了div()功能有可以会出现异常,那么此处必须处理异常,
//否则该方法必须也用throws声明可能会出现异常
System.out.println(d.div(5, 4));
} catch (Exception e) {
System.out.println("被除数不能为零");
}
System.out.println("over");
/*
结果:
1
over
*/
}
}
//简而言之:用throws关键字声明方法可能会出现异常,那么在使用该方法时,
//要么处理异常,要么再用throws关键字声明可能会出现异常


多异常:

1.声明异常时,建议声明更具体的异常。这样处理的可以更具体。

2.对方声明几个异常,就对应有几个catch块。不要定义多余的catch块。

如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。

如果将父类异常放在最上面,那么会导致下面的异常永远不会执行得到,

那么,下面的异常就相当于废话一样

3.如果有多个catch块,出现异常时只能执行一个catch块,因为一旦发现异常

那么该程序就会直接跳到对应的catch块中执行,所以catch块只能执行一个。

建议:进行catch处理时,catch中一定要定义处理方式。

不要简单定义一句e.printStackTrace(),

也不要简单的就书写一条输出语句,因为这样客户在使用该软件发生异常的时候,

客户不知道这是什么东西,一个简单的输出语句不能解决客户的问题

代码示例:

/*
多异常的使用
*/
class ExceptionDemo {
//在该方法上声明多个异常
int div(int a, int b) throws ArithmeticException,
ArrayIndexOutOfBoundsException {
int[] x = new int[a];
// 若此处出异常则抛出ArrayIndexOutOfBoundsException-->(数组角标越界异常)
System.out.println("x[4]=" + x[4]);
// 若此处出异常则抛出ArithmeticException -->(算数异常)
return a / b;
}
}

public class Demo {
public static void main(String[] args) {
ExceptionDemo d = new ExceptionDemo();
try {
d.div(5, 0);// 执行此方法导致-->算数异常
// d.div(4, 1);//执行此方法导致-->数组角标越界异常
} catch (ArithmeticException e) {
System.out.println("除数不能为零");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组角标越界了");
}
System.out.println("over");
/*
结果:
x[4]=0
除数不能为零
over
*/
}
}


throw关键字:

当在函数内部出现了throw抛出异常对象,那么就必须要给出对应的处理动作。

要么在内部try catch处理。

要么在函数上声明,让调用者处理。

一般情况下,函数内抛出异常,函数上需要声明。

自定义异常:

必须是自定义类继承Exception、Error、Throwable

继承它们的原因:

异常体系有一个特点:因为异常类和异常对象都被抛出。

他们都具备可抛性,这个可抛性是Exception、Error或Throwable

体系中的独有特点。

只有这个体系中的类和对象才可以被throws和throw操作。

如何定义异常信息呢?

因为父类中已经把异常信息的操作都完成了。

所以子类只要在构造时,将异常信息通过super语句传给父类

那么就可以直接通过getMessage或toString方法获取自定义的异常信息。

代码示例:

/*
需求:在本程序中,对于除数是-1,也视为是错误的,是无法进行运算的,
那么就需要对这个问题进行自定义的描述。
*/

//创建一个FuShuException类,继承Exception,那么这个类就成为一个自定义异常类
class FuShuException extends Exception{
private int value;
public FuShuException(String string,int value){
//子类只要在构造时,将异常信息通过super语句传给父类
//那么就可以直接通过getMessage或toString方法获取自定义的异常信息。
super(string);

this.value = value;
}
public int getValue(){
return value;
}
}
class ExceptionDemo {
int div(int a, int b) throws FuShuException {
//如果输入的b小于0,则抛出异常,
//同时函数上通过throws的关键字声明该功能有可能会出现异常
if(b<0)
//手动通过throw关键字抛出一个自定义异常对象
throw new FuShuException("此异常为负数异常",b);
return a / b;
}
}

public class Demo {
public static void main(String[] args) {
ExceptionDemo d = new ExceptionDemo();
try {
d.div(5, -9);
} catch (FuShuException e) {
//通过toString方法获取自定义的异常信息。
System.out.println(e.toString());//结果:此异常为负数异常
//调用自定义异常中错误的值
System.out.println("错误的负数是"+e.getValue());//结果:错误的负数是-9
}

System.out.println("over");
}
}

/*
结果
FuShuException: 此异常为负数异常
错误的负数是-9
over
*/


throws和throw区别:

throws定义在函数上。

throw定义在函数内。

throws后面跟异常类。可以跟多个,用逗号隔开。

throw后面跟异常对象。

特殊的异常RunTimeException

RunTimeException异常

Exception中有一个特殊的子类异常RunTimeException 运行时异常。

如果函数内容抛出该异常,函数上可以不用声明,编译一样通过。

如果在函数上声明了该异常。调用者可以不用进行处理,编译一样通过。

之所以不用函数声明,是因为不需要让调用者处理。

当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止后,

对代码进行修正。

如:

class ExceptionDemo {
int div(int a, int b) //throws ArithmeticException//此处声明异常,调用者可以不用进行处理
{
if(b == 0)
throw new ArithmeticException("除数为0");//此处抛出异常,函数上可以不用声明
return a / b;
}
}


自定义异常时:如果该异常的发生,无法再继续进行运算,

就让自定义异常继承RunTimeException。

代码示例:

/*
RuntimeException异常的演示:
*/
class FuShuException extends RuntimeException {//继承RuntimeException异常
private int value;

public FuShuException(String string, int value) {
super(string);

this.value = value;
}

public int getValue() {
return value;
}
}

class ExceptionDemo {
int div(int a, int b) // throws FuShuException//因为自定义异常继承的是RuntimeException,所以函数可以不用声明异常。因为发成异常时不希望被处理
{
if (b < 0)
throw new FuShuException("此异常为负数异常", b);//抛出异常
if (b == 0)
throw new FuShuException("0不能为除数", 0);
return a / b;
}
}

public class Demo {
public static void main(String[] args) {
ExceptionDemo d = new ExceptionDemo();
// try {

d.div(5, 0);//因为函数没有声明异常,所以这里可以不用try处理

// } catch (FuShuException e) {
// System.out.println(e.toString());
// System.out.println("错误的负数是"+e.getValue())
// }

System.out.println("over");
}
}
/*
运行结果:
Exception in thread "main" FuShuException: 0不能为除数
at ExceptionDemo.div(Demo.java:24)
at Demo.main(Demo.java:34)

*/


finally

finally:定义一定执行的代码。 通常用于关闭资源

finally使用的例子:

public void method(){
try{
连接数据库

//数据操作可能会抛出一个异常 throw new SQLException();
//导致程序无法继续向下运行,最终会导致无法关闭数据库

数据操作
}
catch(SQLException e){

对数据库异常进行处理;

throw new NoException();//处理完异常了之后,必定要返回一个结果
}
finally{
关闭数据库   //将关闭数据库放在finally中,不管数据操作是否成功,都肯定会关闭数据库肯定
}
}


代码示例:

class FuShuException extends Exception {
public FuShuException() {
}
public FuShuException(String string) {
super(string);
}
}

class ExceptionDemo {

public int div(int a, int b) throws FuShuException
{
if (b < 0)
throw new FuShuException("除数不能为负数");
return a / b;
}
}

public class Demo {
public static void main(String[] args) {
ExceptionDemo ed = new ExceptionDemo();
try {
ed.div(5, -2);
} catch (FuShuException e) {
System.out.println(e.toString());
//在此处加了个return语句后,System.out.println("over")就不会执行,
//但是finally中的一句还会执行
return;
}
//finally中的数据肯定会执行
finally {
System.out.println("finally");
}
System.out.println("over");

/*
结果:
FuShuException: 除数不能为负数
finally
*/
}
}


异常的三种使用格式:

第一种格式
try{
}
catch{
}

第二种格式
try{
}
catch{
}
finally{
}

第三种格式
try{
}
finally{
}

//第三种格式的一般使用方式:
//不管程序是否检测到异常,都必须关闭资源
//如:
class ExceptionDemo {

public void function() throws Exception{
try{
throw new Exception();
}finally{
//关闭资源
}
}
}


异常在子父类覆盖中的体现:

1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类,或者进行try处理。

2.如果父类方法抛出多个异常,那么子类在覆盖方法时,只能抛出父类的异常子集,或者该异常的子类,或者进行try处理。

3.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。

如果子类方法发生了异常。就必须要进行try处理,绝对不能抛出。

代码示例:

/*
*
*需求:有一个圆形和长方形。
*都可以获取面积。对于面积如果出现非法的数值,视为是获取面积出现问题。
*问题通过异常表示。
*
*思路:
*1.因为三角形和长方形都是图形,他们就应该具备求面积的方法,
*  所以将求面积的方法定义为抽象的
*
*2.定义三角形和长方形类,继承图形类,实现图形类中求面积的方法
*
*3.在求面积的时候可能会出现非法值,例如:圆的半径= -2。所以应该自定义
*  一个异常类,判断如果输入的数值不非法,那么直接抛出异常。
*
*4.因为数值非法这个异常的不可处理的,所以自定义的异常应该继承RuntimeException
*/
abstract class TuXing { // 图形类
abstract double getMianJi();// 获取面积方法
}

class FuShuException extends RuntimeException {// 自定义异常
public FuShuException() {
}

public FuShuException(String s) {
super(s);//将异常的信息传递给父类
}
}

class YuanXing extends TuXing {// 圆形类
private double r;//半径

public YuanXing() {
this.r = 1.0;
}

public YuanXing(double r) {
if (r <= 0)// 如果输入的值不合法,则抛出异常,让程序终止
throw new FuShuException("不能传入负数或者零");
this.r = r;
}

public double getMianJi() // throws Exception 此处不能抛异常,因为子类覆盖父类方法时, 只能抛父类异常的子类或者自己。如果父类没有抛出异常,那么子类也不可以抛
{
return r * r * Math.PI;
}
}

class ChangFangXing extends TuXing {// 长方形类
private double a, b;

public ChangFangXing() {
a = 1;
b = 1;
}

public ChangFangXing(double a, double b) {
if (a <= 0 || b <= 0)// 如果输入的值不合法,则抛出异常,让程序终止
throw new FuShuException("不能传入负数或者零");
this.a = a;
this.b = b;
}

double getMianJi() // throws Exception 此处不能抛异常,因为子类覆盖父类方法时,
// 只能抛父类异常的子类或者自己。如果父类没有抛出异常,那么子类也不可以抛
{
return a * b;
}

}

public class Demo {
public static void main(String[] args) {
TuXing t = new YuanXing(3);
printMianJi(t);
TuXing t1 = new ChangFangXing(12, -4);//此处传入了一个负数,会导致出现异常,使得程序终止
printMianJi(t1);
/*
结果:
28.274333882308138
Exception in thread "main" FuShuException: 不能传入负数或者零
at ChangFangXing.<init>(Demo.java:60)
at Demo.main(Demo.java:77)

*/
}

public static void printMianJi(TuXing t) {
System.out.println(t.getMianJi());
}
}


总结:

异常是什么?是对问题的描述。将问题进行对象的封装。

异常体系:

Throwable

++++|—–Errow

++++|—–Excepting

+++++++|—–RunTimeException

异常体系的特点:异常体系中的所有类以及建立的对象都具备可抛性。

也就是说可以被throw和throws关键字所操作。

只有异常体系具备这个特点。

throw和throws的用法:

throw定义在函数内,用于抛出异常对象。

throws定义在函数上,用于抛出异常类,可以抛出多个,用逗号隔开。

当函数内容有throw抛出异常对象,并未进行try处理。必须要在函数上声明,否则编译失败。

注意:RunTimeException除外。也就说,函数内如果抛出RunTimeException异常或者RunTimeException

异常的子类,函数上可以不用声明。

如果函数声明了异常,调用者需要进行处理。处理方式可以throws,可以try。

异常有两种:

编译时被检测异常

该异常在编译时,如果没有处理(没有throw也没有try),那么编译失败

该异常被标识,代表着可以被处理。

运行时异常(编译时不检测)

在编译时,不需要处理,编译器不检查。

该异常的发生,建议不处理,让程序停止。需要对代码进行修正。

注意:

1,finally中定义的通常是,关闭资源代码,因为资源必须要释放

2,finally只有一种情况不会执行。当程序执行到System.exit(0)时,fianlly不会执行。

//System.exit(0) –> 系统退出。jvm结束。

自定义异常:

定义类继承Exception或者RunTimeException

1,为了让自定义类具备可抛性。

2,让该类具备操作异常的共性方法。

/*
当要定义自定义异常的信息时,可以使用父类已经定义好的功能。
异常的异常信息传递给父类的构造函数
*/
class MyException extends Exception{
public MyException(String string){
super(string);
}
}


异常的好处:

1,将问题进行封装。

2,将正常流程代码和问题处理代码相分离,方便与阅读。

异常的处理原则:

1,处理方式有两种:try 或者 throws。

2,调用到抛出异常的功能时,抛出几个,就处理几个(不要多处理或者少处理)

一个try对应多个catch。

3,多个catch中,父类的catch放到最下面。

4,catch内,需要定义针对性的处理方式,不要简单的定义printStackTrace,输出语句。

也不要不写。

//当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。
try{
throw new AException();
}
catch(AException e){
throw e;
}


/*
如果该异常处理不了,但并不属于该功能出现的异常。
可以将异常转换后,再抛出和该功能相关的异常。

或者异常可以处理,但需要将异常产生的和本功能相关的问题提供出去,
让调用者知道,并处理。也可以将捕获异常处理后,转换为新的异常。
*/
try{
throw new AException();
}
catch(AException e){
//对AException处理。然后再抛BException
throw new BException();
}


在子父类覆盖时:

1,子类抛出的异常必须是父类异常的子类或者子集。

2,如果父类或者接口中没有异常抛出时,子类覆盖出现异常,只能try,不能抛
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息