1. 背景
在面试过程中,经常会遇到被问怎么捕捉和处理异常。。。。
2. 什么是异常
异常(Exception)是编程中的一种概念。它表示在程序执行过程中遇到的错误或异常情况。异常是程序运行时的异常事件,可能导致程序无法按照预期的方式继续执行。当发生异常时,程序的正常流程被打断,如果不做处理,程序通常会终止执行并打印出错误信息。
比如说:在 python 中,当某行代码触发了一个异常,比如除以零、访问不存在的变量或尝试打开一个不存在的文件,Python会创建一个与该错误相关的异常类的实例,并将其抛出。例如,除以零会导致ZeroDivisionError,而尝试访问未定义的变量会抛出NameError。
3. 如何捕捉和处理异常
3.1 python
使用try/except语句来捕获和处理异常。
- 示例代码:
try:
# 尝试执行的代码
# 如果这部分代码引发了一个异常,控制流将立即跳转到相应的except块
potentially_error_prone_code()
except ExceptionType:
# 当特定类型的异常发生时,这里将执行
# ExceptionType 应替换为你要捕获的具体异常类名
handle_exception()
except Exception:
# 这个except块将捕获所有未被前面更具体except块捕获的异常
# 它是一个通用的异常处理器
generic_error_handling()
else:
# 如果try块中的代码没有引发异常,此块的代码将被执行
# 只有在try块成功后才会执行这里的代码
if_no_exceptions()
finally:
# 不管是否发生异常,finally块的代码总是会被执行
# 这通常用于清理资源,如关闭文件或网络连接
cleanup_operations()
- 注意点:
- try块包含可能引发异常的代码。如果在try块内发生异常,程序将立即跳转到匹配的except块。
- except后面可以跟一个或多个异常类型。如果没有指定异常类型,except:将捕获任何类型的异常。
- except ExceptionType允许你针对特定类型的异常编写不同的处理逻辑。
- except: 没有指定异常类型的块将捕获所有其他未被捕获的异常,作为最后的“兜底”处理。
- else块是可选的,只有在try块中没有发生异常时才会执行。
- finally块也是可选的,无论是否发生异常,它的代码都会执行,常用于资源清理。
3.2 java
使用try/catch/finally/throws 语句来捕获和处理异常。
- 示例代码:
try {
// 可能会抛出异常的代码
FileReader file = new FileReader("non_existent_file.txt");
} catch (FileNotFoundException e) {
// 处理FileNotFoundException
System.out.println("File not found: " + e.getMessage());
} finally {
// 关闭资源,无论是否发生异常
if (file != null) {
try {
file.close();
} catch (IOException ioe) {
// 处理关闭文件时的异常
ioe.printStackTrace();
}
}
}
在这个例子中,如果文件不存在,FileReader构造函数会抛出FileNotFoundException,然后控制权转移至对应的catch块。无论是否捕获到异常,finally块都会确保文件被尝试关闭。
- 其中字段说明:
-
try块:
- 包含可能会抛出异常的代码。
- 如果try块中的代码抛出了一个异常,控制流会立即跳转到相应的catch块。
-
catch块:
- 用于捕获和处理特定类型的异常。
- 可以有多个catch块,每个块处理不同类型的异常。
- catch后面的括号里指定的是异常类,例如IOException,NullPointerException等。
- 如果try块中的异常与catch块匹配,那么对应的catch块的代码将被执行。
-
finally块:
- 无论是否发生异常,finally块的代码总是会被执行。
- 常用于资源的清理,例如关闭文件流或网络连接。
- 即使在try或catch块中有return语句,finally块的代码也会在返回之前执行。
-
throw语句:
- 用于显式地抛出一个异常。
- 可以是已知的异常类型,也可以是自定义的异常类实例。
-
throws关键字:
- 在方法签名中使用,声明方法可能会抛出的异常。
- 如果方法可能会抛出非RuntimeException的检查异常,必须在方法签名中声明,否则编译器会报错。
- 使用throws可以让异常的处理推迟到方法的调用者那里。
-
try-with-resources语句(Java 7及更高版本):
- 用于自动关闭实现了AutoCloseable接口的资源。
这样可以确保即使在异常发生时,资源也能正确关闭,避免资源泄露。
- 用于自动关闭实现了AutoCloseable接口的资源。
3.3 JavaScript
在JavaScript中,异常处理是通过try…catch…finally结构来实现的,与Python和Java类似,但有一些细微差别
- 示例代码:
try {
// 可能会抛出错误的代码
let nonExistentValue = someNonExistentVariable;
} catch (error) {
// 处理错误
console.error("An error occurred: ", error.message);
} finally {
// 清理资源或执行无论是否抛出错误都需要进行的代码
// 清理操作
}
- 其中字段说明:
-
try块:包含可能抛出错误的代码。
如果try块中的代码抛出错误,执行会立即跳转到catch块。 -
catch块:用于捕获并处理try块中抛出的错误。
catch后面可以有一个参数,通常是代表错误对象的变量,例如catch(error)。一旦捕获到错误,catch块的代码就会执行。 -
finally块:无论是否发生错误,finally块的代码总会被执行。通常用于清理资源,例如关闭文件或取消网络请求。
-
throw语句:用于手动抛出一个错误。你可以创建一个Error对象,或者任何可以转换为字符串的值。
-
3.4 go
需要注意的是,在Go语言中,异常处理机制与Python、Java或JavaScript有所不同。Go语言没有传统的异常(Exception)概念,而是使用panic和recover来处理错误情况。
- 示例代码:
func doSomething() (int, error) {
defer func() {
if err := recover(); err != nil {
// 在这里处理panic,通常会转换成错误返回
log.Printf("Recovered panic: %v", err)
return -1, fmt.Errorf("an error occurred: %v", err)
}
}()
// 可能会panic的代码
result := 0
if someCondition {
result = divideByZero(1, 0) // 这将导致panic
}
return result, nil
}
func divideByZero(a, b int) int {
return a / b // 如果b为0,会触发panic
}
在这个例子中,doSomething函数内部的divideByZero调用可能会触发panic。由于divideByZero在defer函数的包裹下,recover可以捕获到这个panic,并将其转换为一个错误返回,而不是让程序崩溃。
- 其中字段说明:
-
panic函数:
- 类似于其他语言中的异常抛出,panic函数可以在遇到无法恢复的错误时被调用,中断当前函数的执行。
- 当panic被调用时,会停止执行当前函数的剩余部分,但会执行该函数内任何延迟调用的defer语句。
- panic可以接收一个参数,通常是一个错误信息,这将在控制台输出。
-
defer语句:
- defer语句用于注册一个函数,该函数会在当前函数返回之前执行。
- defer函数的执行顺序是相反的,即最后声明的defer先执行。
-
recover函数:
- recover用于捕获panic后的状态。
- recover只能在defer函数中有效,其他地方调用recover将返回nil。
- 当recover捕获到panic时,它会阻止程序崩溃并允许控制流恢复到正常的执行路径。
暂时只想到这些。。。。。之后想到再补充吧ing