java异常处理中throw和throws的区别

首先:

1.用户程序自定义的异常和应用程序特定的异常,必须借助于 throws 和 throw 语句来定义抛出异常。

1.1   throw是语句抛出一个异常。
语法:throw (异常对象);
         throw e;

1.2   throws是方法可能抛出异常的声明。(用在声明方法时,表示该方法可能要抛出异常)
语法:[(修饰符)](返回值类型)(方法名)([参数列表])[throws(异常类)]{......}
            public void doA(int a) throws Exception1,Exception3{......}

 

2.接着我们来看一段代码:

main函数:

  public static void main(String[] args) {
        try {
            exceptionTest("d:\\a","d:\\c");
        }catch (Exception e){
            System.out.println(e);
        }

    }

 



异常测试函数:
public static void exceptionTest(String inputFileName,String outputFileName)  {
    try {
        int a=1/0;
    }catch (Exception e){
        System.out.println("出现数字运算异常");
        throw  e;
    }
}


这是一段最普通的异常处理代码,程序输出结果为

在exceptionTest函数中,我们的try代码块中出现了分母为0的情况,此时jvm会抛出一个ArithmeticExcepiton的异常,接着我们在catch语句找那个使用Exception这个父类(默认能捕获所有异常)捕获到了异常,此时我们打印出了出现数字运算异常,并将此异常对象抛出,给上层方法体接受处理,即主函数处理,主函数捕捉到exceptionTest抛出的异常后,将改异常打印出来。

 

3.throws关键字是声明在方法体上的,表示该方法可能会抛出某种类型的异常(但并非一定抛出)

我们修改exceptionTest的代码,修改如下:

主函数(不变)

//以文件流的方式读写文件
public static void main(String[] args) {
    try {
        exceptionTest("d:\\a","d:\\c");
    }catch (Exception e){
        System.out.println(e);
    }

}

 



异常测试函数
 public static void exceptionTest(String inputFileName,String outputFileName)   {
        try {
            //文件异常测试
            BufferedInputStream bufferedInputStream=new BufferedInputStream(new FileInputStream("d:\\a.txt"));
            //
            String className="com.demo";
            Class clazz=Class.forName(className);
        }catch (Exception e){
            System.out.println("出现文件读取异常和类名获取异常");
            throw  e;
        }
    }


这个时候我们运行程序,编译器会报错,直接编译不通过,如果我们把exceptionTest中的throw e给注释了
即修改exceptionTest代码为:
public static void exceptionTest(String inputFileName,String outputFileName)   {
        try {
            //文件异常测试
            BufferedInputStream bufferedInputStream=new BufferedInputStream(new FileInputStream("d:\\a.txt"));
            //
            String className="com.demo";
            Class clazz=Class.forName(className);
        }catch (Exception e){
            System.out.println("出现文件读取异常和类名获取异常");
//            throw  e;
        }
    }

 

此时再运行程序,编译通过,程序输出为:

未注释之前编译器直接报错,编译器的提示是:

Unhandled exceptions: java.io.FileNotFoundException, java.lang.ClassNotFoundException

那是因为我们的方法中有未处理的两个异常,我们可以捕捉他们,然后输出信息到控制台

但是此时我们要用throw e将此异常抛出给上层方法体,必须在方法的声明中用throws FileNotFoundException,ClassNotFoundException来处理

即修改exceptionTest的的代码为:

  public static void exceptionTest(String inputFileName,String outputFileName) throws FileNotFoundException, ClassNotFoundException {
        try {
            //文件异常测试
            BufferedInputStream bufferedInputStream=new BufferedInputStream(new FileInputStream("d:\\a.txt"));
            //
            String className="com.demo";
            Class clazz=Class.forName(className);
        }catch (Exception e){
            System.out.println("出现文件读取异常和类名获取异常");
            throw  e;
        }
    }

必须要在方法体中声明这两个异常,是因为我们在try的代码块中调用的两个方法中声明了这两个异常,

首先是

new FileInputStream("d:\\a.txt")),
我们看下这个类的源码:
 * @param      name   the system-dependent file name.
     * @exception  FileNotFoundException  if the file does not exist,
     *                   is a directory rather than a regular file,
     *                   or for some other reason cannot be opened for
     *                   reading.
     * @exception  SecurityException      if a security manager exists and its
     *               <code>checkRead</code> method denies read access
     *               to the file.
     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
     */
    public FileInputStream(String name) throws FileNotFoundException {
        this(name != null ? new File(name) : null);
    }

新建一个文件输出流中,构造函数的方法体上已经用throws声明了FileNotFoundException这个异常

Class.forName(className)这个方法中,我们再看Class.forName这个静态函数的源码:

  * {@code X} to be initialized.
     *
     * @param      className   the fully qualified name of the desired class.
     * @return     the {@code Class} object for the class with the
     *             specified name.
     * @exception LinkageError if the linkage fails
     * @exception ExceptionInInitializerError if the initialization provoked
     *            by this method fails
     * @exception ClassNotFoundException if the class cannot be located
     */
    @CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

改方法上也用throws声明了ClassNotFoundException这个异常,

所以外层方法体调用他们的时候必须要对他们进行try-catch,

同样我们在testExcepiton函数中捕捉完后,想将改异常抛出,则必须在方法体中声明异常的类型,

然后再交由上层方法体处理。

 

总结:

throws只是在方法上的声明,表示函数可能会抛出改异常

throw是抛出实际的异常,如果在try的代码块中使用可能会抛出异常的函数,catch捕获后想要再次抛出给上层方法体,则需要再方法体上再次声明。

 

 

 


 

 

posted @ 2019-03-22 10:38  dazhouwentao  阅读(340)  评论(0)    收藏  举报