目录
1、处理错误
如果由于出现错误而使得某些操作没有完成, 程序应该:
- 返回到一种安全状态,并能够让用户执行一些其他的命令;或者
- 允许用户保存所有操作的结果,并以妥善的方式终止程序。
1.1、异常分类
- 其中 Error 指的是 Java 运行时内部错误和资源耗尽错误. 应用程序不抛出此类异常. 这种内部错误一旦出现,除了告知用户并使程序终止之外, 再无能无力. 这种情况很少出现。
- Exception 是我们程序猿所使用的异常类的父类。
1.2、声明检查型异常
class MyAnimation{
...
public Image loadImage(String) throws FileNotFoundException,EOFExcption{
...
}
}
需要记住在遇到下面 4 种 情况时应该抛出异常:
- 调用一个抛出受査异常的方法, 例如, FilelnputStream 构造器。
- 程序运行过程中发现错误, 并且利用 throw语句抛出一个受查异常。
- 程序出现错误, 例如,a[-1] =0 会抛出一个 ArraylndexOutOfBoundsException 这样的非检查型异常。
- Java 虚拟机和运行时库出现的内部错误。
如果出现前两种情况之一, 则必须告诉调用这个方法的程序员有可能抛出异常。
1.3、如何抛出异常
对于一个已经存在的异常类并且能够满足自己的需求, 将其抛出非常容易。
在这种情况下:
- 找到一个合适的异常类。
- 创建这个类的一个对象。
- 将对象抛出。
一旦方法抛出了异常, 这个方法就不可能返回到调用者。也就是说, 不必为返回的默认值或错误代码担忧。
String readData(Scanner in) throws EOFException{
while() {
if(!in.hasNext) {
if(n<len) {
throw new EOFException();
}
}
}
return s;
}
1.4、创建异常类
我们需要做的只是定义一个派生于 Exception 的类,或者派生于 Exception 子类的类。定义的类应该包含两个构造器, 一个是默认的构造器;另一个是带有详细描述信息 的构造器(超类 Throwable 的 toString 方法将会打印出这些详细信息, 这在调试中非常有用)。
class UserError extends Exception {
public UserError(String message) {
super(message);
}
}
class PasswordError extends Exception {
public PasswordError(String message) {
super(message);
}
}
public static void main(String[] args) {
try {
login("admin", "123456");
} catch (UserError userError) {
userError.printStackTrace();
} catch (PasswordError passwordError) {
passwordError.printStackTrace();
}
}
public static void login(String userName, String password) throws UserError,PasswordError {
if (!Test.userName.equals(userName)) {
throw new UserError("用户名错误");
}
if (!Test.password.equals(password)) {
throw new PasswordError("密码错误");
}
System.out.println("登陆成功");
}
2、异常的基本用法
2.1、捕获异常
基本语法:
try{
有可能出现异常的语句 ;
}[catch (异常类型 异常对象) {
} ... ]
[finally {
异常的出口
}]
- 程序先执行 try 中的代码
- 如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配.
- 如果找到匹配的异常类型, 就会执行 catch 中的代码
- 如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.
- 无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).
- 如果上层调用者也没有处理的了异常, 就继续向上传递。
- 一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止.
public static void main(String[] args) {
try {
func();
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
System.out.println("after try catch");
}
public static void func() {
int[] arr = {1, 2, 3};
System.out.println(arr[100]);
}
// 直接结果
java.lang.ArrayIndexOutOfBoundsException: 100
at demo02.Test.func(Test.java:18)
at demo02.Test.main(Test.java:9)
after try catch
public static void main(String[] args) {
func();
System.out.println("after try catch");
}
public static void func() {
int[] arr = {1, 2, 3};
System.out.println(arr[100]);
}
// 执行结果
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100
at demo02.Test.func(Test.java:14)
at demo02.Test.main(Test.java:8)
2.2、finally子句
- finally 代码块中的代码用于处理善后工作, 会在最后执行。
- 其中 catch 和 fifinally 都可以根据情况选择加或者不加。
public static void main(String[] args) {
System.out.println(func());
}
public static int func() {
try {
return 10;
} finally {
return 20;
}
}
// 执行结果
20
- finally 执行的时机是在方法返回之前(try 或者 catch 中如果有 return 会在这个 return 之前执行 finally)。
- 但是如果finally 中也存在 return 语句, 那么就会执行 fifinally 中的 return, 从而不会执行到 try 中原有的 return。
- 一般我们不建议在 fifinally 中写 return (被编译器当做一个警告)。
2.3、try-with-Resources语句
带资源的 try 语句(try-with-resources) 的最简形式为:
try (Resource res = . . .)
{
work with res
}
同时指定多个资源:
public class TryWithResource {
public static void main(String[] args) {
try (BufferedInputStream buIn = new BufferedInputStream(new FileInputStream(new File("1.txt")));
BufferedOutputStream buOut = new BufferedOutputStream(new FileOutputStream(new File("2.txt")))) {
int b;
while ((b = buIn.read()) != -1) {
buOut.write(b);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
try-with-resources是jdk1.7引入的语法糖,使得关闭资源操作无需层层嵌套在finally。编译器也会自动帮我们补全close(),而且可以避免异常屏蔽。
3、异常的使用技巧
- 异常处理不能代替简单的测试
- 不要过分地细化异常
- 利用异常层次结构
- 不要压制异常
- 在检测错误时,“ 苛刻 ” 要比放任更好
- 不要羞于传递异常
4、使用断言
设确信某个属性符合要求, 并且代码的执行依赖于这个属性。断言机制允许在测试期间向代码中插入一些检査语句。当代码发布时,这些插人的检测 语句将会被自动地移走。
Java 语言引人了关键字 assert。这个关键字有两种形式:
- assert 条件;
- assert 条件:表达式;
这两种形式都会对条件进行检测, 如果结果为 false, 则抛出一个 AssertionError 异常。 在第二种形式中,表达式将被传人 AssertionError 的构造器, 并转换成一个消息字符串。“ 表达式” 部分的唯一目的是产生一个消息字符串。
结语
笔记自用。