java异常处理机制及自定义异常的实现

什么是异常

大家在写java程序时一定经常会遇到控制台弹出一长串红色的字眼,上面介绍了产生错误的原因,发生错误的堆栈名称和位置,这就是异常。异常一般表示程序运行过程中遇到的一些错误,这可能是代码本身的语法逻辑错误,也可能是JVM本身的物理原因导致,异常的触发会导致程序的终止。为了更好地了解异常,我们先来看一下API:
Throwable是所有异常的超类,Error和Exception继承了Throwable类。
1、Error:Error表示程序运行中因为物理原因导致的错误,比如JVM中堆栈的溢出,这种情况一般是由于迭代函数的不断迭代导致空闲物理资源的不足导致,另外,如果发生死锁也会导致Error,Error由程序无法检测,也无法通过逻辑去分析程序的错误,一般是无法避免的。
2、Exception:Exception包括两种异常,一种是检查性异常,另一种是非检查性异常,检查性异常在我们程序的编写过程中会有下划线提示,我们只有加上try和catch才能使得程序编译通过,为什么会有这种异常呢,因为我们在调用程序的某些方法的时候,那个方法中有抛出异常的语句,我们在调用它的时候必然需要加上try和catch来捕获可能出现的异常,即我们需要把可能发生异常的程序包括在try和catch语句中,异常的类型也要和方法内的可能异常一致。那么什么是非检查性异常,顾名思义,这是编译器不会检查出的异常,可能是程序逻辑的错误引发的异常,这一般在程序的运行中才能发现,故我们也称它为运行时异常(Runtime Exception),Runtime Exception是Exception的子类。

常见异常介绍

1、ArithmeticExecption:算术异常类,当算术出现类似除法中分母为0这种情况,会产生算术异常。
2、NullPointerException:空指针异常,如果某个变量在定义后没有实体化,或者某个对象在别的类中引用没有把对象传过去,都会导致空指针异常,这也是很常见的异常。
3、ArrayIndexOutOfBoundsException:数组下标越界异常,当你对数组的调用超出了下标定义的范围,便会产生异常。
4、SQLException:数据库操作异常,比如在数据库的操作中向数据库中存某个记录,此记录内容和字段数据要求不符时产生的异常。
5、IOException:IO异常,在数据的输入输出中常见,如果一个线程没有释放IO资源,而另一个线程先要用这个IO输出数据,便产生了异常。
6、FileNotFoundException:当试图连接某个文件而通过路径找不到文件时便会产生异常。

异常的语法规则

1、基本结构,try和catch结构。try一般修饰可能出现异常的代码块,这里它修饰了一个SQL语句的执行方法,这可能会有SQL异常,如果发生异常,程序便会检查此异常是不是SQL异常,如果符合,便会执行catch语句修饰的代码块,输出发生错误的堆栈信息。

		try {
			Server.stmt.executeUpdate(sql);
		} catch (SQLException e) {
			e.printStackTrace();
		}

2、一个代码块可能发生的异常有时候不止一种,这个时候需要有多个catch表示不同的异常来修饰一个代码块。发生异常后程序会优先检查是不是第一个catch中的异常,如果不是,则会检测下一个catch,直到检测到匹配的异常并执行异常处理程序。我们来看下面这段程序,简单地介绍一下throws和throw的用法,throws一般用在方法名之后用于申明此代码块中可能出现的异常,但由于不确定如何处理,则把异常交给方法的调用者或JVM处理,这是一种消极的异常处理方法,如果一个被throws修饰的代码块被调用,那么调用处需要用try,catch来修饰这个方法。throw则的直接抛出异常,这是一个动作,满足异常的触发条件,便会直接抛出异常,这也是一种不太合适的异常处理方式。对于异常的处理,我们应该在可能发生异常的地方用try和catch修饰可能发生错误的代码块,并写相应的异常处理程序。

