“核心技术:异常、断言和日志”的版本间差异
跳到导航
跳到搜索
(→捕获异常) |
(→捕获异常) |
||
第89行: | 第89行: | ||
== 捕获异常 == | == 捕获异常 == | ||
<syntaxhighlight lang="java"> | |||
try | |||
{ | |||
code that might throw exceptions | |||
} | |||
catch (FileNotFoundException e) | |||
{ | |||
emergencyactionfor missingfiles | |||
} | |||
catch (UnknownHostException e) | |||
{ | |||
emergency actionfor unknown hosts | |||
} | |||
catch (IOException e) | |||
{ | |||
emergencyactionfor all other I/O problems | |||
} | |||
finally | |||
{ | |||
... | |||
} | |||
</syntaxhighlight> | |||
=== 捕获异常(try-catch finally) === | === 捕获异常(try-catch finally) === | ||
第99行: | 第123行: | ||
* 不允许在子类的throws 说明符中出现超过超类方法所列出的异常类范围。 | * 不允许在子类的throws 说明符中出现超过超类方法所列出的异常类范围。 | ||
=== 捕获多个异常 === | |||
* 假设两个异常的动作是一样的(且不是子类关系时),就可以合并catch 子句: | * 假设两个异常的动作是一样的(且不是子类关系时),就可以合并catch 子句: | ||
*: <syntaxhighlight lang="java"> | *: <syntaxhighlight lang="java"> | ||
第108行: | 第135行: | ||
*: 捕获多个异常时, 异常变量隐含为final变量 | *: 捕获多个异常时, 异常变量隐含为final变量 | ||
=== 再次抛出异常与异常链 === | === 再次抛出异常与异常链 === | ||
再次抛出异常: | |||
<syntaxhighlight lang="java" highlight="7"> | |||
try | |||
{ | |||
access the database | |||
} | |||
catch (SQLException e) | |||
{ | |||
throw new ServletException("database error: " + e.getMessageO) ; | |||
} | |||
</syntaxhighlight> | |||
异常链: | |||
* '''包装异常,可以让用户抛出子系统中的高级异常,而不会丢失原始异常的细节''' | |||
<syntaxhighlight lang="java" highlight="7-9,13"> | |||
try | |||
{ | |||
access the database | |||
} | |||
catch (SQLException e) | |||
{ | |||
Throwable se = new ServletException ("database error"); | |||
se.ini tCause(e); | |||
throw se; | |||
} | |||
// 捕获异常, 获取原始异常: | |||
Throwable e = se.getCauseO ; | |||
</syntaxhighlight> | |||
=== finally 子句 === | === finally 子句 === | ||
无论在try 语句块中是否遇到异常, finally 子句中语句都会被执行: | |||
# 代码没有抛出异常。 | |||
# 抛出一个在catch 子句中捕获的异常。 | |||
## 如果catch 子句没有抛出异常, 程序将执行try 语句块之后的第一条语句。 | |||
## 如果catch 子句抛出了一个异常, 异常将被抛回这个方法的调用者。 | |||
# 代码抛出了一个异常, 但这个异常不是由catch 子句捕获的。 | |||
* try 语句可以只有finally 子句,而没有catch 子句。 | |||
* '''finally 中出现异常时,异常会覆盖原异常'''; | |||
当finally 子句包含return 语句时: | |||
# finally 块,会在 try 的 return之前执行; | |||
# 如果finally 中也有 return,则其会覆盖 try中的 return; | |||
<syntaxhighlight lang="java"> | |||
public static int f(int n) | |||
{ | |||
try | |||
{ | |||
int r = n * n; | |||
return r; | |||
} | |||
finally | |||
{ | |||
if (n = 2) return 0; | |||
} | |||
} | |||
</syntaxhighlight> | |||
=== 带资源的 try 语句 === | === 带资源的 try 语句 === | ||
* 资源必须属于一个实现了 '''AutoCloseable''' 接口的类 | |||
带资源的try 语句(try-with-resources ) 的最简形式为: | |||
<syntaxhighlight lang="java"> | |||
try (Resource res = . . .) | |||
{ | |||
work with res | |||
} | |||
</syntaxhighlight> | |||
指定多个资源: | |||
<syntaxhighlight lang="java"> | |||
try (Scanner in = new Scanne「(new FileInputStream('7usr/share/dict/words"). "UTF-8"); | |||
PrintWriter out = new Pri ntWriter("out.txt")) | |||
{ | |||
while (in.hasNext()) | |||
out.pri ntl n(in.next().toUpperCase()) ; | |||
} | |||
</syntaxhighlight> | |||
=== 分析堆栈轨迹元素 === | === 分析堆栈轨迹元素 === | ||
2020年10月20日 (二) 02:57的版本
错误处理
异常分类
异常对象都是派生于Throwable 类的一个实例:
- Error:类层次结构描述了Java 运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。
- Exception:
- RuntimeException:由程序错误导致的异常属于RuntimeException;
- 其他异常:由于像I/O 错误这类问题导致的异常;
派生于RuntimeException 的异常包含下面几种情况:
- 错误的类型转换。
- 数组访问越界i
- 访问null 指针
不是派生于RuntimeException 的异常包括:
- 试图在文件尾部后面读取数据。
- 试图打开一个不存在的文件。
- 试图根据给定的字符串查找Class 对象, 而这个字符串表示的类并不存在。
非受查异常 与 受查异常:
- 非受查(unchecked) :异常派生于Error 类或RuntimeException 类的所有异常称为;
- 受查(checked) :所有其他的异常称为。
声明受査异常
使用throws子句声明异常:
- 调用一个抛出受査异常的方法, 例如, FilelnputStream 构造器。
- 程序运行过程中发现错误, 并且利用throw 语句抛出一个受查异常(下一节将详细地介绍throw 语句)。
- 程序出现错误, 例如,a[-l]=0 会抛出一个ArraylndexOutOffloundsException 这样的非受查异常。
- Java 虚拟机和运行时库出现的内部错误。
- 如果一个方法有可能抛出多个受查异常类型, 那么就必须在方法的首部列出所有的异常类。
class MyAnimation
{
public Image loadlmage(String s) throws FileNotFoundException, EOFException
}
- 如果在子类中覆盖了超类的一个方法, 子类方法中声明的受查异常不能比超类方法中声明的异常更通用。
如何抛出异常
对于一个已经存在的异常类, 将其抛出非常容易:
- 找到一个合适的异常类。
- 创建这个类的一个对象。
- 将对象抛出。
- 抛出的时异常类对象;
throw new EOFExceptionQ ;
- 一旦方法抛出了异常, 这个方法就不可能返回到调用者。
创建异常类
定义一个派生于 Exception 的类, 或者派生于 Exception 子类的类:
- 习惯上,定义的类应该包含两个构造器, 一个是默认的构造器;另一个是带有详细描述信息的构造器
class FileFormatException extends IOException
{
public FileFormatExceptionO {}
public FileFormatException(String gripe)
{
super(gripe);
}
}
相关方法
javaJang.Throwabie
- Throwable( )
构造一个新的Throwabie 对象, 这个对象没有详细的描述信息。
- Throwable(String message )
构造一个新的throwabie 对象, 这个对象带有特定的详细描述信息。习惯上, 所有派生的异常类都支持一个默认的构造器和一个带有详细描述信息的构造器。
- String getMessage( )
获得Throwabie 对象的详细描述信息。
捕获异常
try
{
code that might throw exceptions
}
catch (FileNotFoundException e)
{
emergencyactionfor missingfiles
}
catch (UnknownHostException e)
{
emergency actionfor unknown hosts
}
catch (IOException e)
{
emergencyactionfor all other I/O problems
}
finally
{
...
}
捕获异常(try-catch finally)
- 如果在try 语句块中的任何代码抛出了一个在catch 子句中说明的异常类:
- 程序将跳过try 语句块的其余代码。
- 程序将执行catch 子句中的处理器代码。
- 如果在try 语句块中的代码没有拋出任何异常,那么程序将跳过catch 子句。
- finally 子句不是必须的。
- 不允许在子类的throws 说明符中出现超过超类方法所列出的异常类范围。
捕获多个异常
- 假设两个异常的动作是一样的(且不是子类关系时),就可以合并catch 子句:
catch (FileNotFoundException | UnknownHostException e) { emergency action for missing files and unknown hosts }
- 捕获多个异常时, 异常变量隐含为final变量
再次抛出异常与异常链
再次抛出异常:
try
{
access the database
}
catch (SQLException e)
{
throw new ServletException("database error: " + e.getMessageO) ;
}
异常链:
- 包装异常,可以让用户抛出子系统中的高级异常,而不会丢失原始异常的细节
try
{
access the database
}
catch (SQLException e)
{
Throwable se = new ServletException ("database error");
se.ini tCause(e);
throw se;
}
// 捕获异常, 获取原始异常:
Throwable e = se.getCauseO ;
finally 子句
无论在try 语句块中是否遇到异常, finally 子句中语句都会被执行:
- 代码没有抛出异常。
- 抛出一个在catch 子句中捕获的异常。
- 如果catch 子句没有抛出异常, 程序将执行try 语句块之后的第一条语句。
- 如果catch 子句抛出了一个异常, 异常将被抛回这个方法的调用者。
- 代码抛出了一个异常, 但这个异常不是由catch 子句捕获的。
- try 语句可以只有finally 子句,而没有catch 子句。
- finally 中出现异常时,异常会覆盖原异常;
当finally 子句包含return 语句时:
- finally 块,会在 try 的 return之前执行;
- 如果finally 中也有 return,则其会覆盖 try中的 return;
public static int f(int n)
{
try
{
int r = n * n;
return r;
}
finally
{
if (n = 2) return 0;
}
}
带资源的 try 语句
- 资源必须属于一个实现了 AutoCloseable 接口的类
带资源的try 语句(try-with-resources ) 的最简形式为:
try (Resource res = . . .)
{
work with res
}
指定多个资源:
try (Scanner in = new Scanne「(new FileInputStream('7usr/share/dict/words"). "UTF-8");
PrintWriter out = new Pri ntWriter("out.txt"))
{
while (in.hasNext())
out.pri ntl n(in.next().toUpperCase()) ;
}