使用throws声明抛出异常
一旦使用throws语句声明抛出该异常,程序就无须使用try...catch块来捕获该异常
public class ThrowsTest
{
public static void main(String[] args)throws IOException
{
FileInputStream fis = new FileInputStream("a.txt");
}
}
编译结果:
import java.io.*;
public class TestThrows2
{
public static void main(String[] args) throws Exception
{
//因为test()方法声明抛出IOException异常
//所以调用该方法的代码要么处于try...catch块中
//要么处于另一个带throws声明抛出的方法中
test();
}
public static void test() throws IOException
{
//因为FileInputStream的构造器声明抛出IOException异常
//所以调用FileInputStream的代码要么处于try...catch块中
//要么处于另一个带throws声明抛出的方法中
FileInputStream fis = new FileInputStream("a.txt");
}
}
public class OverrideThrows
{
public void test() throws IOException
{
FileInputStream fis = new FileInputStream("a.txt");
}
}
class Sub extends OverrideThrows
{
//下面代码无法通过编译:子类方法声明抛出了比父类方法更大的异常
public void test() throws Exception
{
//.....
}
}
Checked异常有优势:Checked异常能在编译时提醒程序员代码可能存在的问题,提醒程序员必须注意处理该异常,或者声明该异常由该方法调用者来处理,从而可以避免程序员因为粗心而忘记处理该异常错误。
》》使用throw抛出异常
如果需要在程序中自行抛出异常,应使用throw语句,throw语句可以单独使用,throw语句抛出的不是异常类,而是一个异常实例,而且每次只能抛出一个异常实例:
throw ExceptionInstance
看代码:
public class TestThrow
{
public static void main(String[] args)
{
try
{
//调用带throws声明的方法,必须显式捕获该异常
//否则,必须在main方法中再次声明抛出
throwChecked(-3);
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
//调用抛出Runtime异常的方法既可以显式捕获该异常
//也可不理会异常
throwRuntime(3);
}
public static void throwChecked(int a ) throws Exception
{
if(a >0 )
{
//自行抛出Exception 异常
//该代码必须处于try块里,或处于带throws声明的方法中
throw new Exception("a的值大于0,不符合要求");
}
public static void throwRuntime(int a )
{
if(a>0)
{
//自行抛出RuntimeException异常,既可以显式捕获该异常
//也可完全不理会该异常,把该异常交给该方法调用者处理
throw new RuntimeException("a的值大于0,不符合要求");
}
}
}
}
编译结果:
》》自定义异常类
public class AuctionException extends Exception
{
//异常类无参数的构造器
public AuctionException()
{}
//带一个字符串参数的构造器
public AuctionException(String msg)
{
super(msg);
}
}
》》catch和throw同时使用
public class TestAuction
{
private double initPrice = 30.0;
//因为该方法中显式地throw了AuctionException异常
//所以此处需要声明抛出AuctionException异常
public void bid(String bidPrice) throws AuctionException
{
double d = 0.0;
try
{
d = Double.parseDouble(bidprice);
}
catch(Exception e)
{
//此处完成本方法中可以对异常执行的修复处理,此处仅仅是在控制台打印异常跟踪栈信息
e.printStackTrace();
//再次抛出自定义异常
throw new AuctionException("竟拍价必须是数值,不能包含其他字符");
}
if(intPrice>d)
{
throw new AuctionException("竟拍价比起拍价低,不允许竟拍");
}
initPrice = d;
}
public static void main(String[] args)
{
TestAuction ta = new TestAuction();
try
{
ta.bid("df");
}
catch(AuctionException ae)
{
//main方法再次捕捉到bid方法中的异常,并对该异常进行处理
System.err.println(ae.getMessage());
}
}
}
编译结果:
》》JAVA异常链
程序先捕获原始的异常,然后抛出一个新的业务异常,新的业务异常中包含了对用户的提示信息,这种处理方式被称为异常转译
public calSal throws SalException
{
try
{
//实现结算工资的业务逻辑
...
}
catch(SQLException sqle)
{
//把原始异常中的message就是向用户提示
throw new SalException("访问底层数据库出现异常");
}
catch(Exception e)
{
//把原始异常记录下来,留给管理员
...
//下面异常中的message就是向用户的提示
throw new SalException("系统出现未知异常");
}
}
》》JAVA的异常跟踪栈
class SelfException extends Exception
{
SelfException()
{}
SelfException(String msg)
{
super(msg);
}
}
public class PrintStackTraceTest
{
public static void main(String[] args)throws SelfException
{
firstMethod();
}
public static void firstMethod() throws SelfException
{
secondMethod();
}
public static void secondMethod() throws selfException
{
thirdMethod();
}
public static void thirdMethod()throws SelfException
{
throw new SelfException("自定义异常信息");
}
}
编译结果:
下面代码是多线程中发生异常的情形:
public class TestThreadException implements Runnable
{
public void run()
{
firstMethod();
}
public void firstMethod()
{
secondMethod():
}
public void secondMethod()
{
int a = 5;
int b = 0;
int c = a/b;
}
public static void main(String[] args)
{
new Thread(new TestThreadException()).start();
}
}
》异常处理规则
》不要过度使用异常
》不要使用过于庞大的try块
》避免使用CatchAll语句
》不要忽略捕获到的异常