异常

今天来写一篇关于异常的博客呀 ,下面是个人总结的认为是比较全的异常的知识,异常对我们平时来说的话 还是挺重要的我觉得 。 从今天之后请叫小潘车厘子同志,哈哈哈

父类是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 …变量){

  • …处理的是多个

  • }

  • 但是这个方法是不够好的

    1. 处理的方式是一致的(但是实际开发中可能针对好多同类型的问题,给出同一个处理)
  • 符合我们实际开发要求的 比如说我不管你是咋样的操作的,就知道你是操作失败了

    1. 不能使用父亲来抓异常了
  • 多个异常间必须是平级的关系 父亲不能抓异常了 放在哪里都是不可以的

  • 应该是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类的一个方法,用于垃圾回收
    1. 如果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

  • 这种情况你肯定见得到

    今天的分享就到这里了 我们下期见

如果总结的有错误的话欢迎来留言指正

分享一句名言: 我们在都努力,是为了我们共同的美梦。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值