在很多场景都有异常处理,python、C++、java中都存在,但是一直不理解异常处理的一些深层逻辑,在这里简要学习一下
Reference
什么是异常处理
我们可以自己写一个简单的swtich来判断接受的正确或错误的错误码,这个错误码通常是编程语言和API固定的
int code = processFile("C:\\test.txt"); if (code == 0) { } else { switch (code) { case 1: case 2: default: } }
|
但是上面这个判断有个问题,如果程序本身有严重错误,或者不可抗力的中断,处理起来就很困难
所有基本上每个语言都有自己的异常处理机制
try { String s = processFile(“C:\\test.txt”); } catch (FileNotFoundException e) { } catch (SecurityException e) { } catch (IOException e) { } catch (Exception e) { }
|
在廖雪峰的网站上可以看到一个异常体系图,Java的异常是class
,很多异常存在继承关系,并且都继承自object
错误总体上分为:
Error
表示严重的错误
Exception
则是运行时的错误
举例分析
拿廖雪峰的例子分析一下
import java.io.UnsupportedEncodingException; import java.util.Arrays;
public class Main { public static void main(String[] args) { byte[] bs = toGBK("中文"); System.out.println(Arrays.toString(bs)); }
static byte[] toGBK(String s) { try { return s.getBytes("GBK"); } catch (UnsupportedEncodingException e) { System.out.println(e); return s.getBytes(); } } }
|
但是如果我们不捕获的话,会在toGBK()中提示你做异常处理,可以试一试
import java.sql.*; import java.util.Arrays;
public class Main { public static void main(String[] args) { byte[] bs = toGBK("中文"); System.out.println(Arrays.toString(bs)); }
static byte[] toGBK(String s) { return s.getBytes("GBK"); } }
|
输出为:java: 未报告的异常错误java.io.UnsupportedEncodingException; 必须对其进行捕获或声明以便抛出
但是这种机制是如何建立的?
编译器是如何知道需要写一个异常的?
这是因为String.getBytes(String)
方法定义是:
public byte[] getBytes(String charsetName) throws UnsupportedEncodingException { ... }
|
**在方法定义的时候,使用throws Xxx
表示该方法可能抛出的异常类型。**调用方在调用的时候,必须强制捕获这些异常,否则编译器会报错。也就是说,自己的写的方法如果包含了throws,如果你在调用时没有做异常处理,那么同样也会有编译器的提醒
那么修改为如下的代码
import java.io.UnsupportedEncodingException; import java.util.Arrays;
public class Main { public static void main(String[] args) { byte[] bs = toGBK("中文"); System.out.println(Arrays.toString(bs)); }
static byte[] toGBK(String s) throws UnsupportedEncodingException { return s.getBytes("GBK"); } }
|
此时编译也是不通过的,异常处理的提醒就是在main函数中,因为toGBK定义了throws 异常UnsupportedEncodingException,所有调用者都应该用try…catch…捕获这个异常
正确的修改如下:
import java.io.UnsupportedEncodingException; import java.util.Arrays;
public class Main { public static void main(String[] args) { try { byte[] bs = toGBK("中文"); System.out.println(Arrays.toString(bs)); } catch (UnsupportedEncodingException e) { System.out.println(e); } }
static byte[] toGBK(String s) throws UnsupportedEncodingException { return s.getBytes("GBK"); } }
|
下面这个结论很重要:
只要是方法声明的Checked Exception,不在调用层捕获,也必须在更高的调用层捕获。所有未捕获的异常,最终也必须在main()
方法中捕获,不会出现漏写try
的情况。这是由编译器保证的。main()
方法也是最后捕获Exception
的机会。
日常技巧
偷懒可以这样写
public class Main { public static void main(String[] args) throws Exception { byte[] bs = toGBK("中文"); System.out.println(Arrays.toString(bs)); }
static byte[] toGBK(String s) throws UnsupportedEncodingException { return s.getBytes("GBK"); } }
|
代价就是一旦发生异常,程序会立刻退出。
另一种就是,不知道出现异常做什么的时候,用异常栈来记录
static byte[] toGBK(String s) { try { return s.getBytes("GBK"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null;
|
所有异常都可以调用printStackTrace()
方法打印异常栈,这是一个简单有用的快速打印异常的方法。