void doA(int a) throws (Exception1,Exception2){
        try{
         ......
       }catch(Exception1 e){
        throw e;
        }catch(Exception2 e){
         System.out.println("程序出错了!");
        }

3、finally关键字:finally可加可不加,如果要加,则放在所有catch语句的最后,不管有没有捕获异常,都会执行finally代码块,finally中的代码一般用于关闭流等资源的操作。另外,如果try中有return,则会在finally中代码块执行完后再返回,在finally中不能修改try中return的数值变量的值。另外如果在finally中return,则不会执行try中的return,也不会执行异常的捕获,故我们一般把return写在所有语句的最后面。看例子,这是一个服务器接收客户端传来的文件数据的部分代码,这里我们没有写catch,执行完try后在finally中关闭所有资源,此处我们也可以发现,可以有try而没有catch。

         try {
                dis = new DataInputStream(in);
                String path = "E:\\workspace\\mayifan\\src\\com\\myf\\server1111\\1.png";
                fos = new FileOutputStream(new File(path));
                inputByte = new byte[1024];
                System.out.println("开始接收数据...");
                while ((length = fis.read(sendBytes, 0, sendBytes.length)) > 0) {
                dos.write(sendBytes, 0, length);
                dos.flush();
                }
            } finally {
                if (dos != null)
                    dos.close();
                if (fis != null)
                    fis.close();
                if (socket != null)
                    socket.close();
            }

4、return的返回值问题。在3中我们提到了,try中有return,则在finally语句执行完后再return,这里我们就return的数值做一简单的代码分析。程序的执行结果是:先输出“finally block executed”,再输出1。我们可以得知在返回前会先执行finally中的输出语句,另外,i的值没有被finally中的2修改,这说明在try中返回值1已经被保存在了堆栈中,如果程序执行完就会返回。

 int i = 0;
            try
            {
                i = 1;
                return i;
            }             
            finally
            {
                i = 2;
                System.out.println("finally block executed");
            }

5、自定义异常:在开发一个大型的项目中,往往不可能一个人完成,大家都是分模块编写,自定义异常便能使得对外能够有统一的异常处理机制,另外,自定义异常能够在特殊业务中有特殊的异常处理机制,比如你可以写一个银行存取款的异常处理机制,如果你的取款金额大于卡内余额,则抛出异常;或是在一场只能有胜负的比赛中出现了平局的异常处理等,自定义异常能够使得程序可以适应一些特殊的要求。另外,从架构层次来看,MCV中的业务逻辑层和视觉层需要分离,如果加上自定义异常,可以使逻辑处理和用户的交互分离,因为我们可以通过异常的触发获取相应的逻辑结构。那么如何自定义异常呢?我们来实现一个最简单的自定义异常程序,我们输入一个数,然后控制台反馈它和5的大小比较,这里我们通过自定义异常来分离业务逻辑部分和视图刷新部分。
①继承Exception,重写其方法:

public class Abnormal extends Exception {

	    public Abnormal(String message) {			
	    	super(message);    //把参数传递给Throwable的带String参数的构造方法 
		}	
}

②逻辑处理类,大小判断,手动抛出异常:

public class Check {			
	public void check(int a) throws Abnormal{	
		if(a>5)
			throw new Abnormal("大于");
		else if(a==5)
			throw new Abnormal("等于");
		else
			throw new Abnormal("小于");
	}		
}

③交互界面(视图界面),输入一个数,执行check方法,并获取触发的异常,输出异常对应字符串并输出:

public class View {
	  public static void main(String[] args)
	  {
		  Scanner sc = new Scanner(System.in);
		  int a =sc.nextInt();
          Check ck= new Check();
          try {
			ck.check(a);       //执行check方法,逻辑判断,触发异常
		} catch (Abnormal e) {			
			System.out.println("和5比较"+e.getMessage()+"5");   //输出异常对应字符串
		}
	  }		
}

这样我们便实现了一个自定义的异常,通过自定义,我们可以使得异常的触发条件受我们控制,也实现了业务逻辑层和视图层的分离。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值