第7章:异常处理
作为 Java 开发者,你已经熟悉了 Java 的异常处理机制。Python 的异常处理与 Java 有很多相似之处,但也有一些重要的区别。本章将详细对比两种语言的异常处理。
7.1 异常处理基础
Java 异常处理
try {
// 可能抛出异常的代码
} catch (ExceptionType1 e) {
// 处理异常类型1
} catch (ExceptionType2 e) {
// 处理异常类型2
} finally {
// 无论是否异常都会执行的代码
}
Python 异常处理
try:
# 可能抛出异常的代码
except ExceptionType1 as e:
# 处理异常类型1
except ExceptionType2 as e:
# 处理异常类型2
finally:
# 无论是否异常都会执行的代码
对比:
| 特性 | Java | Python |
|---|---|---|
| try 块 | 相同 | 相同 |
| catch 块 | catch (ExceptionType e) | except ExceptionType as e |
| finally 块 | 相同 | 相同 |
| 多个异常 | 多个 catch 块 | 多个 except 块 |
| 异常类型 | 检查型和非检查型 | 都是运行时异常 |
| throw 异常 | throw new Exception() | raise Exception() |
Python 异常处理示例:
# 基本异常处理
try:
x = int(input("Enter a number: "))
y = 10 / x
print(f"Result: {y}")
except ValueError:
print("Please enter a valid number")
except ZeroDivisionError:
print("Cannot divide by zero")
except Exception as e:
print(f"An error occurred: {e}")
finally:
print("Execution completed")
# 多个异常在一个 except 块
try:
x = int(input("Enter a number: "))
y = 10 / x
except (ValueError, ZeroDivisionError) as e:
print(f"Error: {e}")
# 异常的层次结构
try:
# 代码
pass
except Exception as e: # 捕获所有异常
print(f"Error: {e}")
7.2 异常类型
Java 异常类型
- 检查型异常:必须处理或声明的异常(如
IOException) - 非检查型异常:不需要强制处理的异常(如
RuntimeException) - 所有异常都是
Throwable的子类
Python 异常类型
- 所有异常都是
BaseException的子类 - 常用异常类型:
Exception:所有非系统退出异常的基类ValueError:值错误TypeError:类型错误ZeroDivisionError:除零错误FileNotFoundError:文件未找到错误ImportError:导入错误KeyError:字典键错误IndexError:索引错误
对比:
| Java 异常 | Python 异常 | 描述 |
|---|---|---|
NullPointerException | AttributeError | 访问不存在的属性 |
ArrayIndexOutOfBoundsException | IndexError | 索引越界 |
IllegalArgumentException | ValueError | 参数值错误 |
ClassCastException | TypeError | 类型转换错误 |
FileNotFoundException | FileNotFoundError | 文件未找到 |
IOException | 多种 IO 相关异常 | IO 操作错误 |
Python 异常层次结构:
BaseException
├── SystemExit
├── KeyboardInterrupt
├── GeneratorExit
└── Exception
├── ArithmeticError
│ ├── FloatingPointError
│ ├── OverflowError
│ └── ZeroDivisionError
├── AssertionError
├── AttributeError
├── EOFError
├── ImportError
│ └── ModuleNotFoundError
├── LookupError
│ ├── IndexError
│ └── KeyError
├── NameError
├── OSError
│ ├── FileExistsError
│ └── FileNotFoundError
├── SyntaxError
├── TypeError
└── ValueError
7.3 抛出异常
Java 抛出异常
// 抛出已定义的异常
throw new Exception("Error message");
// 在方法声明中声明异常
public void method() throws Exception {
// 代码
}
Python 抛出异常
# 抛出已定义的异常
raise Exception("Error message")
# 抛出特定异常
raise ValueError("Invalid value")
# 重新抛出异常
try:
# 代码
except Exception as e:
# 处理
raise # 重新抛出原异常
对比:
| 操作 | Java | Python |
|---|---|---|
| 抛出异常 | throw new Exception() | raise Exception() |
| 声明异常 | throws Exception | 不需要声明 |
| 重新抛出 | throw e | raise |
| 异常链 | throw new Exception("Message", cause) | raise NewException("Message") from original_exception |
Python 抛出异常示例:
# 抛出异常
def divide(a, b):
if b == 0:
raise ZeroDivisionError("Cannot divide by zero")
return a / b
try:
result = divide(10, 0)
except ZeroDivisionError as e:
print(f"Error: {e}")
# 异常链
try:
x = int("abc")
except ValueError as e:
raise RuntimeError("Failed to process input") from e
# 自定义异常
class CustomError(Exception):
"""自定义异常"""
pass
def validate_age(age):
if age < 0:
raise CustomError("Age cannot be negative")
try:
validate_age(-5)
except CustomError as e:
print(f"Custom error: {e}")
7.4 自定义异常
Java 自定义异常
// 自定义检查型异常
public class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}
// 自定义非检查型异常
public class CustomRuntimeException extends RuntimeException {
public CustomRuntimeException(String message) {
super(message);
}
}
Python 自定义异常
# 自定义异常
class CustomError(Exception):
"""自定义异常"""
pass
class ValidationError(CustomError):
"""验证错误"""
pass
# 使用自定义异常
def validate_email(email):
if "@" not in email:
raise ValidationError("Invalid email format")
try:
validate_email("user.example.com")
except ValidationError as e:
print(f"Validation error: {e}")
except CustomError as e:
print(f"Custom error: {e}")
except Exception as e:
print(f"General error: {e}")
对比:
| 特性 | Java | Python |
|---|---|---|
| 继承 | 继承自 Exception 或 RuntimeException | 继承自 Exception |
| 构造方法 | 需要显式调用父类构造方法 | 自动调用父类构造方法 |
| 异常类型 | 检查型和非检查型 | 都是运行时异常 |
7.5 异常处理最佳实践
Java 最佳实践
- 只捕获你能处理的异常
- 捕获具体的异常类型,而不是通用的
Exception - 使用 finally 块释放资源
- 不要忽略异常
- 记录异常信息
Python 最佳实践
- 只捕获你能处理的异常
- 捕获具体的异常类型,而不是通用的
Exception - 使用 finally 块释放资源
- 不要忽略异常
- 记录异常信息
- 使用
with语句管理资源(自动处理异常)
Python with 语句示例:
# 使用 with 语句管理文件
with open("example.txt", "r") as file:
content = file.read()
print(content)
# 文件自动关闭,即使发生异常
# 自定义上下文管理器
class Timer:
def __enter__(self):
import time
self.start = time.time()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
import time
self.end = time.time()
print(f"Elapsed time: {self.end - self.start:.2f} seconds")
# 如果返回 True,异常会被抑制
return False
with Timer():
# 执行一些操作
import time
time.sleep(1)
7.6 异常处理对比
| 特性 | Java | Python |
|---|---|---|
| 异常类型 | 检查型和非检查型 | 都是运行时异常 |
| 异常声明 | 方法必须声明可能抛出的检查型异常 | 不需要声明异常 |
| 异常捕获 | catch (Exception e) | except Exception as e |
| 异常抛出 | throw new Exception() | raise Exception() |
| 异常链 | throw new Exception("Message", cause) | raise NewException() from original |
| 资源管理 | try-with-resources | with 语句 |
| 异常层次 | 基于 Throwable | 基于 BaseException |
7.7 练习
- 异常处理练习:编写程序,处理用户输入的非数字情况
- 自定义异常练习:创建一个
AgeValidationError异常,用于验证年龄是否在合理范围内 - 资源管理练习:使用
with语句读取文件内容并处理可能的异常 - 异常链练习:创建异常链,展示底层异常和上层异常
- 综合练习:编写一个函数,读取文件并处理所有可能的异常
7.8 小结
- Python 的异常处理语法与 Java 类似,但更简洁
- Python 没有检查型异常,所有异常都是运行时异常
- Python 使用
as关键字捕获异常对象 - Python 支持异常链,使用
from关键字 - Python 的
with语句提供了更好的资源管理 - Python 的异常层次结构与 Java 类似,但有一些差异
- Python 的自定义异常更容易创建和使用
通过本章的学习,你已经了解了 Java 和 Python 在异常处理上的主要区别。接下来,我们将学习 Python 的 IO 操作。