您的位置:首页 > 编程语言 > Java开发

Java基础知识之异常处理机制

2016-02-27 20:20 549 查看
一:异常概述 1.异常:就是程序在运行时出现的不正常情况.2 异常的由来:问题也是现实生活中的一个具体的事物,也可以通过Java的类的形式进行描述并封装成对象.其实就是Java对不正常的情况进行描述后的对象体现.
3.已经见过的异常:比如角标越界,空指针等都是。就对这些问题进行分类。而且这些问题都有共性内容比如:每一个问题都有名称,同时还有问题描述的信息,问题出现的位置,所以可以不断的向上抽取。形成了异常体系。二:异常体系对于问题的划分为两种:一种是严重的问题:Error,一种是非严重的问题Exception.Error:一般不编写正对性的代码对其进行处理;Exception:可以使用针对性的处理方式进行处理.异常的体系Throwable
|--Error严重问题,我们不处理,比如内存溢出。
|--Exception|--RuntimeException
运行期异常,肯定是我们的代码不够严谨,我们需要修正代码|--非RuntimeException 编译期异常,必须处理的,否则程序编译不通过举例:出国旅游
1.当你提着行李到机场发现,机场被炸掉了,严重的问题.2.飞机在出发前,发现没有油了,应该加油,出发前需要检查的问题;
3.飞机出发后,出现了强大气流,需要迫降,飞行过程中出现的问题;异常的处理:1.JVM的默认处理:如果程序没有定义异常的处理代码,JVM会有默认的处理方案:
把异常的名称,原因,位置等信息输出在控制台,但是程序不能继续执行了。2.自己处理:a:
Java提供了特有的语句进行处理:try{
需要被检测的代码;}catch(异常类 变量名){
处理异常的代码(处理方式);}
finall{一定会被执行的代码(释放资源);
}b:throws
把自己处理不了的,在方法上声明,告诉调用者,这里有问题

例如:
public class ExceptionDemo {
public static void main(String[] args) {

}

public static void method(){
int a = 10;
// int b = 2;
int b = 0;

try {
System.out.println(a / b);
} catch (ArithmeticException e) {
System.out.println("除数不能为0");
}
finally{
System.out.println("一定会执行的代码");
}
}

}


3.异常体系特点:

        1.异常体系中的所有类以及建立的对象都具备可抛性.

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

        3.只有异常体系具备这个特点.
4.Exception的子类名大都是以父类名作为后缀.

4.多个异常的处理:

a:每一个异常就写一个try...catch;麻烦代码看起来非常的杂乱.
b:写一个try,多个catch

  try{

  ...

  }catch(异常类名 变量名) {

  ...

  }

  catch(异常类名 变量名) {

  ...

  }

  ...
注意:
1.出现的异常能尽量明确具体的异常类,用确切的具体异常类来处理.
2.出现多个异常的时候,异常出现了继承关系,父类异常应该放在最后面.

c:JDK7出现了一个新的异常处理方案:
try{

 

  }catch(异常名1 | 异常名2 | ...  变量 ) {

  ...

  }

 

  注意:

  A:处理方式是一致的。(实际开发中,很多时候可能就是针对同类型的问题,给出同一个处理)
B:多个异常间必须是平级关系。

建议:在进行catch处理的时候,catch中一定要定义具体的处理方式,不要简单的书写一条输出语句.

三.异常分类

1.编译时异常:Java程序必须显示处理,否则程序就会发生错误,无法通过编译
程序在运行中可能出现的问题,也可能不会出现问题,所以就需要对可能出现问题的代码进行一些处理,
如果程序在运行时出现了,就可以及时进行处理异常,不至于导致程序停止.

2.运行时异常:无需显示处理,也可以和编译时异常一样处理

