java的异常Exception
2017-06-19 22:24
183 查看
1.什么是异常
非正常的,不同于平常的.生活中:医生说,你的身体某个部位有异常,该部位和正常相比有点不同,该部位的功能将受影响.张三要开车去上班,正常情况下,应该是到达公司,上班.不正常的情况下,车子坏了,只能走路去,导致上班迟到.
程序中:在程序中,代码出现错误,程序就会终止运行.
异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行.
----------------------------------------
异常处理是衡量一门语言是否成熟的标准之一,主流的语言Java,C++,C#等支持异常处理机制.
异常处理机制可以让程序有更好的容错性,使我们的代码更健壮.
遗憾的是传统的C语言却没有异常,此时只能程序员通常使用方法的特定返回值来表示异常情况,并且使用if语句来判断正常和非正常情况,那没有异常会带来什么问题呢?
----------------------------------------
没有异常机制存在的缺点:
1:使用方法的返回值来表示异常情况有限,无法穷举所有的异常情况.
2:异常流程代码和正常流程代码混合一起,增大了程序的复杂性,可读性也不好.
3:随着系统规模的不断扩大,程序的可维护性极低.
2.java的异常体系
1):Error:表示错误,一般指JVM相关的不可修复的错误,如,系统崩溃,内存溢出,JVM错误等,由JVM抛出,我们不需要处理.
几乎所有的子类都是以Error作为类名的后缀.
2):Exception:表示异常,指程序中出现不正常的情况,该问题可以修复(处理异常).
几乎所有的子类都是以Exception作为类名的后缀.
----------------------------------------------------------------------------------------------------
出现异常,不要紧张,把异常的简单类名,拷贝到API中去查.
----------------------------------------------------------------------------------------------------
常见的Error:
StackOverflowError:当应用程序递归太深而发生内存溢出时,抛出该错误。
常见的Exception:
NullPointerException:空指针异常,一般指当对象为null的时候,调用了该对象的方法,字段.
ArrayIndexOutOfBoundsException:数组的索引越界,(小于0或者大于等于数组长度)
NumberFormatException:数字格式化异常, 一般指,把非0~9的字符串转换为整数.
--------------------------------------------------------------
证明出现异常之后,程序会中断,所以必须处理异常.
2.捕获异常
如果异常出现的话,会立刻终止程序,所以我们得处理异常:1):该方法不处理,而是声明抛出,由该方法的调用者来处理(throws).
2):在方法中使用try-catch的语句块来处理异常.
-----------------------------------------------------------------------
使用try-catch捕获单个异常,语法如下:
try{
编写可能会出现异常的代码
}catch(异常类型 e){
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
注意:try和catch都不能单独使用,必须连用.
举例:
1)正常情况
public class ExceptionDemo1 { public static void main(String[] args) { System.out.println("begin----"); int ret = 10/2; //正常的结果 System.out.println("结果="+ret); System.out.println("end------"); } }
2)出现异常,程序会中断执行
public class ExceptionDemo1 { public static void main(String[] args) { System.out.println("begin----"); int ret = 10/0; //除数为0,出现异常 System.out.println("结果="+ret); System.out.println("end------"); } }
可以看出程序出现异常后,程序会终止,这时我们需要处理异常
public class ExceptionDemo1 { public static void main(String[] args) { System.out.println("begin----"); try{ int ret = 10/0; //除数为0,出现异常 System.out.println("结果="+ret); }catch(ArithmeticException e){ System.out.println("出异常啦!!!!"); } System.out.println("end------"); } }
分析:
可以看出异常出现后程序跳转到catch块儿执行,当catch块儿的代码执行完之后,程序并没有停止,而是继续执行后面的代码
3.获取异常信息
如何获取异常信息,Throwable类的方法:1):String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误原因).
2):String toString():获取异常的类型和异常描述信息(不用).
3):void printStackTrace():打印异常的跟踪栈信息并输出到控制台. 不需要使用System.out.println.
包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace.
记住:现在在catch语句块中,必须写:e.printStackTrace();目的:查看异常的具体信息,方便调试和修改.
public class ExceptionDemo1 { public static void main(String[] args) { System.out.println("begin----"); try{ int ret = 10/0; //除数为0,出现异常 System.out.println("结果="+ret); }catch(ArithmeticException e){ System.out.println("异常信息"+e.toString()); //异常信息java.lang.ArithmeticException: / by zero System.out.println("异常信息"+e.getMessage()); //异常信息/ by zero //推荐使用下面这个 e.printStackTrace();//自带打印功能异常信息,java.lang.ArithmeticException: / by zero //at cn.anyglobe.ExceptionDemo1.main(ExceptionDemo1.java:8) } System.out.println("end------"); } }
使用try-catch捕获多个异常:
try{
编写可能会出现异常的代码
}catch(异常类型A e){ 当try中出现A类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}catch(异常类型B e){ 当try中出现B类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
public class ExceptionDemo1 { public static void main(String[] args) { System.out.println("begin----"); String sNum1 = "10"; //输入的除数 String sNum2 = "0"; //输入的被除数 try{ int num1 = Integer.parseInt(sNum1); int num2 = Integer.parseInt(sNum2); int ret = num1/num2; //除数为0,出现异常 System.out.println("结果="+ret); }catch(ArithmeticException e){ System.out.println("除数为0"); }catch (NumberFormatException e) { System.out.println("类型转换异常"); } System.out.println("end------"); } }
public class ExceptionDemo1 { public static void main(String[] args) { System.out.println("begin----"); String sNum1 = "10"; //输入的除数 String sNum2 = "0"; //输入的被除数 try{ int num1 = Integer.parseInt(sNum1); int num2 = Integer.parseInt(sNum2); int ret = num1/num2; //除数为0,出现异常 System.out.println("结果="+ret); }catch(ArithmeticException e){ System.out.println("除数为0"); }catch (NumberFormatException e) { System.out.println("类型转换异常"); } System.out.println("end------"); } }
从上面两个代码可以看出,捕获多个异常时,程序只需要一个catch捕获,不可能同时出现多个异常.
如果不知道什么异常的话可以用父类接收
public class ExceptionDemo1 { public static void main(String[] args) { System.out.println("begin----"); String sNum1 = "10"; //输入的除数 String sNum2 = "0"; //输入的被除数 try { //String转换为int类型 int num1 = Integer.parseInt(sNum1); int num2 = Integer.parseInt(sNum2); //两个整数相除 int ret = num1 / num2; //除数为0,出现异常 System.out.println("结果=" + ret); } catch (ArithmeticException e) { System.out.println("除数为0"); } catch (NumberFormatException e) { System.out.println("类型转换异常"); } catch (Exception e) { e.printStackTrace(); //其他异常统一用父类接受也可以 } System.out.println("end------"); } }或者直接用父类接收全部异常
public class ExceptionDemo1 { public static void main(String[] args) { System.out.println("begin----"); String sNum1 = "10"; //输入的除数 String sNum2 = "0"; //输入的被除数 try { //String转换为int类型 int num1 = Integer.parseInt(sNum1); int num2 = Integer.parseInt(sNum2); //两个整数相除 int ret = num1 / num2; //除数为0,出现异常 System.out.println("结果=" + ret); } catch (Exception e) { e.printStackTrace(); //直接用异常父类接收 } System.out.println("end------"); } }
注意:
1:一个catch语句,只能捕获一种类型的异常,如果需要捕获多种异常,就得使用多个catch语句.
2:代码在一瞬间只能出现一种类型的异常,只需要一个catch捕获,不可能同时出现多个异常.
4.finally代码块
finally语句块表示最终都会执行的代码,无论有没有异常.---------------------------------------------------------------------------------------
什么时候的代码必须最终执行:
当我们在try语句块中打开了一些物理资源(磁盘文件/网络连接/数据库连接等),我们都得在使用完之后,最终关闭打开的资源.
---------------------------------------------------------------------------------------
finally的两种语法:
1):try...finally: 此时没有catch来捕获异常,因为此时根据应用场景,我们会抛出异常,自己不处理.
2):try...catch....finally:自身需要处理异常,最终还得关闭资源.
没有异常:
public class ExceptionDemo2 { public static void main(String[] args) { System.out.println("begin...."); try { int ret = 10 / 2; } catch (ArithmeticException e) { System.out.println("异常:除数为0"); } finally { System.out.println("关闭资源"); } System.out.println("end....."); } }
出现异常:
public class ExceptionDemo2 { public static void main(String[] args) { System.out.println("begin...."); try { int ret = 10 / 0; } catch (ArithmeticException e) { System.out.println("异常:除数为0"); } finally { System.out.println("关闭资源"); } System.out.println("end....."); } }
可以看见,没有异常或者出现异常之后,程序会处理异常,打印异常信息,然后会进入finally代码块执行代码块中的内容,无论有没有异常,finally中的代码都会执行.
注意:finally不能单独使用.
---------------------------------------------------------------------------------------
当只有在try或者catch中调用退出JVM的相关方法,此时finally才不会执行,否则finally永远会执行.
System.exit(0);//退出JVM
public class ExceptionDemo2 { public static void main(String[] args) { System.out.println("begin...."); try { int ret = 10 / 0; } catch (ArithmeticException e) { System.out.println("异常:除数为0"); System.exit(0);//JVM退出 } finally { System.out.println("关闭资源"); //此时不执行 } System.out.println("end....."); } }---------------------------------------------------------------------------------------
finally和不使用finally的区别,必须使用finally才能保证最终必须执行的代码.
如果finally有return语句,永远返回finally中的结果,避免该情况.
5.异常的分类
异常(Exception)的分类:根据在编译时期还是运行时期去检查异常?1):编译时期异常:checked异常.在编译时期,就会检查,如果没有处理异常,则编译失败.
2):运行时期异常:runtime异常.在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错).
运行异常:在编译时期,可处理,可不处理.
---------------------------------------------------
如何确定某一个异常类是编译异常还是运行异常呢?
6.抛出异常
抛出异常:throw: 运用于方法内部,用于给调用者返回一个异常对象,和return一样会结束当前方法.
/** * * throw: 运用于方法内部,用于给调用者返回一个异常对象,和return一样会结束当前方法. * * return返回的是一个值,throw返回的是一个错误,返回给方法的调用者 * @author Lin * */ public class ThrowDemo { public static void main(String[] args) { System.out.println("abcdef".charAt(2));//截取数组索引为-1的位置,必须返回.此处不知道该返回一个什么值,所以用throw返回一个异常给调用者 //查 charAt 有 throw new StringIndexOutOfBoundsException(index); System.out.println("------------"); try { int ret = divide(10,2); System.out.println(ret); } catch (ArithmeticException e) { System.out.println(e.getMessage()); } } private static int divide(int num1, int num2) { System.out.println("begin..."); if (num2 == 0) { // System.out.println("除数不能为0"); // return 1; throw new ArithmeticException("除数不能为0"); } System.out.println("==================");// 当num2 =0的时候,此处代码执行不到, // throw相当于return,返回的是一个错误结果 try { int ret = num1 / num2; System.out.println("结果 =" + ret); return ret; } catch (ArithmeticException e) { e.printStackTrace(); } System.out.println("end...."); return 0; } }throws: 运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
如:private static int divide(int num1, int num2) throws Exception {}
/** * * * 运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常). 如:private static int divide(int num1, int num2) throws Exception {} * @author Lin *ArithmeticException 为RuntimeException 可处理也可不处理 *Exception 必须处理 * * *如果每一个方法都放弃处理异常都直接通过throws声明抛出,最后异常会抛到main方法,如果此时main方法不处理,继续抛出给JVM,底层的处理机制就是打印异常的跟踪栈信息. */ public class ThrowsDemo { public static void main(String[] args) throws Exception { divide(10, 0); } //在本方法中不处理某种类型的异常,提醒调用者需要来处理该异常 private static int divide(int num1, int num2) throws Exception { System.out.println("begin..."); if (num2 == 0) { throw new Exception("除数不能为0");//此处如果为RuntimeException就不会编译出错 } try { int ret = num1 / num2; System.out.println("结果 =" + ret); return ret; } catch (ArithmeticException e) { e.printStackTrace(); } System.out.println("end...."); return 0; } }------------------------------------------------------------------------------------------------------------------
throw语句:
运用于方法内部,抛出一个具体的异常对象.
throw new 异常类("异常信息"); 终止方法.
------------------------------------------------------------
throw:
一般的,当一个方法出现不正常的情况的时候,我们不知道该方法应该返回什么,此时就返回一个错误,在catch语句块中继续向上抛出异常.
return 是返回一个值,throw 是返回一个错误,返回给该方法的调用者.
如果每一个方法都放弃处理异常都直接通过throws声明抛出,最后异常会抛到main方法,如果此时main方法不处理,继续抛出给JVM,底层的处理机制就是打印异常的跟踪栈信息.
-------------------------------------------
runtime异常,默认就是这种处理方式.
--------------------------------------------
方法的覆盖(Override):
一同:方法的签名必须相同.
两小:
1):子类方法返回类型和父类方法返回类型相同,或是其子类.
2):子类方法不能声明抛出新的异常.
一大: 子类方法的访问权限必须大于等于父类方法的访问权限.
7.自定义异常
为什么需要自定义异常类:我们说了Java中不同的异常类,分别表示着某一种具体的异常情况,那么在开发中总是有些异常情况是SUN没有定义好的,此时我们根据自己业务的异常情况来定义异常类.
什么是自定义异常类:在开发中根据自己业务的异常情况来定义异常类.
自定义一个业务逻辑异常: LogicException.
//业务逻辑异常 public class LogicException extends RuntimeException { private static final long serialVersionUID = 1L; public LogicException() { super(); } public LogicException(String message, Throwable cause) { super(message, cause); } public LogicException(String message) { super(message); /** * message 表示和当前异常的原因/信息 * cause当前异常的根本原因 */ } }
//于logicexception 关联 public class RegisterDemo { // 假设数据库中已经存在的账号 public static void main(String[] args) { try { // 可能出现的异常代码 isExist("will"); System.out.println("注册成功"); } catch (Exception e) { // 处理异常 System.out.println("用户:" + e.getMessage());// 对不起,用户名will已存在 } } //判断当前注册的账号是否存在 private static boolean isExist(String username) { String[] data = { "will", "lucy", "xiaoming" }; for (String name : data) { if (name.equals(username)) { throw new LogicException("该名字已经被注册"); // 返回错误的结果给catch(调用者) } } return true; } }
异常类如何定义:
方式1):自定义一个受检查的异常类: 自定义类 并继承于java.lang.Exception.
方式2):自定义一个运行时期的异常类:自定义类 并继承于java.lang.RuntimeException.
8.异常转译和异常链
异常转译:当位于最上层的子系统不需要关心底层的异常细节时,常见的做法是捕获原始的异常,把它转换为一个新的不同类型的异常,再抛出新的异常.异常链:把原始的异常包装为新的异常类,从而形成多个异常的有序排列,有助于查找身材异常的根本原因.
9.Java7的异常新特性
Android用不到Java7,支持的Java5/java6语法.----------------------------------------------------------------------------------------
1):增强的throw
//增强的throw 处理异常更加精细 public class ThrowDemo { public static void main(String[] args) { try { doWork(); } catch (FileNotFoundException e) { e.printStackTrace(); } } public static void doWork() throws FileNotFoundException { try { new FileOutputStream(""); //非runtime } catch (Exception e) { e.printStackTrace(); throw e ;//继续抛给调用者 } } }
2):多异常捕获
//多异常捕获 public class MultiCatchDemo { public static void main(String[] args) { String num1 = "50"; String num2 = "2b"; try { int ret1 = Integer.parseInt(num1); // String类型转换为int类型 int ret2 = Integer.parseInt(num2);// String类型转换为int类型 System.out.println("==============="); int ret = ret1 / ret2; System.out.println("结果为" + ret); } catch (ArithmeticException | NumberFormatException e) { //处理算数异常 System.out.println("异常类型1"); e.printStackTrace(); }catch (Exception e) { //都不满足上述异常类型的时候执行这里 ,在所有catch之后 System.out.println("异常类型3"); e.printStackTrace(); } } }
3):自动资源关闭
import java.io.FileOutputStream; import java.io.OutputStream; public class AutoCloseDemo { public static void main(String[] args) { test1(); test2(); } private static void test1() { OutputStream out = null; try { // 打开一个资源对象 out = new FileOutputStream("C:/123.txt"); // 操作资源对象 out.write(1); } catch (Exception e) { e.printStackTrace(); } finally { // 关闭资源 try { if (out != null) { out.close(); } } catch (Exception e) { e.printStackTrace(); } } } private static void test2() { try ( // 打开资源对象 OutputStream out = new FileOutputStream("C:/123.txt"); ) { out.write(1); } catch (Exception e) { // 处理异常 e.printStackTrace(); } } }
10.处理异常的原则:
1:异常只能用于非正常情况,try-catch的存在也会影响性能.2:需要为异常提供说明文档,比如Java doc,如果自定义了异常或某一个方法抛出了异常,我们应该记录在文档注释中..
3:尽可能避免异常.如NullPointerException
4:异常的粒度很重要,应该为一个基本操作定义一个 try-catch 块,不要为了简便,将几百行代码放到一个 try-catch 块中.
5:不建议在循环中进行异常处理,应该在循环外对异常进行捕获处理(在循环之外使用try-catch).
6:自定义异常尽量使用RuntimeException类型的.
相关文章推荐
- java.util.ConcurrentModificationException异常
- 异常:java.util.ConcurrentModificationException
- Java基教--异常与错误区别 Error and Exception
- seam的异常总结——java.lang.RuntimeException: exception invoking: getTransaction
- 异常:java.util.ConcurrentModificationException
- 异常:java.util.ConcurrentModificationException
- [Domino]“java.lang.ClassCastException:lotus.domino.cso.Item”异常解决办法
- 异常:java.lang.ClassNotFoundException: org.springframework.web.jsf.DelegatingVariableResolver
- 解决spring+hibernate+struts2的java.lang.reflect.InvocationTargetException-->null异常
- Java 学习笔记 (4) -异常 Exception
- java.util.ConcurrentModificationException异常的解决办法
- 【原创】java.lang.ClassCastException异常问题解决
- 异常:java.util.ConcurrentModificationException
- Tomcat:IOException while loading persisted sessions: java.io.EOFException异常处理
- 什么是异常,我们为什么要关心它--The Java Tutorial--Exception第一节
- Tomcat:IOException while loading persisted sessions: java.io.EOFException异常处理
- [Domino]“java.lang.ClassCastException:lotus.domino.cso.Item”异常解决办法
- Jboss客户端连接EJB,javax.naming.CommunicationException [java.rmi.ConnectException: Connection refused to host: 127.0.0.1]异常解决
- Hibernate的Exception in thread "main" java.lang.NoSuchMethodError的异常
- java.util.ConcurrentModificationException 异常