java的异常处理机制可以使程序中的异常处理代码与正常业务代码分离,保证程序代码更加优雅,并可以提高程序的健壮性。
在try{} catch(){} 异常处理机制中,try发生的异常对象会被提交到java的运行环境,叫做抛出异常,运行环境会寻找处理该异常的catch块,如果找到,则称为捕获异常,若没有找到合适的catch,则运行时环境终止,程序也将终止
Error和Exception:
java把所有的非正常情况分为两种类型,Error(错误)和Exception(异常),他们都继承Throwable父类。Error错误一般是指虚拟机相关的错误,如系统崩溃,虚拟机错误,动态链接失败等,这种错误无法恢复或不可捕获,将导致程序中断,所以不应该用catch捕获错误,也不需要用throws抛出错误
多异常捕获 与 finally语句块
/*
*运行时为main方法的args参数赋值,右击--run as--run config--agument--参数 回车 参数
*/
/*
* 异常处理语法结构里,try语句块是必须的,catch finally 必有其一
*/
public class SubExceptionTest
{
public static void main(String[] args)
{
try
{
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
int c = a/b;
System.out.println("两数相除的结果是:"+c);
}
/*
* java 7开始新增的方法,一个catch中可以同时捕获多个异常
* 每个异常都默认使用final修饰,所以不能重新进行赋值
*/
catch(IndexOutOfBoundsException | NumberFormatException | ArithmeticException e) //先捕获子类异常,再捕获父类异常,否则会编译错误
{
e.printStackTrace();
return; //1.... finally语句块会被执行
//System.exit(0); //2..退出虚拟机,finally语句得不到执行
//e = new RuntimeException();
}
catch(Exception e)
{
e.printStackTrace();
e = new RuntimeException(); //单独捕获一个异常可以重新赋值,异常变量没有final修饰
}
finally
{
System.out.println("主要进行物理资源的回收");
}
}
}
不要在finally语句块中使用return,throw会使方法终止的语句,一旦使用,将导致try catch中的return throw 失效
/*
* 通常情况下不要在finally块中执行return throw语句,否则会导致try catch中的return throw失效
* 如下程序:
* 当运行到try中的return语句时不会立即导致该方法结束,而是先找是否有finally块,如果有,
* 则执行完finally之后再执行try中的return,如果finally中有return语句,则不会再执行try中的return
* 导致try中的return失效
*/
public class ReturnTest
{
public static void main(String[] args)
{
boolean a = test();
System.out.println(a); //输出false
}
public static boolean test()
{
try
{
return true;
}
finally
{
return false;
}
}
}
java7自动 关闭资源的try语句
import java.io.*;
/*
* 在try语句中申请的资源会自动关闭,前提是资源类实现了AutoCloseable,或Closeable接口,
* 其中定义了close()方法。
* 在java7中几乎把所有资源类都实现了上述两个接口
* 自动关闭资源的try语句,相当于包含了隐式的finally语句块,所以可以没有catch。finally语句块
*/
public class AutoCloseTest
{
public static void main(String[] args) throws IOException
{
try(BufferedReader br = new BufferedReader(new FileReader("D:\\b.txt"));
PrintStream pr = new PrintStream(new FileOutputStream("D:\\a.txt")))
{
System.out.println(br.readLine());
pr.println("我是一个大好人");
}
/*
catch(IOException e)
{
e.printStackTrace();
}
*/
}
}
/*
* 1.异常被分为Checked异常,Runtime异常,只要不是RuntimeException的本身或子类,都属于Checked异常
* 2.Checked异常是java独有的,它认为所有的Checked异常都是能够被修复或处理的,所以必须显示的处理异常或throws抛出异常
* 如果不进行处理,则无法通过编译,这增加了程序的严谨性和健壮性,但同时增加了程序的复杂度
* 3.如果一个方法抛出Checked异常,则调用它的方法必须处理异常或再次抛出异常,最终会交给JVM,JVM处理异常的方式是打印异常的
* 跟踪栈信息,并终止程序
*/
/*
* throws方法仅用于方法签名,当子类方法重写父类抛出异常的方法时,应该遵循两个原则
* 1.子类抛出的异常类只能是父类本身或其子类
* 2.子类不能比父类抛出更多的异常
*/
/*
* 推荐使用Runtime异常,它既能保证正确代码和错误处理分离,保证程序的健壮性,也能避免编程的繁琐性
*/
/*
* 自行抛出异常使用throw关键字,每次只能抛出一个异常实例
* java接收到程序自行抛出的异常时,同样会终止当前的执行流,转到相应的catch中处理,与程序员手动抛出异常无异
* 如果throw抛出的是Checked异常,则必须显示的捕获该异常或者声明抛出异常,其调用者也是如此
* 如果抛出的是RuntimeException,则没有这种要求,是否处理,是否抛出都没有关系
*/
public class CheckedAndRuntime
{
public static void main(String[] args)
{
//runtime(); //当异常需要被JVM处理时,下面的代码执行不到,但是runtime()放到之后,则能被执行
try
{
check();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void check()throws Exception
{ System.out.println("测试");
throw new Exception("抛出Checked异常");
}
public static void runtime()
{
throw new RuntimeException("抛出runtime异常");
}
}
自定义异常类:
/*
* 自定义Checked异常,只需要继承Exception基类,而自定义Runtime异常,需要继承RuntimeException
* 都需要提供两个构造器,一个无参,一个以字符串为参数,该参数就是getMessage()的返回值
*/
public class IdentityException extends Exception
{
public IdentityException()
{}
public IdentityException(String message)
{
super(message);
}
}
catch 和 throw同时使用
/*
* 在异常出现的当前方法中,程序只对方法进行部分处理,其他的交给调用它的方法处理
* 完成多个方法协作处理一个异常,使用catch 与 throw
*/
/*
* 在企业级的应用中两者结合的使用方式非常常用,catch用来作为后台的日志记录异常信息
* throw用来为使用者提供提示信息
*/
public class CatchAndThrow
{
public static void main(String[] args)
{
try
{
bid("3n");
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void bid(String bidPrice)throws Exception
{
double d = 0.0; //竞拍底价
try
{
Double.parseDouble(bidPrice);
}
catch(Exception e)
{
e.printStackTrace();
throw new Exception("竞拍价格必须是数值"); //throws之后的代码不会被执行
/*
* 如果不自动抛出异常,后面的代码会被执行
* throw会结束该方法的运行,这也是之前在finally块里不要使用throw的原因
*/
}
System.out.println("测试是否能执行"); //没有执行
}
}
java7增强的 throw语句:
import java.io.FileOutputStream;
import java.io.IOException;
/*
* 在catch中抛出的异常为Exception,java7之前,主函数只能抛出Exception
* 然而方法只可能抛出IOException,java7会对其进行更细致的检查,允许抛出更准确的子类
*/
public class Java7Exception
{
public static void main(String[] args)throws IOException //抛出Exception的子类
{
try
{
new FileOutputStream("a.txt");
}
catch(Exception e)
{
e.printStackTrace();
throw e;
}
}
}
异常链:
import java.sql.SQLException;
/*
* 在平时的应用开发中,如使用三层架构,业务逻辑层访问持久层出现的SQLException不应该再被传递到用户界面
* 而应该提示更贴近用户的信息,即捕获原始异常,抛出新的异常,成为异常转译
*/
public class LinkException
{
//工资结算
public double calSal()
{
try
{
//实现工资结算
}
catch(SQLException e)
{
//把原始信息记录下来
.....
//提示给用户的信息
//throw new SaxException("数据库访问异常");
/*
* 将原始异常保存下来,责任链模式
* 需要SaxException有相应的构造器 SaxException(Throwable e)
*/
throw new SaxException(e);
}
}
}
java的 异常跟踪栈:
/*
* 异常传递给JVM,JVM打印出异常跟踪栈信息,
* Exception in thread "main" java.lang.RuntimeException: 异常
at StackException.two(StackException.java:15)
at StackException.one(StackException.java:11)
at StackException.main(StackException.java:7) 最外部通常是main() 或 run()
可以清楚的看到异常的传递情况
异常栈!与方法调用栈正好相反
*/
public class StackException
{
public static void main(String[] args)
{
one();
}
public static void one()
{
two();
}
public static void two()
{
throw new RuntimeException("异常");
}
}
异常处理机制的初衷是将不可预期的异常的处理代码与正常的业务逻辑分开,因此绝不要使用异常处理代替正常的业务判断
1>不要把异常和普通错误混淆在一起
2>不要使用异常来代替流程控制
3>不要使用过于庞大的try语句块
4>避免使用catch All
5>不要忽略捕获到的异常