`
FengShen_Xia
  • 浏览: 279296 次
  • 性别: Icon_minigender_1
  • 来自: 东方水城
社区版块
存档分类
最新评论

Java异常框架中finally执行、及其他相关问题

    博客分类:
  • Java
阅读更多

     首先看一下异常处理的完整语法,如下:

try{
      //(尝试运行的)程序代码
}catch(异常类型 异常的变量名){
      //异常处理代码
}finally{
      //异常发生,方法返回之前,总是要执行的代码
}


        在Java中,应用try-catch-finally结构可以使我们在出现异常的时候能保证相关资源被按时正确的清理。 

        我们都知道一个try-catch-finally结构,只要try块开始执行了,finally块里面的代码保证执行一次并且只执行一次。try-catch-finally给我们提供了在抛出异常时“保证执行某个动作”的机会,机会是提供了,但是finally一定会把握这次机会,完成某个动作的执行吗?或者说finally能完成它{...}里的相关操作吗?(当然这里除了system.exit()操作,因为在system.exit()时,finally是不会执行的) 

       下面我们就通过一个例子来说明一下,一个最常见的实例应用就是jdbc的Connection, Statement, ResultSet的使用。

先看一个例子:

例1:

void test(){ 
   Connection conn = ...; 
   Statement stmt = ...; 
   ResultSet rset = ...; 
   rset.close(); 
   stmt.close();
   conn.close(); 
   ... 
} 


        乍一看,这个程序没有问题,按jdbc标准ResultSet, Statement, Connection都close()掉了,不用GC来帮忙回收资源了。但是如果在rset或者stmt关闭时,出现了异常,那么conn的close()就不能执行了,那么就会存在着浪费资源的问题。也就是说这个例子这样写是有问题的。 

        这个时候我们就会想到用finally来执行ResultSet, Statement, Connection的close()操作,在finally中,肯定能执行这些close()操作。

例2:

void test(){ 
     Connection conn = null; 
     Statement stmt = null; 
     ResultSet rset = null; 
     try{ 
          conn = ...; 
          stmt = ...; 
          rset = ...; 
          ... 
     } catch(Exception e){
          e.printStackTrace();   
     } finally{ 
          if(rset!=null)rset.close(); 
          if(stmt!=null)stmt.close(); 
          if(conn!=null)conn.close(); 
     } 
} 


        有人认为这下终于安全了,不会存在资源浪费的情况了。 

        其实很多人都是这么认为的,但是在finally里close的时候,也是会抛出异常的。如果在执行if(stmt!=null)stmt.close(); 出现了异常,那么conn.close()是不会执行的,finally{}不能完全执行结束。这样写还是有可能出现问题的。

所以就需要对上面的例2再进行改造:

例3:

void test(){ 
Connection conn = null; 
Statement stmt = null; 
ResultSet rset = null; 
try{ 
conn = ...; 
stmt = ...; 
rset = ...; 
... 
} 
finally{ 
try{ 
   if(rset!=null)rset.close(); 
}catch(Exception e){ 
   e.printStackTrace(); 
} 

try{ 
   if(stmt!=null)stmt.close();
}catch(Exception e){ 
   e.printStackTrace(); 
} 

try{ 
   if(conn!=null)conn.close();
}catch(Exception e){ 
   e.printStackTrace(); 
} 
} 
} 


        这样就可以解决因为异常而存在浪费资源的问题了。一般的Exception通过例3都能解决这些问题。 

        但是除了Exception,我们的程序还会碰到Error,那么上面这个例子是否也能处理Error呢?众所周知,Error代表不可恢复错误,是程序无法处理的错误,所以我们也处理不了这种Error。所以在finally里执行stmt.close()时,如果出现Error,那么conn.close()还是不会被执行的。finally还是不能执完全行结束。那我们遇到Error时,该怎么处理里? 

        这里我们可以把Error转成Exception或者RuntimeException,然后抛出,再做处理。因为对于一个应用系统来说,系统所发生的任何异常或者错误对操作用户来说都是系统"运行时"异常,都是这个应用系统内部的异常。这也是将Error转成Exception或者RuntimeException的指导原则(当然也可以将Exception-->RuntimeException)。 

        ①:Error到Exception:将错误转换为异常,并继续抛出。例如Spring WEB框架中,将org.springframework.web.servlet.DispatcherServlet的doDispatch()方法中,将捕获的错误转译为一个NestedServletException异常。这样做的目的是为了最大限度挽回因错误发生带来的负面影响。因为一个Error常常是很严重的错误,可能会引起系统挂起。 

        ②:Exception到RuntimeException:将检查异常转换为RuntimeException可以让程序代码变得更优雅,让开发人员集中经理设计更合理的程序代码,反过来也增加了系统发生异常的可能性。 

       ③:Error到RuntimeException:目的还是一样的。把所有的异常和错误转译为不检查异常,这样可以让代码更为简洁,还有利于对错误和异常信息的统一处理。 

        所以例3总的来说,还是存在着一些问题,这样对于上面的例3我们又需要进行程序的修改(在例4中就不介绍Error与Exception或者RuntimeException的转换了):

例4:

void test(){ 
 final Connection conn = ...; 
 try{ 
  final Statement stmt = ...; 
  try{ 
   final ResultSet rset = ...; 
   try{ 
    ... 
   }catch(Exception e){
      e.printStackTrace();
   }finally{rset.close();} 
  }catch(Exception e){
   ...
  }finally{stmt.close();} 
 }catch(Exception e){
  ...
 }finally{conn.close();} 
} 


       这样每建立一个需要清理的资源,就用一个try-catch-finally来保证它可以被清理掉。当然了,在执行close操作的时候,我们必须要注意close的次序。通过例4你会发现,close的次序问题好像已经被解决了,不用去考虑这个问题了。


=====================================================================================================

在Java里finally子句的处理还有其他诡异的地方。比如:它可以改写返回值。
如下所示:

public class Test {
	public static void main(String[] args) {
		System.out.println(ret(-1));
		System.out.println(ret(1));
	}

	private static boolean ret(int i) {
		try {
			if (i < 0) {
				return false;
			} else {
				return true;
			}
		}catch (Exception e) {
			// TODO: handle exception
		}finally{
			return false;
		}
	}
}



        两次的返回结果都是:false。其实在调用ret(1)的时候,按道理应该返回true,但是就因为finally里的return操作改写了返回值。所以一般情况下,finally里不会return。


===================================================================================================== 

     其实在例4中还是存在着一些小问题的:

  

void test(){ 
	final Connection conn = ...; 
	try{ 
		final Statement stmt = ...; 
		try{ 
			final ResultSet rset = ...; 
			try{④
				...③
			}catch(Exception e){①
				e.printStackTrace();②
			}finally{
				rset.close();⑤
			}
		}catch(Exception e){
			...
		}finally{stmt.close();} 
	}catch(Exception e){
		...
	}finally{conn.close();} 
}

 

        ①: 这里应该指定具体的异常,而不提倡用一个catch(Exception e)语句捕获所有的异常。

     catch语句表示我们预期会出现某种异常,而且希望能够处理该异常。异常类的作用就是告诉Java编译器我们想要处理的是哪一种异常。

 

     在这段程序中,最明显的一个就是SQLException,这是JDBC操作中常见的异常。所以我们在捕获这个异常的时候最好能说明具体是那个异常。

 

     如果这try块中有多个异常产生,那么最好是通过多个catch来捕获不同的异常,而不是为了图省事,就用一个catch(Exception e)语句捕获所有的异常。

 

      ②:这里异常丢弃了,因为调用一下printStackTrace算不上“处理异常”,调用printStackTrace对调试程序有帮助,但程序调试阶段结束之后,printStackTrace就不应再在异常处理模块中担负主要责任了。

 

     所以在异常处理的时候针对具体异常采取具体行动,例如修正问题、提醒某个人或进行其他一些处理,要根据具体的情形确定应该采取的动作。 认为自己不能处理的一场,可以重新抛出异常也不失为一种选择,或者把该异常转换成另一种异常(可以把一个低级的异常转换成应用级的异常)。

 

       ③:如果在这个地方进行数据循环输出,而在循环输出时抛出了异常,那么循环的执行就会被打断的,这样就会导致用户将收到一份不完整的(或者错误的)数据,但却得不到任何有关这份数据是否完整的提示。对于有些系统来说,数据不完整可能比系统停止运行带来更大的损失。

 

       这个时候就要在处理异常的时候向输出设备写一些信息,声明数据的不完整性;另一种可能有效的办法是,先缓冲要输出的数据,准备好全部数据之后再一次性输出,如下所示:

 

catch(SQLException sqlex) 
{ 
 out.println("警告:数据不完整"); 
 throw new SQLException("读取数据时出现SQL错误", sqlex); 
} 

 

       ④:try块不要过于庞大

      把大量的语句装入单个巨大的try块就象是把所有东西就扔到一个大箱子,不能是吃的,还是用的,虽然东西是带上了,但要找出来却不容易。

 

       ⑤:其实应该跟例3一样

 

finally{ 
try{ 
   if(rset!=null)rset.close(); 
}catch(Exception e){ 
   e.printStackTrace(); 
} 
}

 

分享到:
评论

相关推荐

    Java异常框架设计

    这篇博文“Java异常框架设计”可能探讨了如何有效地利用Java的异常处理机制来构建可靠的系统。在这个讨论中,我们将深入理解Java异常的基本概念、异常分类、以及如何通过良好的框架设计提升代码的可读性和可维护性。...

    高效的java异常处理框架高效的java异常处理框架高效的java异常处理框架

    本文将从 Java 异常的基本概念和语法开始,讲述 Java 异常处理的基本知识,分析 Java 异常体系结构,对比 Spring 的异常处理框架,阐述异常处理的基本原则,并提出了自己处理一个大型应用系统异常的思想,并通过设计...

    java 异常框架CODE

    Java异常框架是Java编程语言中处理程序运行时错误和异常的核心机制。在Java中,异常是一种特殊的对象,用于表示程序运行过程中的不正常状态。Java的异常处理模型基于\"异常处理块\",包括try、catch、finally和throw...

    java异常框架处理.pdf

    Java异常框架处理是Java编程中十分关键的一部分,主要涉及到Java异常类的层次结构、异常的分类、异常的处理方式,以及如何在实际开发中使用异常框架来处理各种运行时错误。 首先,我们需要了解Java的异常类的层次...

    深入探索高效的Java异常处理框架

    Java异常处理是编程中至关重要的一个环节,它用于在程序执行期间处理错误和不正常的情况。本文深入探讨了高效Java异常处理框架,旨在提高代码的健壮性和稳定性。首先,文章介绍了异常的基本概念和Java异常体系结构。...

    Java异常处理体系

    Java异常处理的核心在于五个关键字:try、catch、finally、throw和throws。这些关键字帮助程序员构建了一个框架,当程序遇到预期或未预期的问题时,能够妥善地响应。 1. **try**:try块是异常处理的起点,它包含...

    在静态编译器中实现Java异常机制的算法.pdf

    在静态编译器中实现Java异常机制的算法 Java 异常机制是 Java 语言中的一种重要机制,用于处理程序中的异常情况。在静态编译器中实现 Java 异常机制可以提高 Java 程序的执行效率和可靠性。下面将对在静态编译器中...

    java 异常 问题收集 Exception

    在这个“java 异常 问题收集 Exception”主题中,我们将深入探讨Java异常处理的基本概念、常用类以及最佳实践。 1. 异常的概念与分类: Java中的异常是程序运行时出现的不正常情况,通常会导致程序中断。Java将...

    java 异常处理 代码实例

    Java异常处理是编程中至关重要的一个环节,它确保了程序在遇到错误时能够优雅地运行,而不是突然崩溃。本篇文章将深入探讨Java异常处理的概念、机制以及如何通过代码实例进行有效的异常管理。 Java异常处理的核心...

    07 java异常处理和集合框架

    Java异常处理和集合框架是Java编程中的两个核心概念,它们对于编写健壮、高效和易于维护的代码至关重要。在这个主题中,我们将深入探讨这两个领域的关键知识点。 首先,让我们来看看Java异常处理。在Java中,异常是...

    java实验报告4-异常处理

    Java异常处理是编程中至关重要的一个环节,它确保了程序在遇到错误时能够优雅地运行,而不是突然崩溃。本实验报告“java实验报告4-异常处理”旨在帮助初学者掌握Java中的异常处理机制,以及如何利用log4j进行日志...

    java异常管理

    Java异常处理包括五个关键字:try、catch、finally、throw和throws。try块用于包含可能会抛出异常的代码,catch块用来捕获并处理异常,finally块确保在任何情况下都会执行的代码,无论是否发生异常。如果一个方法...

    java框架及基础开发培训

    Java框架及基础开发培训是Java开发者提升技能的重要环节,它涵盖了Spring、Struts和Hibernate(SSH)等主流的Java Web框架。这些框架大大简化了应用程序的开发,提高了开发效率,并促进了代码的可维护性和可复用性。...

    java异常总结

    ### Java异常总结 #### 一、Java异常概述 在Java编程语言中,异常处理机制是一项非常重要的特性。它提供了一种方法来响应错误条件,并且能够有效地管理程序运行时可能出现的各种异常情况。Java中的异常主要分为两...

    Java异常处理机制应用研究.pdf

    本文将详细介绍 Java 异常处理机制的应用研究,包括 Java 异常体系统结构、异常分类与处理机制、异常处理的一般原则和异常处理框架等。 Java 异常体系统结构 Java 异常体系统结构如图 1 所示,Throwable 是所有...

    各种JAVA基础及框架

    - **异常处理**: 异常是程序运行过程中可能出现的错误,Java提供了try-catch-finally语句来处理异常。 - **线程**: Java支持多线程编程,可以创建和控制线程以实现并发处理。 - **输入输出流**: 用于文件读写和网络...

    使用try-catch-finally处理异常

    Java、C#等许多编程语言提供了异常处理框架,其中“try-catch-finally”是常用的一种结构。下面我们将详细探讨这个主题。 1. **异常的概念** 异常是程序执行期间发生的非正常情况,它可能由用户输入错误、文件不...

    Java API中的异常类体系框架捕捉及详解.docx

    Java异常处理的关键字包括`try`、`catch`、`finally`、`throw`和`throws`。`try`块用来包含可能会抛出异常的代码,当异常发生时,控制流会立即跳转到匹配的`catch`块。`catch`块用于处理特定类型的异常,可以有多个`...

    Java异常处理的四大金刚:try、catch、finally和throw的深度解析

    ### Java异常处理的四大金刚:try、catch、finally和throw的深度解析 #### Java异常处理概述 异常处理机制是程序设计中的一个重要组成部分,它能够帮助程序员有效地管理程序运行过程中可能出现的各种错误情况。...

    Java Web开发异常处理方式及AOP技术

    在Java Web开发中,异常处理是一项至关重要的任务,它确保了程序在遇到错误时能够优雅地处理并提供有用的反馈信息,而不是突然崩溃。本主题将深入探讨Java Web开发中的异常处理方式以及Aspect-Oriented Programming...

Global site tag (gtag.js) - Google Analytics