写在前面
编程语言里会提供对异常错误的处理,一般分为两种,可恢复错误和不可恢复错误,可恢复错误也就是说会影响到某个操作,但对系统的稳定性不会有影响,也就是说程序认为这种错误其实是允许发生,但希望我们能够捕捉到后处理;反之不可恢复错误则意味着会对系统带来严重的影响,导致我们的程序崩溃之类的,希望立即中止。
内容
Java
在 Java 里,异常分为 Exception 和 Error 两种,它们都继承于 Throwable 类:
在我们程序运行的时候,Exception 比较常见的有 NullPointerException、IOException 等,这些 Exception 我们可以通过 try-catch进行捕获处理,也就是可恢复错误,允许有这样的错误,但我们可以处理好。而对于 Error,例如 OutOfMemoryError、NoClassDefFoundError 等这些是系统层面的问题,不是我们的可处理范畴,Java 也告诉我们不应该尝试去捕获处理它。
Exception
The class Exception and its subclasses are a form of Throwable that indicates conditions that a reasonable application might want to catch.
The class Exception and any subclasses that are not also subclasses of RuntimeException are checked exceptions. Checked exceptions need to be declared in a method or constructor’s throws clause if they can be thrown by the execution of the method or constructor and propagate outside the method or constructor boundary.
Error
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. The ThreadDeath error, though a “normal” condition, is also a subclass of Error because most applications should not try to catch it.
A method is not required to declare in its throws clause any subclasses of Error that might be thrown during the execution of the method but not caught, since these errors are abnormal conditions that should never occur. That is, Error and its subclasses are regarded as unchecked exceptions for the purposes of compile-time checking of exceptions.
在 Java 里,如果需要抛出一个异常,那么需要在方法上添加抛出异常的声明。
public static void main(String[] args) {
try {
throwException();
} catch (Exception e) {
System.out.println(e);
}
}
private static void throwException() throws Exception {
throw new Exception("custom exception msg");
}
当我们 throw Exception 后,可以被正确的捕获到,然后程序接着完成运行。而如果是 throw Error,则程序会立马中止运行。
Dart
在 Dart 里,也同样分为Exception和Error两种。在对这两个所表达的意义,Dart 也是这样,Exception是需要被捕获并处理,而Error是不应该被捕获的。
但有一个例子:
void main() {
try {
testException();
} catch (e) {
print(e);
}
try {
testError();
} catch (e) {
print(e);
}
print('end');
}
void testException() {
throw Exception('testException');
}
void testError() {
throw Error();
}
在这个例子里,Exception和Error都能被捕获到,并且程序能完整的运行结束。似乎在编码层面上,这两者没有什么区别。但根据两者的文档介绍,以及回到一开始我们说的可恢复错误和不可恢复错误上,在 Dart 里可能更多是以一种规范来要求。我们在实际的开发过程中,例如设计一个 API 、一个库给别人,如果我们认为调用者的一些做法是可允许出现的错误,那么就应该抛出 Exception;如果我们认为调用者这种做法是完全不对的,需要中止程序,那我们就应该抛出Error。
Exception
Error
Rust
在 Rust 里,不可恢复的错误是通过panic宏来处理,可恢复错误是用Result<T, E>。
panic
fn main() {
panic!("crash and burn");
}
Result
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => {
panic!("Problem opening the file: {:?}", error)
},
};
}
Result<T, E>是一个枚举类型:
enum Result<T, E> {
Ok(T),
Err(E),
}
如果程序正常,会返回Ok,否则就返回Err,这种处理上也是很清晰的。
我们会发现,如果我想设计一个 API 给别人用,当我想抛出异常的时候,如果是不可恢复的,那么就像 Java 和 Dart 的 throw一样,我们直接panic即可。但如果是可恢复的,那么我们就应该是构造Result枚举值来作为返回值,以提供一个Err选项,而没有所谓的类似 throw的语法。
Go
在 Go 里,不可恢复的错误是用 panic函数来处理,一般的错误是用 error类型来表示。
error
func main() {
result, err := testError(2)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(result)
}
}
func testError(a int) (int, error) {
if a == 1 {
return 1, nil
}
return a, errors.New("testError")
}
panic
func main() {
testPanic()
}
func testPanic() {
panic("testPanic")
}
比较 Rust 和 Go,这两者在语法层面上有不少东西还是挺像的,对于一般性的错误,都是需要在函数的返回值里增加相应的 Error 参数。

455

被折叠的 条评论
为什么被折叠?



