一. Java 中的异常和 .Net 中的异常。
C# 中的异常处理是很自由的,不需要在方法的签名中声明所可能抛出的异常类型,也不强制要求在调用方法时捕获异常。对于没有 catch 的异常会一直往上抛,直到被 CLR 处理,程序被中断。
JAVA 中的异常处理很严谨,除了 RuntimeException 或其子类(非检查性异常),其他异常必须在方法签名中进行声明。所有异常必须在程序的某个地点捕捉,否则 JVM 将会退出。
二. Java 异常类层次结构
三. 检查性异常和非检查性异常
1. 检查性异常
在 Java 中所有不是 RuntimeException 派生的 Exception 都是检查型异常,检查性异常在编译阶段就暴露出来。
当函数中存在抛出检查型异常的操作时,该函数的函数声明中必须包含 throws 语句。调用该函数的函数也必须对该异常进行 try...catch 处理,如不进行处理则必须在调用函数上声明 throws 语句,如不进行处理则必须在调用函数上声明 throws 语句。
常见检查性异常:输入输出异常 (IOException)、SQL 语句异常 (SQLException) 等。
2. 非检查性异常
在 Java中 所有 RuntimeException(RuntimeException派生自Exception) 的派生类都是非检查型异常,非检查型异常在运行阶段才暴露出来。
当函数中存在抛出非检查性异常时,可以不用再函数上声明 throws 语句。调用该函数的函数可以不用在函数上声明 throws 语句,也可以不使用 try...catch 进行处理。如果有异常产生,则异常将由 JVM 进行处理。
常见非检查性异常:空指针异常(NullPointerException)、除零异常(ArithmeticException)、数组越界异常(ArrayIndexOutOfBoundsException)、以及用户自定义的 Exception 异常等。
注:
对于 RuntimeException 的子类最好也使用异常处理机制。虽然 RuntimeException 的异常可以不使用 try...catch 进行处理,但是如果一旦发生异常,则肯定会导致程序中断执行。
所以,为了保证程序再出错后依然可以执行,在开发代码时最好使用 try...catch 的异常处理机制进行处理。
四. 测试源码
1. C# 测试源码
using System; namespace ConsoleApplication3 { class Program { static void Main(string[] args) { // 如果不捕获异常,则会直接上抛给 CLR 处理,然后程序中断,后面代码不会执行 Test test = new Test(); test.ConvertToString(""); // 捕获异常 try { Test test2 = new Test(); test2.ConvertToString(""); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } public class Test { public int ConvertToString(string msg) { if (msg == null || msg == "") { // 可以直接抛出异常,不需要再函数中声明异常类型 throw new NullOrEmptyStringException("参数不能为空"); } return int.Parse(msg); } } public class NullOrEmptyStringException : Exception { private string _message; public NullOrEmptyStringException(string message) { this._message = message; } public override string Message { get { return this._message; } } } }
2. Java 测试源码
package indi.tracine.jdbc; public class Instance { public static void main(String[] args) { try { String sVal1 = ""; Integer iVal1 = convertTOString1(sVal1); System.out.println(iVal1); } catch (RuntimeException e) { System.out.println(e.getMessage()); } System.out.println("-----------------------------------"); // 运行时异常可以不捕获,直接抛给 JVM 处理,后面代码不会再执行 String sVal2 = ""; Integer iVal2 = convertTOString1(sVal2); System.out.println(iVal2); System.out.println("-----------------------------------"); // 检查性异常必须捕获调用的函数可能抛出的异常,或者在 函数签名中声明 throws Exception try { String sVal3 = ""; Integer iVal3 = convertTOString2(sVal3); System.out.println(iVal3); } catch (Exception e) { System.out.println(e.getMessage()); } System.out.println("-----------------------------------"); // 这里会编译失败 //String sVal4 = ""; //Integer iVal4 = convertTOString2(sVal4); //System.out.println(iVal4); } public static int convertTOString1(String msg) { if (msg == null || msg == "") { // 运行时异常(非检查性异常)可以不用再函数签名中声明 throws throw new RuntimeException("这里不能为空"); } int val = Integer.parseInt(msg); return val; } public static int convertTOString2(String msg) throws Exception { if (msg == null || msg == "") { // 检查性异常,必须在函数签名中声明异常类型 throw new Exception("这里不能为空"); } int val = Integer.parseInt(msg); return val; } }