今天来写一篇关于异常的博客呀 ,下面是个人总结的认为是比较全的异常的知识,异常对我们平时来说的话 还是挺重要的我觉得 。 从今天之后请叫小潘车厘子同志,哈哈哈
父类是Throwable ,下面由ERROR和异常
ERROR 是那种系统级别的错误 , 异常我们又分为 编译时期的异常 和运行时期的异常
在我们平常开发的过程当中java不可能对所有的情况都考虑到,在实际的开发中,我们可能
自己定义异常,而我们自己写的类是不能作为异常类的 要想你的类 是一个异常类 就必须继承自Exception 或者是RuntimeException
-
两种方式:继承自Exception (编译时期的异常)
-
或者是RuntimeException (运行时期的异常 )
-
所有的异常 :只有构造方法 没有其他的了
-
继承自Exception地话 。给一个无参地构造函数 来创建你地异常的对象
-
给出带字符串参数是因为 想要异常提供额外的信息
-
Exception :是编译时期的异常, 是比较严重的 需要进行throws在方法上面进行声明的
-
然后给方法的调用者 谁调用 谁就的try catch
-
当然 也是一直可以进行声明的 直到 抛到main方法上 让我们的Jvm来进行处理
-
但这是不负责任的表现,代码的可读性也很差
-
RuntimeException :属于的是运行时期的异常
-
如果你是继承 RuntimeException 的话 是不需要在方法上面进行声明的
//因为你还没有运行 你连会出现什么错误 你也是不知道的 -
可以选择try catch,也可以不进行try catch ,在这里是不做强制性的要求的
```
我们自己如何处理异常呢?
* try....catch..... finally
* throws 抛出 在方法上面进行异常的声明
*
* try ...catch ...final的处理格式:
* try{
* 可能出现问题的代码
* }catch(异常名 变量){
* 针对问题的处理
* }finally{
* 通常是用来方法释放资源
* 这里的代码一定执行的
*
* }
*
* 变形格式:
* try{
* 可能出现问题的代码
* }catch(异常名 变量){
* 针对问题的处理
* }
* 应该放在方法的里面
*
* 注意:try里面的代码越少越好
* 代码越多的话java需要给它分配更多的资源
*
* catch(){}里面必须有内容,哪怕只是一句简单的提示
* 将来开发的过程中,我们都是给对方明确的提示
*
*如果catch()里面不存放代码的话,
*就会不管,然后执行之后的代码 这样不行 就是属于隐藏异常
*
*自己处理异常的好处就是,前面出问题了没关系,
* 我后面的还可以继续的运行
*
* 让我们的java虚拟机去抓异常的话 如果你出现异常之后 你后面的代码就直接不执行了
* catch(){}语句不能脱离 try语句而独立的存在
```
方法中有多个异常的话 :
- 两个异常:每一个写一个 try…catch
- 写一个try…多个catch
- try{
- …
- }catch(异常类名 变量名){
- }
- catch(异常类名 变量名){
- }
- catch(异常类名 变量名){
- }
- 注意事项:
-
- 注意:一旦try出了问题,就会在这里把问题抛出去
- 和catch里面的问题就进行匹配,一旦有匹配的话
- 就会执行catch里面的处理 相当于结束了try…catch ()
- 继续执行后面的去了
- 比如说,你在try语句里面,第一句是 数组越界的赋值
- 第二句是 除数为0的算数的异常 在执行try里面的语句的时候,
- 在发现了第一个数组越界了之后就会去catch里面去找匹配的异常,一旦找到
- 就会执行catch异常 里面对应的语句,这句数组越界之后的try里面的代码就不会执行的到
-
- 注意事项:能明确的话就尽量的明确,不要大的来进行处理
- 会使效率变得很低 因为它是在一个一个具体的接口找,也是需要一定的时间的,需要耗费一定的资源
- 异常直接的关系呢?
- 是兄弟关系 都来自于runtime 时期的异常
-
- 平级关系的异常 谁前谁后都是无所谓的
- 如果出现了子父 关系 ,父一定是在后面的
- 一定是小的先抓,抓不到了大的再去抓
- 父亲出手了的话 儿子再出去就会报错
下面的这种做法是正确的
private static void method4() {
int a=10;
int b=0;
int []arr={1,2,3};
//爷爷是在最后
try{
System.out.println(a/b);
System.out.println(arr[3]);
System.out.println("这里出现了一个异常,你不太清楚该怎么办?");
}catch(ArithmeticException ae){
System.out.println("除数不能为0");
}
catch(ArrayIndexOutOfBoundsException ai){
System.out.println("数组越界了,访问了不该访问的索引");
//我在最后挂一个父类的异常 这样的话,谁都是跑不了的
}catch(Exception e){
System.out.println("出问题了");
}
System.out.println("over");
来一个错误的做法:
//爷爷在前面
//爷爷在前面
//匹配找的时候是先找第一个的
//爷爷是万能的,是所有的异常都是可以匹配的
//我一旦我出手去抓了 其他的都会报错 我把能抓的都抓了
/*
try{
System.out.println(a/b);
System.out.println(arr[3]);
System.out.println("这里出现了一个异常,你不太清楚该怎么办?");
}
catch(Exception e){
System.out.println("出问题了");
}
catch(ArithmeticException ae){
System.out.println("除数不能为0");
}
catch(ArrayIndexOutOfBoundsException ai){
System.out.println("数组越界了,访问了不该访问的索引");
//我在最后挂一个父类的异常 这样的话,谁都是跑不了的
}
System.out.println("over");
对于多个异常的话,我们的jdk7 出现了一个新的方法
-
JDK7针对多个异常的处理方案 :
-
JDK7出了一个新的异常处理方案
-
JDK的一个新特性就是可以一下子处理很多的异常
-
但是前提是这个异常的处理方法是一致的
-
另外一个缺点是: 不能利用父亲来抓异常了
-
try{
-
-
}cath(异常名1|异常名2|异常名3 …变量){
-
…处理的是多个
-
}
-
但是这个方法是不够好的
-
- 处理的方式是一致的(但是实际开发中可能针对好多同类型的问题,给出同一个处理)
-
符合我们实际开发要求的 比如说我不管你是咋样的操作的,就知道你是操作失败了
-
- 不能使用父亲来抓异常了
-
多个异常间必须是平级的关系 父亲不能抓异常了 放在哪里都是不可以的
-
应该是JDK1.8j进行了改进 我eclipse的jdk的版本是1.8 ,把Exception放在后面不会报错了
private static void method() {
int a=10;
int b=0;
int []arr={1,2,3};//JDK7 以后的方案 //这个处理变得十分得简单 //前提是这多个处理给的提示信息是一样的 //但是这样的话不能用父类来抓异常了 // 这里我们的eclipse 的版本是1.8 不知道为什么放在后面的话不会报错了 try{ System.out.println(a/b); System.out.println(arr[3]); } catch(ArithmeticException | ArrayIndexOutOfBoundsException e){ System.out.println("出问题了 "); }catch(Exception e){ System.out.println("这里出问题了"); }
编译时的异常和运行时期的异常 怎样的划分,以及应该怎样做
有些知识点可能会说重复,是在因为是太重要了 多说几遍
编译时期的异常和运行时期的异常的区别:
- 运行时期的异常我们是不需要进行处理的
- 不需要进行强制性的try catch
- 异常分为两大类,编译时期的异常,和运行时期的异常
- 所有的runtimeException以及它的子类的异常都称为
- 运行时期的异常
- 其他的异常就是编译时期的异常
- ArithmeticException
- 二者的区别:
- 编译时期的异常: 报差号的
- 在编译期间你必须进行处理,不处理的话就不行
- 处理的话点鼠标
- 运行时期的异常:
- 程序足够严谨的话运行时期是不会出现异常的
-
- 编译时期的异常:Java程序必须显示处理的,否则程序会发生错误,无法编译
- 运行时期的异常: 无需进行显示处理,也可以和编译处理异常一样处理
下面说一说Throwable为我们提供的几种显示异常的信息的方法。
/*
-
e.printStackTrace();
-
在try里面发现问题会,jvm会帮我们自己生成一个异常对象
-
然后把这个对象抛出,和catch里面的类进行匹配
-
如果该对象是某个类型的,那就执行该类型的catch的里面的处理信息
-
-
异常中要了解的几个方法
-
Throwable中的几个常见的方法:
-
public String getMessage()
-
返回的是throwable的详细消息字符串 异常的消息字符串
-
public String toString()
-
返回throwable的简短描述 结果是下列字符串的串联
-
此对象的类名字 name(全路径名)
-
": " 冒号和一个空格
-
调用此对象的getLocalizedMessage()方法的结果
-
默认返回的是getMessage()
-
可以重写的
-
这三个方法一起拼接而成的 可以往后走
*
*printStackTrace()
*获取异常类名和异常信息,以及异常在程序中出现的位置
*返回值是void -
把信息输出在控制台
-
给出了异常的信息之后我是还可以往后面走的
-
用这个
* -
printStackTrace(PrintStream s)
-
通过该方法把异常的内容保存到日志文件,以便查问
-
我将来可以方便的看我程序都是哪里出问题了
-
*/
public static void main(String[] args) {
String s=“2014-11-20”;
//ParseException
SimpleDateFormat sdf=new SimpleDateFormat(“yyyy-MM-dd HH-mm-ss”);
try {
//在这相当于创建了一个ParseException对象 抛出去
//和catch里面进行匹配
Date d=sdf.parse(s);
} catch (ParseException e) {
//ParseException e=new ParseException();
// TODO Auto-generated catch block
//ParseException
//没有出现空指针的问题,那么这里应该出现的是一个对象
//是对象的话我们就可以去看它的方法
//c
//System.out.println(e.getMessage()); //可以继续往后走
//Unparseable date: “2014-11-20” 我不能解析这个 over//toString() //System.out.println(e.toString()); //java.text.ParseException: Unparseable date: "2014-11-20" //over e.printStackTrace(); //异常的类名信息 出现位置 //跳转到某一个指定的页面 index.html //在这个页面上输出一句话 //我之后的东西是可以执行的 } System.out.println("over");
}
说一说我们的throws
throws
- 定义功能方法的时候,需要把出现的问题暴露出来
- throws在方法上进行标识 也就是说是对异常的声明
- 用在编译时期的异常的时候 我把我可能出现的异常 放我的方法上进行声明
- 让方法的调用者知道 然后对其进行处理 或者继续进行方法声明
-
- 有些时候,我们是可以对异常进行处理的, 但是有有一个时候我们没有权力去处理
- 某一个异常 或者说是我处理不了 我就索性不处理了 为了解决出错问题,
- Java针对这种情况就提供了另一种处理
- 抛出; 格式:
- throws 异常类名
- 注意:这个格式必须跟在方法的后面
-
- 注意:尽量不要再main方法上抛出异常 这样是不负责任的
- 你在main方法上面抛出的异常最后是我们的jvm在处理
-
- 编译期异常抛出将来调用者必须处理 在方法上面进行声明 不声明的话就会报错
- 方法的调用者进行异常的try catch 也就是捕获
- 运行期异常抛出将来调用者可以处理也可以不处理 我只有运行了我才会知道会出现怎样样的异常
- 不用进行方法声明(也可以进行 ) 捕获不捕获采取自愿
throws和throw的区别
- throws:用在方法声明后面,跟的是异常类名
- 可以跟多个异常类名 用逗号隔开
- 表示抛出异常 有该方法的调用者处理
- throws表示异常的一种可能性 并不一定会发生这些异常
-
- throw :
- 用在方法体内,跟的是异常对象名
- 只能抛出一个异常对象名
- 表示抛出异常 有方法体内的语句进行处理
- throw抛出了异常 ,执行 throw是一定出现了某种异常
到底是如何处理异常的呢?
原则:如果该功能内部可以将问题处理,用try
如果解决不了的话,就去交给调用者处理吧 这是throws
区别:
后续程序需要继续运行就用try
后续程序不需要运行就用throws 默认的虚拟机 就停止了
- 举例:
- 感冒了自己吃药就好了 try
- 吃了好几天药都没有好结果得了重感冒 那就得到throws医院
- 如果医院没有特效药变成Error了
- 变成Error之后我们也就没有办法了
finally 的特点和作用和面试题
- 格式 try{}catch…finally…
- 被finally 语句控制的语句体是一定会被执行的
- 常常用来释放资源
- 注意:如果执行到finally之前jvm 退出了 ,就不能执行了
- 虚拟机都退出了 就不能执行代码了
- 例如:System.exit(0);
- finally:用于释放资源 在IO流操作和数据库操作中会遇见
下面我们来说一说final,finalize,finally这三者的区别:
- final:最终的意思,可以修饰类,成员变量,成员方法
- 修饰类,类不能被继承
- 修饰变量,变量只能是常量 要有初始值
- 修饰方法,方法不能被重写 但是可以被继承
- 修饰引用的话,引用的地址不能改变,但是引用的值是可以改变的
- finally :异常处理的一部分,用于释放资源
- 一般来说,代码肯定是会被执行的,
- 特殊情况,在执行到finally 之前JVM就退出了 System.exit(0)
- finalize:不是关键字 是我们曾经讲过的一个方法
- 是Object类的一个方法,用于垃圾回收
-
-
- 如果catch里面有return 语句,请问finally里面的代码还会执行吗?
- 如果会,是在return 前还是在之后 ?
- 会 前 准确的来说是中间
- 只要虚拟机没退出就会执行finally里面的代码
- 会执行的 会在之前
- finally里面的执行内容不在return之前也不再之后在中间
- 3.try…catch…finally的格式变形
- A try…catch …finally
- B try…catch
- C try…catch…catch
- D try…catch…catch…finally
- E try…finally 这样也是没有问题的
- 做的目的是为了释放资源 异常不处理
- 单独使用catch 和finally是不可能的 必须有try的存在
可以看一下下面的这个代码 结果是30
public static void main(String[] args) {
System.out.println(getInt());
}
public static int getInt(){
int a=10;
try{
System.out.println(a/0);
a=20;
}catch(ArithmeticException e){
a=30;
return a;
/*
* return a 在程序执行到这一步的时候,这里不是return a
*而是return 30;
*这个返回路径就形成了
*但是它发现finally 就继续执行finally 的内容 a=40;
*再次回到以前的 返回路径 返回return 30;
*/
}finally {
a=40;
//return a;//如果这样的话 结果就是40
}
return a;
}
异常的注意事项:
-
A 子类覆盖父类的方法时(重写)必须输出相同的异常或父类异常的子类
-
(父亲坏了 儿子不能比它更坏 )
-
抛相同的是没有问题的 父亲比儿子一样坏 最好是这样
-
或者说是父亲比儿子坏
-
B :如果父类抛出了多个的异常,子类重写父类时,只能抛出相同的异常
-
或者是异常的子集
-
子类不能抛出父类没有的异常
-
-
C 如果被重写的方法没有抛出异常,那么子类的方法绝对不可以抛出异常
-
如果子类方法内有异常发生 那么子类只能用try 不能throw
-
-
你可以抛父类的异常或者是异常的子集,但是如果父类没有异常
-
子类就不能抛异常 这个时候你只能见到try catch
-
这种情况你肯定见得到
今天的分享就到这里了 我们下期见
如果总结的有错误的话欢迎来留言指正
分享一句名言: 我们在都努力,是为了我们共同的美梦。