1.异常处理
异常(exception ) 又称为例外、差错、违例
对应着Java运行错误处理机制
基本写法
try{
语句组
}catch(Exception ex){
异常处理语句组;
}
import java.io.*;
public class ExceptionForNum
{
public static void main(String[] args)
{
try{
BufferedReader in = new BufferedReader(
new InputStreamReader( System.in ) );
System.out.print("Please input a number: ");
String s = in.readLine();
int n = Integer.parseInt( s );
}catch(IOException ex){
ex.printStackTrace();
}catch(NumberFormatException ex){
ex.printStackTrace();
}
}
}
传统的 语言如何处理
在一些传统的语言(如C语言中)
if语句来判断是否出现了例外
全程变量ErrNo
但这有几个缺点
正常处理与异常处理的代码同样处理
可读性(readability)差
每次调用一个方法时都进行错误检查
可维护性( maintainability )差
错误由谁处理不请
职责不清
Java中处理异常
抛出(throw)异常
运行时系统在调用栈中查找
从生成异常的方法开始进行回溯,直到找到:
捕获(catch) 异常的代码
相关的语句
抛出异常
throw 异常对象;
捕获异常
try{
语句组
}catch(异常类名 异常形式参数名){
异常处理语句组;
}catch(异常类名 异常形式参数名){
异常处理语句组;
}finally{
异常处理语句组;
}
其中,catch语句可以0至多个,可以没有finally语句
异常的分类
Throwable (可抛出)
Error: JVM的错误
Exception: 异常
一般所说的异常
是指Exception及其子类
Exception类
构造方法
public Exception();
public Exception(String message);
Exception(String message, Throwable cause) ;
方法
getMessage()
getCause()
printStackTrace()
多异常的处理
子类异常要排在父类异常的前面
finally语句
无论是否有异常都要执行
即使其中有break,return等语句
在编译时,finally部分代码生成了多遍
package ch5;
public class text1 {
public static String output = "";
public static void foo(int i) {
try {
if (i == 1) {
throw new Exception();
}
output += "1";
} catch(Exception e) {
output += "2";
return;
} finally {
output += "3";
}
output += "4";
}
public static void main(String args[]) {
//foo(0);
//System.out.print(output + " ");
foo(1);
System.out.println(output);
}
}
//最后结果是23这说明,不管之前catch里是什么语句,都会执行finally语句
Exception分两种
RuntimeException及其子类,可以不明确处理
否则,称为受检的异常(checked Exception)
受检的异常,要求明确进行语法处理
要么捕(catch)
要么抛(throws):在方法的签名后面用throws xxxx来声明
在子类中,如果要覆盖父类的一个方法,若父类中的方法声明了 throws异常,则子类的方法也可以throws异常
可以抛出子类异常(更具体的异常),但不能抛出更一般的异常
package ch5;
import java.io.FileInputStream;
import java.io.IOException;
public class text1{
public static void main(String[] args){
try{
System.out.println("====Before====");
readFile();
System.out.println("====After====");
}catch(IOException e){ System.out.println(e); }
}
public static void readFile()throws IOException {
FileInputStream in=new FileInputStream("myfile.txt");
int b;
b = in.read();
while(b!= -1) {
System.out.print((char)b);
b = in.read();
}
in.close();
}
}
try…with…resource
try(类型 变量名 = new 类型() ){
。。。
}
自动添加了finally{ 变量.close(); }
不论是否出现异常,都会执行
package ch5;
import java.io.*;
class TryWithResourcesTest {
public static void main(String ... args)
throws IOException
{
String path = "c:\\aaa.txt";
System.out.println( ReadOneLine1( path ) );
System.out.println( ReadOneLine2( path ) );
}
static String ReadOneLine1(String path){
BufferedReader br=null;
try {
br=new BufferedReader(new FileReader(path));
return br.readLine();
} catch(IOException e) {
e.printStackTrace();
} finally {
if(br!=null){
try{
br.close();
}catch(IOException ex){
}
}
}
return null;
}
static String ReadOneLine2(String path)
throws IOException
{
try(BufferedReader br= new BufferedReader(new FileReader(path))){
return br.readLine();
}
}
}
2. 自定义异常
创建用户自定义异常类
创建用户自定义异常时
(1) 继承自Exception类或某个子Exception类
(2) 定义属性和方法,或重载父类的方法
重抛异常及异常链接
对于异常,不仅要进行捕获处理,有时候还需要将此异常进一步传递给调用者,以 便让调用者也能感受到这种异常。这时可以在catch语句块或finally语句块中采取 以下三种方式:
(1)将当前捕获的异常再次抛出:
throw e;
(2)重新生成一个异常,并抛出,如:
throw new Exception(“some message”);
(3)重新生成并抛出一个新异常,该异常中包含了当前异常的信息,如:
throw new Exception(“some message”,e);
可用e.getCause() 来得到内部异常
public class ExceptionCause {
public static void main(String [] args) {
try
{
BankATM.GetBalanceInfo( 12345L);
}catch(Exception e) {
System.out.println("something wrong�� " + e);
System.out.println("cause��" + e.getCause());
}
}
}
class DataHouse {
public static void FindData( long ID)
throws DataHouseException
{
if( ID>0 && ID<1000)
System.out.println( "id: " + ID );
else
throw new DataHouseException("cannot find the id");
}
}
class BankATM{
public static void GetBalanceInfo( long ID)
throws MyAppException
{
try
{
DataHouse.FindData(ID);
}catch (DataHouseException e) {
throw new MyAppException("invalid id",e);
}
}
}
class DataHouseException extends Exception {
public DataHouseException( String message ) {
super(message);
}
}
class MyAppException extends Exception {
public MyAppException (String message){
super (message);
}
public MyAppException (String message, Exception cause) {
super(message,cause);
}
}
3. 断言及程序的测试
断言(assertion)
assert的格式是:
assert 表达式; (逻辑表达式)
assert 表达式 : 信息;
在调试程序时
如果表达式不为true,则程序会产生异常,并输出相关的错误信息
class Assertion {
public static void main(String[] args) {
assert hypotenuse(3,4)==5 : "算法不正确";
}
static double hypotenuse( double x, double y ){
return Math.sqrt( x*x + y*y + 1);
}
}
Assert 的编译及运行
编译
只有在JDK1.4及以上的版本中才可以使用断言。
具体地说,在早期的JDK版本(1.4)中编译时,要通过-source选项来指明版本,如:
javac -deprecation -source 1.4 -classpath . Assertion.java
运行
在运行时,要使assert起作用,则在java命令中,使用选项(-ea,即-enableassertions)。如:
java -ea -classpath . Assertion
程序的测试及 JUnit
程序的修改是经常要进行的过程,必须保证程序在修改后其结果仍然 是正确的。
在编写程序代码的同时,还编写测试代码来判断这些程序是否正确。
这个过程称为“测试驱动”的开发过程。
从而保证了代码的质量,减少了后期的查错与调试的时间,所以实际 上它提高了程序的开发效率。
JUnit
在Java的测试过程,经常使用JUnit框架
参见http://www.junit.org。
现在大多数Java集成开发工具都提供了对JUnit的支持。
在Eclipse中
项目右键—New— Junit Test Case
项目右键—Run as — Junit Test
测试通过则为绿色,不通过显示红色
在NetBeans中
项目右键—新建— Junit测试
运行—测试,或者直接按Alt+F6即可
测试函数
@Test来标注测试函数
在测试中常用的语句如下:
fail( 信息 ); //表示程序出错
assertEqauls(参数1,参数2 ); //表示程序要保证两个参数要相等
assertNull(参数); //表示参数要为null
@Test
public void testSum2() {
HelloWorld a = new HelloWorld();
assertEquals(a.sum(0, 100), 100);
// fail("Not yet implemented");
}
4. 程序的调试
程序中的错误
程序中的错误通常可以分成三大类
语法错误(Syntax error)
编辑、编译器发现
运行错误(Runtime error)
异常处理机制
逻辑错误(Logic error)
调试(debug) 、单元测试(unit test)
程序的调试(debug)
在IDE中,项目上点右键 ,debug as…
进入到调试视图(debug perspective)
调试的三种手段
断点 (breakpoint)
跟踪 (trace)
监视 (watch)
断点
切换断点(toggle breakpoint )
用鼠标单击(或右击)编辑器左边条
或者
Eclipse Ctrl+Shift+B
NetBeans Ctrl+F8
跟踪
Eclipse | NetBeans | |
---|---|---|
逐语句执行 | F5 | F7 |
逐过程执行 | F6 | F8 |
跳出函数 | F7 | Ctrl+F7 |
运行到光标处 | Ctrl+R | F4 |
监视
即时监视
鼠标指向变量
快速监视
点右键,Inspector
添加监视
点右键,Watch
还可以看:调用堆栈等等