1. 异常由来:
问题也是现实生活中的一个具体事物,也可以通过程序进行描述,然后java类将其封装成对象。即把问题封装成对象。对于问题分两种情况,严重和不严重。严重则为Error类。非严重的java通过Exception类进行描述。当一个异常发生时,会有几件事随之而来,首先,像普通对象一样,通过new在堆上创建一个异常对象。然后当前程序的执行路径不能被继续下去,并且从当前环境中弹出异常对象的引用。此时异常处理机制接管程序,并开始寻找一个合适的地方去执行程序。这个恰当的地方就是异常处理程序,他使得程序从错误中出来,要么换种方式执行,要么继续执行。
2. 异常的体系:
Throwable
Error:错误。通常出现重大问题,比如内存溢出,不编写代码针对其进行处理。
Exception:异常。程序在运行时出现的一些非正常情况。可以用try-catch-finally进行处理.
3. 对异常的处理
虚拟机内部有自己的异常处理机制:只要程序出现异常,就提前停止运行程序。Java提供了特有的语句进行处理。
Try(){
可能发生异常的代码块
}catch(异常类 变量){
对异常的处理
}finally{
一定会执行的语句
}
现在用try—catch进行处理。
示例:
public class Exceptions {
public staticvoid main(String[] args){
int a=3;
System.out.println("请输入一个整数");
Scanner sc= new Scanner(System.in);
int b =sc.nextInt();
try{
int c =a/b; //输入的b假如是0,则会发生异常。
System.out.println(c);
}catch(Exception e[李艳1] ){
e.printStackTrace();
}
}
}
运行结果:
请输入一个整数
0
java.lang.ArithmeticException: / by zero
atexception.Exceptions.main(Exceptions.java:22)
ArithmeticException: 计算异常。由此也可知,那句话发生了异常,则try中后边的代码不会再运行。
4. 打印异常信息的几种函数:
1> getMessage() 这个函数只会获取到信息,但是不会打印出来,需要打印则需要用输出语句,比如:System.out.println(“e.getMessage()”) 打印异常信息。
示例:/ by zero
2> getStackTrace():获取异常信息。[Ljava.lang.StackTraceElement;@4aa298b7
3> printStackTrace():打印出异常信息,异常名称,异常发生位置。无需再次调用输出函数。其实默认的异常处理机制就是在调用该方法。
示例:java.lang.ArithmeticException:/ by zero
at exception.Exceptions.main(Exceptions.java:22)
4> ToString():不常用,打印异常名称和异常信息。
示例:java.lang.ArithmeticException:/ by zero
5. 异常声明机制
你自己写的程序输入时知道传入0会有问题,但是别人用不知道,所以可能会传入0,故你需要给别人一个提示:也就是声明异常,告诉别人我这里可能有异常发生。这样别人就会注意。
声明方法:
在功能上使用Throws的关键字声明了该功能可能会出现问题。
public static int div(int a,int b)throws Exception{
int c =a/b;
return c;
}
告诉调用者,我这里有一个异常,让调用者自己选择处理不处理,可以处理(用try-catch),也可以直接抛给别人(继续在调用时选择throws,此时抛给了虚拟机)。但是如果两种方法都不选择,则编译失败。
6. 多异常处理
同一个代码可能不止发生一种异常。此时要对不同的异常进行处理。
可以在声明异常时抛出多个异常
1》Throws异常名1,异常名2,….异常名n。
2》或者用多个catch进行捕捉,但是catch中必须写对应的处理。
尽量不要用异常父类直接进行捕捉,因为用父类捕捉,相当于隐藏问题,发生了问题但是没有进行处理,程序仍然在运行,相当于有个潜在的风险。
1> 建议声明更为具体的异常。这样才会处理的越具体。
2> 对方声明几个异常,就进行几个异常处理。
3> 先捕获子类,再捕获异类。就比如假设你让老大在前面,发生的问题大哥都搞定了,小弟的存在就是多余,所以应该先让小弟处理,再找大哥。
7. 自定义异常:
Java中会出此案一些特定的问题,而这些问题并未被java描述并且封装成对象,对于这些特有问题,可以按照java封装思想,可以将其封装成自定义异常。
如何自定义异常?
需求:做一个除法运算,除数为零和负数都不可以。为0的情况已经被Java封装,所以为负数的情况需要自己定义一个类,对这个问题进行描述。
定义异常类:一般是描述问题方法+Exception后缀名。有了名字后,还需要入伙,这样才能算是异常中的一个成员,故所有自定义异常都需要继承Exception类。当函数内部出现了throw抛出了异常对象,则必须给出对应的处理动作。要么在内部try-catch,要么在函数上声明,让调用者处理。一般函数内出现异常,函数上需要给出声明。
如何自定义呢?父类已经完成了异常信息的操作,子类构造时只需通过getMessage()获取异常信息即可。
示例:
class FushuException extends Exception{
private intvalue;
FushuException(String msg,int value){
super(msg);
this.value = value; //获取到出错的值
}
public intgetValue() {
returnvalue;
}
}
class Demo{
int div(int a,int b) throws FushuException{
if(b<0){
thrownew FushuException("除数不能为负数",b);
}
return a/b;
}
}
8. throws和throw的区别:
1. throw使用在函数内,throws使用在函数上。
2. throws后跟异常类,用逗号隔开。Throw跟的时异常对象。
Throw是用来异常说明的,为了让调用者知道这里可能发生异常。。
9.运行时异常(RuntimeException)
如果在函数内容上抛出此异常,函数上不用声明,编译也可以通过。如果在函数上声明了该异常,调用者可以不用处理,编译一样通过。之所以不用声明,是不希望调用者处理,一旦发生问题,就希望程序停下来,修改代码解决问题,而不是将问题隐藏。这样看来,如果你自定义一个异常而不向声明时,可以让他继承RuntimeException类。因为运行时异常类java虚拟机已经默认声明了。
/*
* To change thislicense header, choose License Headers in Project Properties.
* To change thistemplate file, choose Tools | Templates
* and open thetemplate in the editor.
*/
package exception;
import java.util.logging.Level;
import java.util.logging.Logger;
/** 为一个类定义两个方法f()和g(),在g里抛出一个自定义异常,然后在f里调用g,
* 然后捕获异常,并且在catch里抛出另一个异常,在main中测试该异常。
*
* @author dell
*/
public class Two {
public staticvoid main(String[] args) {
try {
Two x =new Two();
x.f(3);
x.g(-1);
} catch(AException ex) {
ex.printStackTrace();
} catch(BException ex) {
Logger.getLogger(Two.class.getName()).log(Level.SEVERE, null, ex);
}
}
//定义方法
void g(int a) {
if(a<0)
thrownew AException("参数不可以小于0");
}
void f(int b){
Two two =new Two();
try {
two.g(b);
} catch(AException ex) {
ex.printStackTrace();
thrownew BException("都说了参数不能为0");
}
}
}
//异常1
class AException extends RuntimeException{
publicAException(String msg) {
super(msg);
}
}
//异常2
class BException extends RuntimeException{
publicBException(String message) {
super(message);
}
}
10 使用finally进行异常清理
对于一些代码,很多时候,无论异常是否发生,都希望执行,经常适用于内存回收之外的情况(因为内存回收由虚拟机执行)。对于这部分代码,可以将其放在finally块中执行。
Finally用来做什么?
对于没有垃圾回收机制的语言中,finally显得尤为重要,但是java有这个机制,所以不需要考虑回收内存。但是对于释放资源,或者关闭一些链接之类的东西,需要用到finally块,比如你打开一个文本文件,在里边写东西,当然希望无论你写入成功失败,都必须保证在main方法结束时可以关闭文件夹,这样就可以把关闭的代码放在finally中。当涉及到break和continue语句时,finally也会被执行。
try {
Two x =new Two();
for(inti=0;i<=0;i++){
break;
}
x.f(3);
x.g(-1);
} catch(AException ex) {
ex.printStackTrace();
} catch(BException ex) {
Logger.getLogger(Two.class.getName()).log(Level.SEVERE, null, ex);
}finally{
System.out.println("finally块被执行了");
}
执行可发现,还是会执行finally中的。
[李艳1]这句被执行其实是相当于:Exceptione = new ArithmeticException()