【Java基础】Java异常的一些总结
什么是异常
异常是指程序运行可能出现的不能正常继续的情况,也可以理解为程序出现了不在预期范围内的一些情况,都可以称之为异常。
异常的分类
所有的异常类是从java.lang.Exception类继承的子类。Exception类是Throwable类的子类。除了Exception类外,Throwable还有一个子类Error 。Java程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。Error用来指示运行时环境发生的错误。例如,JVM内存溢出。一般地,程序不会从错误中恢复。层次关系图如下
Throwable
Error Exception
other Exception RuntimeException
所以从上图可以看出,异常分为两类:
- 运行时异常:运行的时候才出现的,程序编译期间无法预知,这种情况一般不做捕获。出现运行期异常一般是代码不严谨,需要修改代码。例如下面的例子
/**
* Created by lili on 15/11/25.
*/
public class ExceptionTest {
public static void main(String[] args) {
int a = 10;
int b = 0;
System.out.println(a/b);
System.out.println("---------");
}
}上述代码就是代码不严谨所致,分母不能为0,所以程序运行至a/b会抛出异常Exception in thread "main" java.lang.ArithmeticException: / by zero
java.lang.Object
继承者 java.lang.Throwable
继承者 java.lang.Exception
继承者 java.lang.RuntimeException
继承者 java.lang.ArithmeticException查看该异常,发现是运行期异常,所以不能捕获,需要给出处理,例如加一个if判断。
- 非运行时异常:在编译期间就能发现的异常,必须要明确捕获或者抛出,不然程序编译无法通过。例如下面的代码:
/**
* Created by lili on 15/11/25.
*/
public class ExceptionTest {
public static void main(String[] args) {
String dateStr = "2015-11-22";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date d = sdf.parse(dateStr); }
}上述代码无法通过编译,因为sdf.parse(dateStr)可能出现问题(尽管没问题),所以要做异常处理。
public class ExceptionTest {
public static void main(String[] args) {
String dateStr = "2015-11-22";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date d = sdf.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
} finally {
System.out.println("异常处理后");
}
System.out.println("结束在这里");
}
}
处理异常的几种方法
- try{语句;}catch(异常名 e){异常处理}catch(异常名 e){异常处理}...finally{结束处理}
上述是异常正面处理的方式,对可能出现异常的语句进行try catch,try包含的语句的原则是尽量要少,try catch可以有多层,例如上面的对日期处理的异常处理可以写成下面这样的多层异常处理,最下面一层处理所有可能出现的异常。try {
Date d = sdf.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
System.out.println("异常处理1");
} catch(Exception e){
e.printStackTrace();
System.out.println("异常处理2");
}finally {
System.out.println("异常处理后");
}也就是说,如果抛出的是异常A,我们处理异常A的父亲异常是可以的。但是,一般建议catch准确的异常。上述多层异常处理的前后关系必须是父亲异常必须在后,即异常范围越大越靠后放,即最后才可能去比较,这也符合精确处理的原则,因为如果将Exception写在最前面,后面的处理都不会执行。最后不管是否有异常需要处理,finally都会执行。
JDK7提供了一种新的异常捕获方式,该方法用户捕获同等级的异常,并且这些异常的处理方法可以有相同的处理方式。try{ }catch (ArithmeticException | ArrayIndexOutOfBoundsException e){
System.out.println("同类异常处理");
}finally { }try catch执行的逻辑:
在try里面发现问题后,jvm会帮我们生成一个异常对象,然后把这个对象抛出,和catch里面的类进行匹配。
一旦有匹配的,就执行catch里面的处理,然后结束了try...catch 继续执行后面的语句。 - throws:当出现的异常我们没有能力或者权限去处理时,可以在改方法体的()后面去抛出。
public class ExceptionTest {
public static void main(String[] args) {
String dateStr = "2015-11-22"; try {
dateFormat(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("这行代码可以执行");
} public static void dateFormat(String str) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(str);
}
}上述代码展示了如何使用throws,但是调用该方法的地方还是要面临该异常。面临的时候可以选择处理或者继续抛出,但是在main方法里最好不要再抛出,不然就抛给JVM。抛给JVM的话,一旦出现问题,那后面的代码就无法继续执行了。
public class ExceptionTest {
public static void main(String[] args) throws ParseException {
String dateStr = "2015-11-22";
dateFormat(dateStr);
System.out.println("这行代码执行不了"); } public static void dateFormat(String str) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(str);
}
} - throw:如果出现了异常情况,我们可以把该异常抛出,这个时候的抛出的应该是异常的对象。
public class ExceptionTest {
public static void main(String[] args) {
int a = 10;
int b = 0;
division(a,b);
} public static void division(int a,int b){
if(b==0){
throw new ArithmeticException("被除数为0");
}
System.out.println(a/b);
System.out.println("---------");
}
}上面之所以不会提示处理division,是因为ArithmeticException是运行时异常的子类,所以这是程序有问题,要改善程序。
throws和throw的区别
- throws
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常
2. throw
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定抛出了某种异常
finally关键字:如果执行finally之前JVM意外退出,finally也有可能执行不了
finally一般用在try catch中用来做最后的一些收尾工作,如释放资源,在IO操作和数据库操作中用的比较多。但是如果在catch中有return语句,finally是否会执行呢?
public class ExceptionTest {
public static void main(String[] args) {
int a = 10;
System.out.println("return a:"+ test(a));
} public static int test(int a) {
try{
a = 10;
int b = a / 0;
} catch (Exception e){
a = 20;
return a;
} finally {
a = 30;
System.out.println("finally a:" + a);
}
a = 40;
return a;
}
}
上面这段代码返回的是
finally a:30
return a:20
这说明,就算有返回语句,finally还是执行了,但是此时返回的a应该是30才对啊,观察debug发现,是执行到return把return语句的a替换为20后发现还有finally才去执行finally的,此时返回值已经确定。所以,finally中的语句执行在return中间;但是如果将代码改为下面这样,则返回的a也为30;
public class ExceptionTest {
public static void main(String[] args) { Student s = new Student(0);
System.out.println("return a:" + test(s).age);
} public static Student test(Student s) {
try {
s.age = 10;
int b = s.age / 0;
} catch (Exception e) {
s.age = 20;
return s;
} finally {
s.age = 30;
System.out.println("finally a:" + s.age);
}
s.age = 40;
return s;
}
}
如何自定义异常
上面就提到了,异常分为两类,一类是运行期异常,一类是非运行期异常,所以自定义异常类一般是继承自这两类异常。以Exception为例进行分析。
Exception类中出了5个构造方法,啥方法都没有。
public Exception(){}
public Exception(String message) {
super(message);
}
public Exception(String message, Throwable cause) {
super(message, cause);
}
public Exception(Throwable cause) {
super(cause);
}
protected Exception(String message, Throwable cause,
boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
这里就要去了解出现异常是打印的信息从何而来?前面讲到throw的时候就可以看出,创建一个Exception对象并throw。try catch中是自动创建了一个异常对象去对比,类型一致(或者可以向上转型)则执行catch。所以打印信息应该是new对象的时候传入的,也有默认的打印(空构造时)。
所以我们自定义异常时,出了要继承两类异常外,还需要至少有两个构造的方法,一个空构造,一个非空构造,这样可以自定义异常输出。
下面是一个自定义的异常类和测试用例:
public class ExceptionTest {
public static void main(String[] args){
int[] ageArr = new int[]{1,2,3,-1,130};
for(int a : ageArr){
try {
ageCheck(a);
} catch (AgeException e) {
e.printStackTrace();
}
} }
public static void ageCheck(int age) throws AgeException {
if(age > 120){
throw new AgeException("年龄超过120岁.");
}
if(age < 0){
throw new AgeException("年龄小于0岁.");
}
} } class AgeException extends Exception {
public AgeException() {
} public AgeException(String message) {
super(message);
}
}
异常注意事项
1. 子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)
2. 如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
3. 如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws
【Java基础】Java异常的一些总结的更多相关文章
- java基础之异常 · fossi
在开发中,异常处理是一个不可绕开的话题,我们对于异常的处理已经非常熟练了,对于异常本身的概念.用法等不再赘述了,直接结合面试问题来加深对异常的理解吧. Throwable 可以用来表示任何可以作为异常 ...
- Java基础-Java中23种设计模式之常用的设计模式
Java基础-Java中23种设计模式之常用的设计模式 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.设计模式分类 设计模式是针对特定场景给出的专家级的解决方案.总的来说设 ...
- java基础---->java中正则表达式二
跟正则表达式相关的类有:Pattern.Matcher和String.今天我们就开始Java中正则表达式的学习. Pattern和Matcher的理解 一.正则表达式的使用方法 一般推荐使用的方式如下 ...
- Java基础-Java中的堆内存和离堆内存机制
Java基础-Java中的堆内存和离堆内存机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.
- Java基础-Java中的内存分配与回收机制
Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二.
- Java基础-Java中的并法库之重入读写锁(ReentrantReadWriteLock)
Java基础-Java中的并法库之重入读写锁(ReentrantReadWriteLock) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在学习Java的之前,你可能已经听说过读 ...
- Java基础-Java中的并法库之线程池技术
Java基础-Java中的并法库之线程池技术 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是线程池技术 二.
- Java基础-JAVA中常见的数据结构介绍
Java基础-JAVA中常见的数据结构介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是数据结构 答:数据结构是指数据存储的组织方式.大致上分为线性表.栈(Stack) ...
- Java基础-Java数据类型
Java基础-Java数据类型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.数据类型的作用 数据类型就是一组值,以及这一组值上的操作,数据类型可以决定数据的存储方式,取值范围 ...
- 【java基础之异常】死了都要try,不淋漓尽致地catch我不痛快!
目录 1.异常 1.1 异常概念 1.2 异常体系 1.3 异常分类 1.4 异常的产生过程解析 2. 异常的处理 2.1 抛出异常throw 2.2 Objects非空判断 2.3 声明异常thro ...
随机推荐
- nls_sort和nlssort 排序功能介绍
nls_sort和nlssort 排序功能介绍 博客分类: oracle ALTER SESSION SET NLS_SORT=''; 排序影响整个会话 Oracle9i之前,中文是按照二进制编码 ...
- 【Druid】 阿里巴巴推出的国产数据库连接池com.alibaba.druid.pool.DruidDataSource
阿里巴巴推出的国产数据库连接池,据网上测试对比,比目前的DBCP或C3P0数据库连接池性能更好 简单使用介绍 Druid与其他数据库连接池使用方法基本一样(与DBCP非常相似),将数据库的连接信息 ...
- 一步步学习ASP.NET MVC3 (10)——@Ajax,JavaScriptResult(1)
请注明转载地址:http://www.cnblogs.com/arhat 首先老魏先说一下抱歉,昨天由于在安装CentOS,Mono,Jexus配置Linux环境下的ASP.NET运行环境,花费了不少 ...
- 成为JavaGC专家(2)—如何监控Java垃圾回收机制
什么是GC监控? 垃圾回收收集监控指的是搞清楚JVM如何执行GC的过程,例如,我们可以查明: 1. 何时一个新生代中的对象被移动到老年代时,所花费的时间. 2. Stop-t ...
- Servlet的getContextPath(), getServletPath(), getRequestURI(), getRealPath("/")
假定web application 名称为news,你在浏览器中输入请求路径: http://localhost:8080/news/main/list.jsp 则执行下面向行代码后打印出如下结果: ...
- 我的PHP之旅--数组的认识(初级)
数组 PHP的数组与swift有些许不同,分为3类(初级,以后会涉及到多维数组和数组指针等). 枚举数组 关联数组 混合数组 枚举数组 枚举数组跟swift中的数组差不多: <?php $arr ...
- Python属性、方法和类管理系列之----属性初探
在学习dict的时候,肯定听过dict是Python中最重要的数据类型,但是不一定知道为什么.马上你就会明白原因了. Python中从模块.到函数.到类.到元类,其实主要管理方法就是靠一个一个的字典. ...
- 使用js为html元素动态添加class
<ul id="root"> <li>1</li> <li>2</li> <li>3</li> ...
- APT攻防对抗
APT(高级持续性威胁)攻击是指近年来,专业甚至是有组织和国家背景支持的黑客,针对重要目标和系统发起的一种攻击手段,主要特征有 1)持续性:攻击者为了重要的目标长时间持续攻击直到攻破为止.攻击成功用上 ...
- FastCGI中文规范
http://fuzhong1983.blog.163.com/blog/static/1684705201051002951763/ . 介绍 FastCGI是对CGI的开放的扩展,它为所有因特网应 ...