1、throws与throw关键字
1.1 throws 关键字

在定义一个方法的时候通常可以用throws关键字声明,使用throws声明的方法表示此方法不处理异常,由此方法的调用者处理。
throws使用格式

public 返回值类型 方法名称(参数列表…) throws 异常类 {}

结合具体例子来看,还是用两数相除求商的例子

class Math{
    public int div(int i, int j)throws Exception{   // 定义除法方法,如有异常交给调用处处理
        int result = i/j;       // 两数相除可能出现异常
        return result;
    }

}
public class ThrowsDemo {
    public static void main(String[] args) {
        Math m = new Math();
        try{
            System.out.println("除法操作" + m.div(10,0));
        } catch (Exception e) {
            e.printStackTrace();	// 打印异常
        }
    }
}

// 运行结果:
java.lang.ArithmeticException: / by zero
	at Math.div(ThrowsDemo.java:7)
	at ThrowsDemo.main(ThrowsDemo.java:16)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

可以看到,在div()方法声明的时候用了throws关键字,方法体里没有去处理异常,而是在调用它的主方法里再去处理,那如果主方法也继续使用throws声明,那会怎么样?

class Math{
    public int div(int i, int j)throws Exception{   // 定义除法方法,如有异常交给调用处处理
        int result = i/j;       // 两数相除可能出现异常
        return result;
    }

}
public class ThrowsDemo {
    public static void main(String[] args) throws Exception {
        Math m = new Math();
        System.out.println("除法操作" + m.div(10, 0));

    }
}

// 运行结果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Math.div(ThrowsDemo.java:7)
	at ThrowsDemo.main(ThrowsDemo.java:15)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

在主方法中使用了throws关键字,那么方法体中也不用再处理异常,而是交给更大一级的调用者处理,是谁呢?对了,就是JVM,所有的处理都由JVM来完成。

1.2 throw关键字

与throws关键字不同,使用throw关键字可以直接抛出一个异常,抛出的时候直接抛出异常类的实例化对象。

在异常处理中,try语句要捕获的是一个异常对象,那么该对象也可以自己抛出。

public class ThrowDemo {
    public static void main(String[] args) {
        try{
            throw new Exception("自己抛自己玩");
        }catch (Exception e){
            System.out.println(e);
        }
    }
}

// 运行结果:
java.lang.Exception: 自己抛自己玩
1.3 实战 throws与throw的应用

实际开发中,try… catch … finally 、throw、throws一起使用的场景比较多。
例如现在要设计一个相除的方法,在开始的时候打印“方法开始”信息,结束的时候打印“方法结束”信息,中间有异常单独交给调用方法的地方处理

class Math{
    public int div(int i, int j) throws Exception {
        System.out.println("********** 计算开始 *********");
        int result = 0;
        try {
            result = i / j;
        } catch (Exception e) {
            throw e;		// 这里直接向外抛出异常,由调用处来处理
        } finally {
            System.out.println("********** 计算结束 *********");
        }
        return result;
    }
}

public class ThrowDemo {
    public static void main(String[] args) {
        Math m = new Math();
        try{
            System.out.println("除法操作:" + m.div(10,0));
        }catch (Exception e){
            System.out.println("异常产生:" + e);
        }
    }
}


// 运行结果:
********** 计算开始 *********
********** 计算结束 *********
异常产生:java.lang.ArithmeticException: / by zero

思考:
这里要求在调用出处理异常,因此需要使用throws关键字声明div方法,而在div方法和main主方法里都加了try … catch语句,在div方法里的的catch语句直接throw了异常,由调用它的main方法处理,main方法里的catch捕获到并且处理。

下面是程序的执行过程

java的算术异常 java除法运算及异常_java

如果我们在div方法里没有用throw抛出异常,而是直接打印异常,那运行结果会是怎样?

class Math{
    public int div(int i, int j) throws Exception {
        System.out.println("********** 计算开始 *********");
        int result = 0;
        try {
            result = i / j;
        } catch (Exception e) {
            e.printStackTrace();		// 这里不向外抛出异常,打印异常
        } finally {
            System.out.println("********** 计算结束 *********");
        }
        return result;
    }
}

public class ThrowDemo {
    public static void main(String[] args) {
        Math m = new Math();
        try{
            System.out.println("除法操作:" + m.div(10,0));
        }catch (Exception e){
            System.out.println("异常产生:" + e);
        }
    }
}

// 运行结果:
java.lang.ArithmeticException: / by zero
********** 方法开始 *********
	at Math.div(ThrowDemo.java:10)
********** 方法结束 *********
	at ThrowDemo.main(ThrowDemo.java:24)
除法操作:0
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
2、Exception和RuntimeException
2.1 两者的区别
  • Exception 在程序中必须用try … catch 处理
  • RuntimeException 可以不使用 try … catch 处理,但是如有有异常 ,在异常交给JVM处理。

一般为了保证程序的健壮性,还是建议在可能出现异常的地方用 try … catch 处理