java异常处理--用代码说话

1.基本概念

当出现程序无法控制的外部环境问题(如:用户提供的文件不存在,文件内容损坏,网络不可用)时,java就会用异常对象描述。


2.处理

java中使用两种方式来处理异常:

1>在发生异常的地方直接处理;

2>将异常抛给调用者,让调用者处理。


3.异常分类

1>检查性异常 java.lang.Exception

检查性异常:

程序是正确的,但因为外界的环境条件不满足而引发。比如,我晚上要去吃饭,结果,去了饭馆没开门,这是我的错吗?我吃饭(就类似于程序)有错吗?没错,只是外界条件不满足,所以这就是异常。在java中,比如,程序试图打开一个远程并不存在的Socket端口,或者打开不存在的文件时,这不是程序本身的逻辑错误,而很可能是远程机器名字错误,对商业软件系统,程序开发者必须考虑并处理这个问题,java编译器强制要求,处理这类异常类,如果不捕获这些异常,程序不能被编译。


我举一个实际案例来说明问题:


package com.test;


import java.io.FileReader;
import java.net.Socket;


public class test3 {
    public static void main(String[] args) {
        //检查性异常,1.打开文件
        FileReader fr=new FileReader("d:\\aa.text");
       //2.连接一个192.168.1.23 ip的端口号78
        
    }
}

FileReader fr=new FileReader("d:\\aa.text");
这条语句会报错,

未报告的异常错误FileNotFoundException; 必须对其进行捕获或声明以便抛出
----

Socket s=new Socket("192.168.1.23", 78);

会报错:

未报告的异常错误UnknownHostException; 必须对其进行捕获或声明以便抛出
----

就算你写的ip和端口都是对的,但是编译器认为你可能写错了。

所以,检查性异常就是编译器可以事先确认的异常。



2>运行期异常 java.lang.RuntimeException

运行时异常:

这意味着,程序存在bug,如:数组越界,0被除,入参不满足规范...........这类异常需要更改程序来避免。java编译器强制要求处理这类异常。

这类异常,编译通过,这一点上,编译器“并不是足够聪明”。所以,在运行的时候会出错。属于程序逻辑上出了错。一般比较难检查。


3>错误(最严重) java.lang.Error


错误:

       一般很少见,也很难通过程序解决。它可能源于程序的bug,但一般更可能源于环境问题,比如,内存耗尽,错误在程序中处理,

而由运行环境处理。



 java.lang.RuntimeException继承自 java.lang.Exception。

 java.lang.Error和 java.lang.RuntimeException继承自java.lang.Throwable类。

但是顶层类都是java.lang.Throwable



4.异常处理:

1>try.....catch

程序运行产生异常时,将从异常的发生点中断程序,并向外抛出异常信息。

package com.test;


import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;


