Java异常处理
在很多场景都有异常处理,python、C++、java中都存在,但是一直不理解异常处理的一些深层逻辑,在这里简要学习一下
Reference
- runoob https://www.runoob.com/java/java-exceptions.html
- 廖雪峰 https://www.liaoxuefeng.com/wiki/1252599548343744/1264734349295520
什么是异常处理
- 简单来说就是尽可能避免程序不正常运行的技术
我们可以自己写一个简单的swtich来判断接受的正确或错误的错误码,这个错误码通常是编程语言和API固定的
int code = processFile(“C:\\test.txt”);
if (code == 0) {
// ok:
} else {
// error:
switch (code) {
case 1:
// file not found:
case 2:
// no read permission:
default:
// unknown error:
}
}
但是上面这个判断有个问题,如果程序本身有严重错误,或者不可抗力的中断,处理起来就很困难
所有基本上每个语言都有自己的异常处理机制
try {
String s = processFile(“C:\\test.txt”);
// ok:
} catch (FileNotFoundException e) {
// file not found:
} catch (SecurityException e) {
// no read permission:
} catch (IOException e) {
// io error:
} catch (Exception e) {
// other error:
}
在廖雪峰的网站上可以看到一个异常体系图,Java的异常是class,很多异常存在继承关系,并且都继承自object
错误总体上分为:
Error表示严重的错误Exception则是运行时的错误
举例分析
拿廖雪峰的例子分析一下
// try…catch
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 {
// 用指定编码转换String为byte\[\]:
return s.getBytes("GBK");
} catch (UnsupportedEncodingException e) {
// 如果系统不支持GBK编码,会捕获到UnsupportedEncodingException:
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,如果你在调用时没有做异常处理,那么同样也会有编译器的提醒
那么修改为如下的代码
// try…catch
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…捕获这个异常
正确的修改如下:
// 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 {
// 用指定编码转换String为byte\[\]:
return s.getBytes("GBK");
}
}
下面这个结论很重要:
只要是方法声明的Checked Exception,不在调用层捕获,也必须在更高的调用层捕获。所有未捕获的异常,最终也必须在
main()方法中捕获,不会出现漏写try的情况。这是由编译器保证的。main()方法也是最后捕获Exception的机会。
日常技巧
偷懒可以这样写
public class Main {
public static void main(String[] args) throws Exception { // 在main函数抛出
byte[] bs = toGBK(“中文”);
System.out.println(Arrays.toString(bs));
}
static byte\[\] toGBK(String s) throws UnsupportedEncodingException {
// 用指定编码转换String为byte\[\]:
return s.getBytes("GBK");
}
}
代价就是一旦发生异常,程序会立刻退出。
另一种就是,不知道出现异常做什么的时候,用异常栈来记录
static byte[] toGBK(String s) {
try {
return s.getBytes(“GBK”);
} catch (UnsupportedEncodingException e) {
// 先记下来再说:
e.printStackTrace();
}
return null;
所有异常都可以调用printStackTrace()方法打印异常栈,这是一个简单有用的快速打印异常的方法。