RuntimeException(运行时异常):
是指因设计或实现方式不当而导致的问题.
说白了,就是程序员造成的,程序员小心谨慎是完全可以避免的异常.比如,
事先判断对象是否为null就可以避免NullPointerException异常,
事先检查除数不为0就可以避免ArithmeticException 异常;
特点:
这种异常Java编译器不会检查它,也就说程序中出现这类异常的时候,即使不处理也没有
问题,但是一旦出现异常,程序将异常终止,若采用异常处理,则会被相应的程序执行处理.

代码:

public static ExceptionDemo{
public static void main(String[] args) {
int[] arr = { 1, 2, 3 };

//访问数组不存在的第三个角标,会出现数组角标越界异常.
System.out.println(arr[3]);

}
}
//程序会停止抛出ArrayIndexOutOfBoundsException。


3.对于捕获到异常进行操作的常见方法

String getMessage():获取异常信息,返回字符串。
String toString():获取异常类名和异常信息,返回字符串。
返回此 throwable 的简短描述。结果是以下字符串的串联: 
此对象的类的 name 
": "(冒号和一个空格) 
调用此对象 getLocalizedMessage() 方法的结果 
如果 getLocalizedMessage 返回 null,则只返回类名称。
void printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置。JVM的默认处理

void printStackTrace(PrintStream s):通常用该方法将异常内容保存在日志文件中,以便查阅。 

4.声明异常:throws

 有些时候,我们是可以对异常进行处理的,但是又有些时候,我们根本就没有权限去处理某个异常。

  或者说,我处理不了,我就不处理了。

  为了解决出错问题,Java针对这种情况,就提供了另一种处理方案:抛出。

  
格式:

  throws 异常类名

  注意:这个格式必须跟在方法的括号后面。

注意:

  尽量不要在main方法上抛出异常。
因为调用main方法的是JVM,如果main方法抛出,发生异常时,就会由JVM默认处理.

  
小结:

  编译期异常抛出,将来调用者必须处理。

  运行期异常抛出,将来调用可以不用处理。

throw:在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。

在程序内部抛出一个异常对象,抛出异常类的对象;
若 throw 抛出的是 RuntimeException:
程序可以显示使用 try...catch 来捕获并处理,也可以不管,直接交给方法调用者处理;
若 throw 抛出编译时异常:
要么放在 try 里自己处理,要么放在一个 throws 声明的方法里面,交给调用者处理。

例如:
public class ExceptionDemo {

public static void method2() {
int a = 10;
int b = 0;
if (b == 0) {
throw new ArithmeticException();
} else {
System.out.println(a / b);
}
}
public static void mehtod1() thorws ArithmeticException{

int a = 10;
int b = 0;
System.out.println(a/b);
}
}


5.到底如何处理异常:

原则:如果该功能内部可以将问题处理,用try,如果处理不了,交由调用者处理,这是用throws
区别:
后续程序需要继续运行就try
后续程序不需要继续运行就throws

6.异常处理的变形格式:
try...catch...finally
try...catch...
try...catch...catch...
try...catch...catch...fianlly
try...finally

catch是用于处理异常的,如果没有catch语句就代表异常没有被处理过,如果该异常时编译时异常,必须要声明.

7.finally

finally用于释放资源,它的代码永远会执行。特殊情况:在执行到finally之前jvm退出了,
  当执行到System.exit(0),fianlly不会执行。

四.自定义异常:

因为在实际开发中,会出现特有的异常,而这些问题并没有被Java所描述并封装成对象,
所以对于这些问题按照Java的封装思想,将特有问题进行自定义的异常封装.
而我们自己写的类是不能作为异常类来看,如果想要一个类是异常类,就必须要是异常体系中的一员.

两种方式:

继承Exception:如果是编译时的异常,就让自定义异常继承Exception;
继承RuntimeException:如果该异常的发生,无法再继续进行运算.让自定义异常继承RuntimeException;
继承异常体系的原因:
异常体系有一个特点,异常类和异常对象都被抛出,他们具备可抛性,这个可抛性是Throwable这个体系中的独有特点,
只有这个体系中的类和对象才可以被throw和throws操作.

如何自定义异常信息?