public class test3 {
    public static void main(String[] args) {
        try {
            //检查性异常,1.打开文件
            FileReader fr=new FileReader("d:\\aa.text");
            //2.连接一个192.168.12.12 ip的端口号4567
             Socket s=new Socket("192.168.1.23", 78);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(test3.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(test3.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

要做到最小捕获异常的原则。是在不知道,可以catch(Exception e),最大的。

捕获结果;

六月 11, 2015 9:47:34 下午 com.test.test3 main
严重: null
java.io.FileNotFoundException: d:\aa.text (设备未就绪。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.(FileInputStream.java:138)
at java.io.FileInputStream.(FileInputStream.java:93)
at java.io.FileReader.(FileReader.java:58)
at com.test.test3.main(test3.java:15)

因为第一个有异常,所以第二个就没机会捕获了,程序已经中断了,想要看到第二个catch的作用,那么我现在把第一个语句注释掉,再次捕获。再次修改代码!

package com.test;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

public class test3 {
    public static void main(String[] args) {
        try {
            //检查性异常,1.打开文件
           // FileReader fr=new FileReader("d:\\aa.text");
            //2.连接一个192.168.12.12 ip的端口号4567
             Socket s=new Socket("192.168.1.23", 78);
             System.out.println("connect success!");
        } catch (FileNotFoundException ex) {
            Logger.getLogger(test3.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(test3.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("ok");
    }
}
运行结果:

java.net.ConnectException: Connection timed out: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at java.net.Socket.connect(Socket.java:538)
at java.net.Socket.(Socket.java:434)
at java.net.Socket.(Socket.java:211)
at com.test.test3.main(test3.java:17)

ok

小结:再出现异常的地方,就终止执行代码,然后进入到catch,如果,你有多个catch语句,则进入匹配异常那个的catch。

2>finally

如果把finally块放在try......catch的语句后面,finally语句是不管catch语句块是否执行,一般都会执行的。

下面是非一般情况:

a. finally块中发生异常

b.  程序所在线程死亡

c. 在前面的代码中有system.exit();语句

d.  关闭cpu

package com.test;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

public class test3 {
    public static void main(String[] args) {
        FileReader fr=null;
        try {
            //检查性异常,1.打开文件
            fr=new FileReader("H:\\aa.txt");
            //2.连接一个192.168.12.12 ip的端口号4567
            // Socket s=new Socket("192.168.1.23", 80);
        } catch (FileNotFoundException ex) {
            System.exit(-1);//finally就不会执行
            Logger.getLogger(test3.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(test3.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally{
            System.out.println("进入finally语句块");
            //这个语句块,不管有没有异常都会执行
            //一般把需要关闭的资源,如文件,或者数据库的连接,开辟的一些内存等
               if(fr!=null){
                   try {
                       fr.close();
                   } catch (IOException ex) {
                                ex.printStackTrace();
                   }
               }
        }
        System.out.println("ok");
    }
}


2>抛出异常,将异常抛给调用者,让调用者处理异常 throws

案例说明:

package com.test;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.logging.Level;
import java.util.logging.Logger;

public class test {
public static void main(String[] args) {
                Father father=new Father();
                father.test1();
    }
}
class Father{
    private Son son=null;
    public Father(){
        son=new Son();
    }
    public void test1(){
        System.out.println("1");
         //son.test2();//现在好了,儿子没有处理的异常抛给了父亲,父亲调用了儿子的方法,
            //而throws语句,是抛给调用者的,所以,此时父亲有两种方法解决这个异常,
            //一个是也不想管这个异常,往出抛,谁调用谁来处理这个异常,那么现在再
            //往上抛就是JVM了,那好了, 既然是当父亲的,那么就管管吧,用try catch
            //用throws的缺点就是,不知道异常出在了哪里
        try {
            son.test2();
        } catch (FileNotFoundException ex) {
            System.out.println("父亲在处理异常。");
            ex.printStackTrace();
        }
    }
}
class Son{
    public void test2() throws FileNotFoundException{
        FileReader fr=null;
        fr=new FileReader("d://aa.txt");//这个文件并不存在的
    }
}
输出结果:

1
父亲在处理异常。
java.io.FileNotFoundException: d:\aa.txt (设备未就绪。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.(FileInputStream.java:138)
at java.io.FileInputStream.(FileInputStream.java:93)
at java.io.FileReader.(FileReader.java:58)
at com.test.Son.test2(test.java:37)//真正的错误的根源在这一行
at com.test.Father.test1(test.java:27)//第27行在父亲类test1方法 里面调用了,
at com.test.test.main(test.java:11)//在主方法里面调用了

如果父亲也不管,都向上抛最后抛到主方法那里去,然后呢,Jvm处理,这样子做的效率并不高,不建议。建议,哪里出问题,就在哪里try catch。

就像下面这样的代码:不建议

package com.test;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.logging.Level;
import java.util.logging.Logger;

public class test {
public static void main(String[] args) throws FileNotFoundException {
                Father father=new Father();
                father.test1();
    }
}
class Father{
    private Son son=null;
    public Father(){
        son=new Son();
    }
    public void test1() throws FileNotFoundException{
        System.out.println("1");
         son.test2();//现在好了,儿子没有处理的异常抛给了父亲,父亲调用了儿子的方法,
            //而throws语句,是抛给调用者的,所以,此时父亲有两种方法解决这个异常,
            //一个是也不想管这个异常,往出抛,谁调用谁来处理这个异常,那么现在再
            //往上抛就是JVM了,那好了, 既然是当父亲的,那么就管管吧,用try catch
            //用throws的缺点就是,不知道异常出在了哪里
//        try {
//            son.test2();
//        } catch (FileNotFoundException ex) {
//            System.out.println("父亲在处理异常。");
//            ex.printStackTrace();
//        }
    }
}
class Son{
    public void test2() throws FileNotFoundException{
        FileReader fr=null;
        fr=new FileReader("d://aa.txt");
    }
}
运行结果:

1
Exception in thread "main" java.io.FileNotFoundException: d:\aa.txt (设备未就绪。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.(FileInputStream.java:138)
at java.io.FileInputStream.(FileInputStream.java:93)
at java.io.FileReader.(FileReader.java:58)
at com.test.Son.test2(test.java:37)
at com.test.Father.test1(test.java:21)
at com.test.test.main(test.java:11)
Java Result: 1













你可能感兴趣的:(Java)