`

java异常处理(初级)

    博客分类:
  • Java
阅读更多

从学习到现在从事java开发一年多了,个人觉得对java只了解皮毛,很多东西都是用到再去慢慢学习,编程真的是一项艺术,要完成一段好的代码,需要懂得很多。

最近项目经理让我负责一个组件开发,框架都由自己搭建,最让我头疼的是异常处理,我看了一些网上的源码,发现他们对异常的处理不是很重视,研究了很久都没有找到很好的解决方案。后来有幸看到一个200W美元的项目部分源码,通过他们对异常处理的解决方案,我终于弄通了java异常的一些基本机制,在这与大家分享一下。

 

(一)说到异常,首先从Throwable开始,Throwable是所有异常的基类,旗下有Error和Exception两个子类:Error属于程序无法控制的错误,通常不推荐捕获,捕获了你也处理不了;Exception就是我们熟知的可控制异常了。Exception旗下又分两种异常,运行时异常(RuntimeException)和非运行时异常:运行时异常是不需要强制捕获的,因为它随时随地可能发生,比如空指针异常(NullPointerException)和数组下标越界(IndexOutOfBoundsException);而非运行时异常在java里是需要你最终捕获的,不然编译都不通过,比如IO异常(IOException)和数据库错误(SqlException)。

 

下面来个例子:

①运行时异常数组下标越界(IndexOutOfBoundsException):

public class RuntimeDemo {
	public static void main(String[] args) {
		List<String> lst = new ArrayList<String>();
		lst.add("1");
		System.out.println(lst.get(10));
	}
}

 

上面代码list里只有1条数据,但是我希望获取第11条数据,肯定会报异常的,但是我不需要捕获异常,因为结果是运行是异常,它会自动抛出异常:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 10, Size: 1
	at java.util.ArrayList.RangeCheck(ArrayList.java:547)
	at java.util.ArrayList.get(ArrayList.java:322)
	at demo.RuntimeDemo.main(RuntimeDemo.java:10)

 

②非运行时异常,IoException为例:

public class IoDemo {
	public static void main(String[] args) {
		File f = new File(""); 
		try {
			f.createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

这里要求我必须捕获或者抛出,看结果:

java.io.IOException: 系统找不到指定的路径。
	at java.io.WinNTFileSystem.createFileExclusively(Native Method)
	at java.io.File.createNewFile(File.java:883)
	at demo.IoDemo.main(IoDemo.java:10)

 

 

 

(二)异常的两种处理方式:抛出和捕获。

抛出异常表示当前的错误不在本方法中处理,交由调用当前方法的地方处理;捕获异常表示当前错误在本方法中通过catch捕获进行一些特殊处理。

①首先来看try...catch:

public class ThrowDemo {
	public void cathcMethod(){
		System.out.println("running cathcMethod...");
		File file = new File("");
		try {
			file.createNewFile();
		} catch (IOException e) {
			//直接在本方法把异常消化掉
			System.out.println("running cathcMethod's catch...");
		}
	}
	
	public static void main(String[] args) {
		ThrowDemo td = new ThrowDemo();
		td.cathcMethod();
		System.out.println("running???????");
	}

这里main函数里会运行cathcMethod方法,而该方法绝对会出现IOException异常,我们要看的是当运行完cathcMethod后,下面一句 System.out.println("running???????")是否会执行,看结果:

running cathcMethod...
running cathcMethod's catch...
running???????

 

结果是,虽然td.cathcMethod();发生了异常,但是没有影响后面的代码的执行。这是因为当程序运行到cathcMethod方法时会发生IOException,但是cathcMethod方法通过catch直接捕获了异常,等于这个错误被该方法消化了,外面是不知道里面情况的。

这种捕获异常的方法通常是不可取的,因为你莫名其妙把这个重要的一个异常“吃”掉了,很可能会影响到一个系统的正常运作,通常我们会考虑抛出异常。

抛出异常需要说到两个关键字:throw和throws,这个东西口头不好说,直接代码说话:

public class ThrowDemo {
	/**
	 * 
	 * Function  : 直接抛出异常
	 * @author   : bless<505629625@qq.com>
	 * @throws IOException
	 */
	public void throwsMethod() throws IOException{
		System.out.println("running throwsMethod...");
		File file = new File("");
		file.createNewFile();
	}
	
	public static void main(String[] args) throws IOException {
		ThrowDemo td = new ThrowDemo();
		td.throwsMethod();
		System.out.println("running??????");
	}
}

 

throws写在方法后面,表示当前方法可能会出现的异常,一但加上了throws xxxException则该异常在方法体内就不需要用try...catch刻意捕获了(当然你也可以写,后面再说)。这个throws表示什么意思呢?它表示当运行当前方法时,可能会出现一个异常,但是当前方法不做处理,让调用该方法的地方去处理。我们看到main方法也有throws IOException ,这样再往上抛的话就到java虚拟机了,java虚拟机捕获到错误时就会打印错误信息到控制台,我们看结果:

running throwsMethod...
Exception in thread "main" java.io.IOException: 系统找不到指定的路径。
	at java.io.WinNTFileSystem.createFileExclusively(Native Method)
	at java.io.File.createNewFile(File.java:883)
	at demo.ThrowDemo.throwsMethod(ThrowDemo.java:16)
	at demo.ThrowDemo.main(ThrowDemo.java:21)

 

我们看到上面运行了throwsMethod方法,但因为发生了异常终止了main方法里System.out.println("running??????");的执行,这是因为当运行到某个方法,该方法发生异常时候,如果该方法是throws了异常的,则该程序就只执行到发生异常的方法,然后把异常再往上处理。当然如果你在main函数里像厦门这样写,结果又不一样了:

public static void main(String[] args) {
		ThrowDemo td = new ThrowDemo();
		try {
			td.throwsMethod();
		} catch (IOException e) {
			System.out.println("running error...");
		}
		System.out.println("running??????");
	}

 

 

 

 

(三)回头说说我正在开发的组件,后台三层Dao层(数据库操作)、Service层(业务操作)、Action层(实现页面交互),代码运行顺序依次是dao->service->action,action采用的是struts2框架,我的设计思想是dao和service对异常进行封装,到action层通过拦截器截获异常进行处理。为了明确发生了什么异常,个人建议使用自定义异常,通过自定义异常来处理各种错误。

首先看自定义异常代码:

public class SystemException extends RuntimeException{
	private static final long serialVersionUID = 1L;
	
	String errorCode = "default";

	public SystemException(){
		super();
	}
	
	public SystemException(Throwable e){
		super(e);
	}
	
	public SystemException(String message){
		super(message);
	}
	
	public SystemException(String message,Throwable e){
		super(message,e);
	}
	
                 public SystemException(String errorCode,String message){
          super(message);
          this.errorCode = errorCode;
}

	/**
	 * 最常用的构造方法
	 * @param errorCode 错误ID
	 * @param message   错误消息
	 * @param e         异常信息
	 */
	public SystemException(String errorCode,String message,Throwable e){
		super(message,e);
		this.errorCode = errorCode;
	}
	
	public String getErrorCode() {
		return errorCode;
	}

	public void setErrorCode(String errorCode) {
		this.errorCode = errorCode;
	}
}

 

首先介绍几点我这个自定义异常:

①为什么继承RuntimeException: 因为RuntimeException是运行时异常,是不需要被捕获或强行抛出的,如果自定义异常继承Exception,后面方法都得捕获或throws,很麻烦。

②errorCode的作用:错误编号,这个是关键,因为系统可能会有很多种异常,我们可以给每种异常定义一个错误编号,然后在action层通过拦截器捕获自定义异常的errorCode,就可以知道是什么错误了。

 

再说Dao层使用的是spring封装过的类,spring把所有非运行时异常全部转换成了运行时异常。为了保证用户能明白执行什么,我会对每个方法捕获RuntimeException然后转换成自定义异常:

public class BaseDaoImpl extends HibernateDaoSupport implements BaseDao {
 	public Object getObject(Class clazz, Serializable id)
			throws RuntimeException {
		Object o = null;
		try {
			o = getHibernateTemplate().get(clazz, id);
		} catch (RuntimeException e) {
			throw new SystemException("query_error","Sql exceptioin : query data error!",e);;
		}
		return o;
	}
}

 其它层可能涉及到非运行时异常,比如action层ajax,后台可能会打印信息到页面,这时可能会有IOException:

PrintWriter out;
		try {
			out = response.getWriter();
		} catch (IOException e) {
			throw new SystemException("io_error","response.getWriter() error!",e);
		}

 

 

未完待续...

7
0
分享到:
评论
6 楼 白糖_ 2013-12-18  
linlin1987 写道
白糖_ 写道
linlin1987 写道
好厉害!你好,认真学习了你这篇文章,有一个疑惑请教一下,看你的回复,你相当于把errorCode处理成了一个映射表,对吧?就是前面是错误编号,后面对应的是错误信息,是这样么?然后,errorCode为什么不做成枚举类?能不能看一下你的errorCode代码?谢谢啦!!!!!


errorCode完全可以做成枚举
errorCode的作用是让开发人员立刻理解错误的大致方向,然后好迅速定位排


errorCode 其实有一个问题,就是增加了开发人员的工作量。需要开发人员一边写程序,旁边还要放一个错误映射表,当他要抛出异常的时候,来查表确定异常对应的errorCode值,而且如果没有查到对应的errorCode值,还需要自行添加?


errorCode用不用取决于开发人员自觉性,如果我throw new SystemException(e);就没有errorCode。但是如果每个开发人员都谨慎抛出异常,那么errorCode就能很好运作,这个的确是需要一定工作量,但是一旦你做好了就一劳永逸的事。
至于你说的自行添加,肯定是多个开发人员一起往里添内容啦
5 楼 linlin1987 2013-12-12  
白糖_ 写道
linlin1987 写道
好厉害!你好,认真学习了你这篇文章,有一个疑惑请教一下,看你的回复,你相当于把errorCode处理成了一个映射表,对吧?就是前面是错误编号,后面对应的是错误信息,是这样么?然后,errorCode为什么不做成枚举类?能不能看一下你的errorCode代码?谢谢啦!!!!!


errorCode完全可以做成枚举
errorCode的作用是让开发人员立刻理解错误的大致方向,然后好迅速定位排


errorCode 其实有一个问题,就是增加了开发人员的工作量。需要开发人员一边写程序,旁边还要放一个错误映射表,当他要抛出异常的时候,来查表确定异常对应的errorCode值,而且如果没有查到对应的errorCode值,还需要自行添加?
4 楼 白糖_ 2013-12-12  
linlin1987 写道
好厉害!你好,认真学习了你这篇文章,有一个疑惑请教一下,看你的回复,你相当于把errorCode处理成了一个映射表,对吧?就是前面是错误编号,后面对应的是错误信息,是这样么?然后,errorCode为什么不做成枚举类?能不能看一下你的errorCode代码?谢谢啦!!!!!


errorCode完全可以做成枚举
errorCode的作用是让开发人员立刻理解错误的大致方向,然后好迅速定位排
3 楼 linlin1987 2013-12-09  
好厉害!你好,认真学习了你这篇文章,有一个疑惑请教一下,看你的回复,你相当于把errorCode处理成了一个映射表,对吧?就是前面是错误编号,后面对应的是错误信息,是这样么?然后,errorCode为什么不做成枚举类?能不能看一下你的errorCode代码?谢谢啦!!!!!
2 楼 白糖_ 2011-05-04  
获RumtimeException再重新
Loudyn 写道
请问
public class BaseDaoImpl extends HibernateDaoSupport implements BaseDao {
 	public Object getObject(Class clazz, Serializable id)
			throws RuntimeException {
		Object o = null;
		try {
			o = getHibernateTemplate().get(clazz, id);
		} catch (RuntimeException e) {
			throw new SystemException("query_error","Sql exceptioin : query data error!",e);;
		}
		return o;
	}
}

为什么要申明抛出RumtimeException?
其次为什么在捕获RumtimeException再重新抛出你自定义的RumtimeException后还要让代码继续执行下去?,如果我在你所谓的action层上这样调用你的代码:
Object obj = dao.getObject(xxx.class,id);

我是不是还要:
if(null!=obj)
  //do something else

再者,为何要定义那些所谓的error_code,如果我维护你的代码,再得到异常后,我是不是要进去你的代码,看一下error_code的定义?异常的语义本身就很丰富,为什么还要定义什么error_code?
毋庸置疑,维护你所写的代码将会是艰辛的事。



①为什么要申明抛出RuntimeException?
因为spring在封装hibernate的时候已经将所有jdbc的非运行时异常(如SQLException)转换成自定义的运行时异常(RuntimeException),所以用RuntimeException捕获已经足够
②还要不要if(null!=obj)//do something else
答案是:不用,如果在上面发生了异常以后,异常会一直向上抛,直到某个地方在此try...catch捕获它,前面我已经说过:代码运行顺序依次是dao->service->action,action采用的是struts2框架,如果dao层抛出了RuntimeException,到action层通过拦截器截获异常进行处理即可
③为什么要定义error_code?
正是为了代码维护,这个error_code是为了给用户看的,我把所有的error_code按照编辑依次写到一个文件中,当发生异常的时候,拦截器获取error_code编号再去文件中找对应的错误信息,然后把文件中已经写好的错误信息返回给用户。比如在文件中定义一个编号为error_code001,错误消息为:该条数据已被删除。最后用户在页面上就能看到的信息是:该条数据已被删除。
异常的语义确实太丰富了,所以我们程序员要尽量去分析不同情况的异常,最后转换成用户能看懂的错误消息(总不能让用户看到:java.lang.NullPointerException
这样的信息吧)
1 楼 Loudyn 2011-02-17  
请问
public class BaseDaoImpl extends HibernateDaoSupport implements BaseDao {
 	public Object getObject(Class clazz, Serializable id)
			throws RuntimeException {
		Object o = null;
		try {
			o = getHibernateTemplate().get(clazz, id);
		} catch (RuntimeException e) {
			throw new SystemException("query_error","Sql exceptioin : query data error!",e);;
		}
		return o;
	}
}

为什么要申明抛出RumtimeException?
其次为什么在捕获RumtimeException再重新抛出你自定义的RumtimeException后还要让代码继续执行下去?,如果我在你所谓的action层上这样调用你的代码:
Object obj = dao.getObject(xxx.class,id);

我是不是还要:
if(null!=obj)
  //do something else

再者,为何要定义那些所谓的error_code,如果我维护你的代码,再得到异常后,我是不是要进去你的代码,看一下error_code的定义?异常的语义本身就很丰富,为什么还要定义什么error_code?
毋庸置疑,维护你所写的代码将会是艰辛的事。

相关推荐

    java基础教学-java初级资料.zip

    共十五个章节 第一章 认识java 第二章 java 语言语法1 第三章 java 语言语法2 ...第十章 异常处理 第十一章 java集合 第十二章 文件操作以及流 第十三章 java线程 第十四章 java网络编程 第十五章 XML

    java初级项目(一)

    这个是Java的初级练习小项目,涉及到的内容有:基础语法/集合的使用/IO读写流/异常处理/

    Java语言与面向对象程序设计第16讲(异常处理,多线程和流式输入输出与文件处理)

    java语言与面向对象设计PPT,讲解的很是详细,很适合初级学员仔细拜读,里面还有很多随堂练习题

    Java初级开发面试题

    Java基础知识:语法、面向对象编程、集合、多线程、异常处理等。 Java高级特性:反射、泛型、枚举、注解、 Lambda表达式等。 Java虚拟机:Java内存模型、垃圾回收、类加载机制等。 常见的Java框架:Spring、...

    完整版 Java基础入门教程 Java程序语言设计 全套PPT课件资源 共17个章节 含源代码.rar

    完整版 Java基础入门教程 Java程序语言设计 06 异常处理 异常和垃圾收集(共27页).ppt 完整版 Java基础入门教程 Java程序语言设计 07 网络编程 JDBC(共21页).ppt 完整版 Java基础入门教程 Java程序语言设计 07 ...

    面试必问Java面试题,对标初级Java

    1.Java泛型(约束类型) 2.Java中函数式编程-Stream流-Lambda表达式 3.JVM虚拟机 ...17.Java中异常处理机制 18.java中==equals有哪些区别 19.ArrayList和LinkedList有什么区别 20.Java面向对象有哪些特征

    Java范例大全 源码

    首先,全书以Java开发环境搭建开篇,循序渐进地介绍了Java语法的方方面面,不仅包括变量、语句、字符串、数组、类、集合、面向对象等必备的基础语法,而且还涵盖异常处理与反射机制、I/O文件操作、线程、数据库操作...

    java源码包---java 源码 大量 实例

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    java JDK 实例开发宝典

    全书共有19个章节,169个实例,内容涉及Java的语言基础、面向对象程序设计、数字处理、数组与集合、字符串、异常处理、文件操作、多线程、Swing编程、图形和多媒体编程、反射机制、网络程序设计、数据库编程、Applet...

    JAVA上百实例源码以及开源项目

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    JAVA上百实例源码以及开源项目源代码

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    java源码包4

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码...

    从零开始学Java资源包

    全书内容分为六篇共23章,讲解了Java的各个方面,主要内容包括Java语言的环境配置、基本语法、流程控制语句、字符串处理、数组、面向对象、图形界面设计、输入/输出、异常处理、网络编程、数据库及Java Web基础JSP和...

    java源码包3

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码...

    Java后端+Java后端中级面试题

    请解释Java中的异常处理机制,并提供一个相关的示例。 什么是Java中的线程?如何创建和管理线程? 解释什么是Java的集合框架,并提供一些常用的集合类和它们的用法。 请解释Java中的反射机制,以及它的用途和局限性...

    Java大数据开发+Java大厂面试题

    请解释Java中的异常处理机制,并提供一个相关的示例。 什么是Java中的线程?如何创建和管理线程? 解释什么是Java的集合框架,并提供一些常用的集合类和它们的用法。 请解释Java中的反射机制,以及它的用途和局限性...

    Java面试题+Java后端中级面试题

    请解释Java中的异常处理机制,并提供一个相关的示例。 什么是Java中的线程?如何创建和管理线程? 解释什么是Java的集合框架,并提供一些常用的集合类和它们的用法。 请解释Java中的反射机制,以及它的用途和局限性...

    java源码包2

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码...

    一份面向Java初学者和初级工程师的知识点总结和面试题解析,着重关注面试中最常见的知识点。.zip

    Java基础知识点:包括数据类型、面向对象特性、异常处理、集合框架等。 Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 ...

    Java技术教程.基础篇.pdf 高清下载

    Java技术教程基础篇顾名思义就是面向JAVA初级新手,是一本入门书籍,全书一共17章,从JAVA环境配置、数据类型、流程控制、面向对象、字符串处理、异常处理、线程、用户界面、JAVA小程序制作、集合框架、网络通信、...

Global site tag (gtag.js) - Google Analytics