------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
1、异常的概念和分类
异常是程序在运行过程中出现的一些意外情况导致程序不能正常运行的情况。
Bug:程序中存在的语法错误,程序根本就不能运行。
在Java中把异常分成两大类:Error和Exception。
Error:致命性错误,是Java的内部错误。是程序员无法解决的。 一般指的JVM的错误等。这个不是我们关注的重点。
Exception:Java程序在编译和运行时出现的错误。Exception又分为编译时异常和运行时异常。我们在本章主要解决的是运行时异常。
100/I;
解决程序中运行时的突发情况,使程序不致于崩溃,仍然能够正常运行的机制,称为异常处理机制。
在C中读文件的过程:
Open the file
Determine file size
Malloc memory
Read file
Close file
Free memory
加上异常处理之后的代码
Int errorCode = 0;
If(open the file)
If(determine file size)
…
Else
errorCode = -2
Else
errorCode = -1;
C语言中进行异常处理的问题:
(1)程序员在写程序之前要考虑所有可能出现的问题
(2)把程序异常处理代码和业务代码混合在一起,程序可读性降低
(3)返回的错误信息太少。
在Java中提供了一个java.lang.Throwable类用于定义异常。
在 Java 中,所有的异常都有一个共同的祖先 Throwable(可抛出)。Throwable 指定代码中可用异常传播机制通过 Java 应用程序传输的任何问题的共性。
Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。
Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。
Exception(异常):是程序本身可以处理的异常。
Exception 类有一个重要的子类 RuntimeException。RuntimeException 类及其子类表示“JVM 常用操作”引发的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。
注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。
通常,Java的异常(包括Exception和Error)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。
可查异常(编译器要求必须处置的异常):正确的程序在运行中,很容易出现的、情理可容的异常状况。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。
除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。
Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。程序中应当尽可能去处理这些异常。
运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
非运行时异常 (编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
Throwable 类的构造方法以及常用的方法。
Throwable()
Throwable(String message):构造一个错误信息为message的异常对象
Throwable(String message, Throwable cause):构造一个错误信息为message,产生该异常原因为cause的异常对象。
Throwable(Throwable cause)
getCause():返回导致该异常发生的原因。
getMessage():返回该异常的信息。
printStackTrace():打印堆栈的信息,比getMessage()更为详细。
简单处理Exception的demo
public static void main(String[] args) {
int i = 0;
try{
<span style="white-space:pre"> </span>//执行到本行时,出现了异常,程序非法退出。
<span style="white-space:pre"> </span>System.out.println(100/i);
}catch(Exception e)
{
<span style="white-space:pre"> </span>//System.err.println(e.getMessage());
<span style="white-space:pre"> </span>//e.printStackTrace();
<span style="white-space:pre"> </span>System.err.println(e.getCause().getMessage());
}
<span style="white-space:pre"> </span>System.out.println("Hello!");
}
Java的异常处理机制(捕获异常)
1、try/catch/finally
try
{
监视的代码段
}catch(XxxException e1) //子类异常
{
处理异常
}catch(Exception e2)//父类异常
{
}
finally //可以省略不写
{
最终要处理的代码
}
try:是一个监视器,对try监视下的代码可能出现的异常进行监视,如果发现了异常,就主动抛出异常(报告)。
在try语句块的声明的变量都是局部变量,只在try中有效。
catch:一个try语句块可以对应多个catch语句。
catch(异常类型 变量)
catch只能捕获(Exception e)内对应声明的异常类型及其子类。
注意:如果有多个catch语句时,应该先捕获子类异常,再捕获父类异常。
finally:无论异常是否发生,finally程序块总会被执行。finally里边一般放置一些例行的事务性代码。比如文件的关闭,数据库连接的断开等。
2、throw抛出异常
程序中主动抛出一个异常对象。
使用throw抛出异常之后,程序中必须使用try/catch来捕获,或者在调用本段代码的地方使用throws声明,告诉调用者需要捕获异常。
3、throws声明异常
主要用在方法的声明
访问控制修饰符 返回值类型 方法名(参数列表) throws 异常类型
{
方法体
}
package com.tai.GX;
import java.io.*;
public class Exp
{
// b
// 声明异常,告诉调用者,如果调用method方法时,需要捕获Exception异常
public void method() throws Exception
{
// try{
Exception e = new Exception("这是人为制造的异常!");
throw e; // a
// }catch(Exception ex)
// {
// ex.printStackTrace();
// }
}
public static void main(String[] args)
{
Exp exp = new Exp();
// 调用method方法
try
{
exp.method();
}
catch (Exception e6)
{
}
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = null;
try
{
s = br.readLine();
}
catch (IOException e7)
{
}
System.out.println(s);
int a = 0;
int b = 0;
try
{
a = Integer.parseInt(args[0]);
b = Integer.parseInt(args[1]);
}
catch (NumberFormatException e1)
{
e1.printStackTrace();
}
catch (ArrayIndexOutOfBoundsException e2)
{
e2.printStackTrace();
}
// catch(Exception e4)
// {
// e4.printStackTrace();
// }
// java Exp 100,200
try
{
System.out.println("a/b=" + a / b);
}
catch (ArithmeticException e3)
{
e3.printStackTrace();
}
}
}
自定义异常
使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。
在程序中使用自定义异常类,大体可分为以下几个步骤。
(1)创建自定义异常类。
(2)在方法中通过throw关键字抛出异常对象。
(3)如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
(4)在出现异常方法的调用者中捕获并处理异常。
package com.tai.GX;
public class BankAccount
{
// 帐户名称
private String name;
// 帐号
private String account;
// 开户行
private String bank;
// 帐户余额
private double balance = 0;
/**
* 无参构造方法
*/
public BankAccount()
{
super();
}
/**
* 含有用户名、帐号的构造方法
*
* @param name
* @param account
*/
public BankAccount(String name, String account)
{
super();
this.name = name;
this.account = account;
}
/**
* 含 有全部成员变量的构造方法
*
* @param name
* @param account
* @param bank
* @param balance
*/
public BankAccount(String name, String account, String bank, double balance)
{
super();
this.name = name;
this.account = account;
this.bank = bank;
this.balance = balance;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAccount()
{
return account;
}
public void setAccount(String account)
{
this.account = account;
}
public String getBank()
{
return bank;
}
public void setBank(String bank)
{
this.bank = bank;
}
public double getBalance()
{
return balance;
}
public void setBalance(double balance)
{
this.balance = balance;
}
/**
* 取钱
*
* @param amount
*/
public void widthdraw(double amount) throws AmountException
{
if (amount > 0)
{
if (this.balance >= amount)
{
this.balance = this.balance - amount;
System.out.println("你取了" + amount + "元,当前余额为:" + this.balance);
}
else
{
AmountException ae = new AmountException();
throw ae;
}
}
}
/**
* 存钱
*
* @param amount
*/
public void saving(double amount)
{
if (amount > 0)
{
this.balance = this.balance + amount;
System.out.println("你存了" + amount + "元,当前余额为:" + this.balance);
}
}
/**
* @param args
*/
public static void main(String[] args)
{
BankAccount ccb_lisi = new BankAccount("Lisi", "6227 34344 2352",
"建设银行东区支行", 2000);
ccb_lisi.saving(500);
try
{
ccb_lisi.widthdraw(3000);
}
catch (AmountException e)
{
System.out.println(e.getMessage());
}
}
}
/**
* 自定义异常类,必须继承于一个Java的异常类,如Exception/Throwable
*
* @author Administrator
*
*/
class AmountException extends Exception
{
public AmountException()
{
}
public AmountException(String message)
{
super(message);
}
public String getMessage()
{
return "余额不足";
}
}
自定义异常必须继承一个现有的异常类,即自定义异常类是现有异常类的子类。在自定义异常类中可以重写相关方法。
捕获自定义异常类与Java提供的异常类没有区别。