因为父类中已经把异常星系的操作都完成了,
所以子类只要在构造时,将异常星系传递给父类的,通过super语句,
就可以直接通过getMessage()方法获取自定义的异常信息.
继承自Exception或者RuntimeException,只需要提供无参构造和一个带参构造即可;



注意:


异常在子父类覆盖的体现
1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或者该异常的子类.
2.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法的时候,也不能抛出异常.
3.如果子类方法发生异常,就必须要进行try...catch处理,绝不能抛.

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

或者异常可以处理,当需要将异常产生后和本功能相关的问题提供出去,让调用者知道。并处理。

也可以将捕获异常处理后,转换新的异常。
例如:
public class MyException extends Exception {
public MyException() {
}

public MyException(String message) {
super(message);
}
}

五.异常好处
1、将问题进行封装.

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

异常练习:

/*
毕老师用电脑上课。

开始思考上课中出现的问题。

比如问题是
电脑蓝屏。
电脑冒烟。

要对问题进行描述,封装成对象。

可是当冒烟发生后,出现讲课进度无法继续。

出现了讲师的问题:课时计划无法完成。

*/
//自定义蓝屏异常
class LanPingException extends Exception
{
LanPingException(String message)
{
super(message);
}
}
//自定义冒烟异常
class MaoYanException extends Exception
{
MaoYanException(String message)
{
super(message);
}
}
//自定义无法上课异常。
class NoPlanException extends Exception
{
NoPlanException(String msg)
{
super(msg);
}
}
//电脑类
class Computer
{
private int state = 1;
public void run() throws LanPingException,MaoYanException
{
if(state==2)
throw new LanPingException("蓝屏了");
if(state==3)
throw new MaoYanException("冒烟了");

System.out.println("电脑运行");
}
public void reset()
{
state = 1;
System.out.println("电脑重启");

}
}
//老师类
class Teacher
{
private String name;
private Computer cmpt;

Teacher(String name)
{
this.name = name;
cmpt = new Computer();

}

public void prelect()throws NoPlanException
{
try
{
cmpt.run();
}
catch (LanPingException e)
{
cmpt.reset();
}
catch (MaoYanException e)
{

test();
throw new NoPlanException("课时无法继续"+e.getMessage());

}
System.out.println("讲课");
}
public void test()
{
System.out.println("练习");
}

}

class ExceptionTest
{
public static void main(String[] args)
{
Teacher t = new Teacher("毕老师");
try
{
t.prelect();
}
catch (NoPlanException e)
{
System.out.println(e.toString());
System.out.println("换老师或者放假");
}

}
}
/*
当电脑蓝屏的时候:
电脑重启,上课;
当电脑冒烟的时候:
学生做做练习
NoPlayException: 课时无法继续  原因是冒烟
换老师或者放假
*/


六.面试题


1.throw和throws有什么区别?

throw:是使用在函数内,后面跟的是异常对象. 只能抛出一个异常对象
     表示抛出异常,由该方法的内部的语句处理. throw则是抛出了异常,执行throw则一定抛出了某种异常

throws:是使用在函数方法声明上,跟的是异常类名. 可以声明多个异常类名.用逗号隔开. 
      表示抛出该异常,由该方法的调用者去处理.throws表示可能会有某些异常发生,但并不一定会发生.

2.编译期异常和运行期异常的区别?

编译期异常 必须要处理的,否则编译不通过
运行期异常 可以不处理,也可以处理

3.final,finally,finalize的区别?

final:是关键字,最终的意思,可以修饰类,成员变量,成员方法.
修饰类,类不能被继承;
修饰变量,变量是常量;
修饰方法,方法不能被重写;
finally:是异常处理的一部分,里面写的代码一定会被执行,用于释放资源,
特殊情况是在执行到finally的时候JVM退出了.
finalize:是Object类里面的方法,用于垃圾回收.

4.如果catch里面有return语句,请问finally里面的代码还会执行吗?如果会,请问是在return前,还是return后。
会执行,在return的前面。
准确的说,应该是在中间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  异常处理