简单了解Java异常

  一   Throwable 

      在刚开始学习编程的时候,或多或少的会出现一些问题,有的问题在你编写的时候已经提示了,而有的问题只有在你遇到问题中才会出现,而这个问题我们称它为异常

      这里异常可以分三类 

  • 检查性异常  这是我们日常编程过程中最常见的问题,在编译的时候 不能被忽略
  • 运行时异常  能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
  • 错误             可以理解为不能被察觉的问题,不在我们编程时的意料之中.不好追究问题

前两个引用下菜鸟的分类

  • 检查性异常: 不处理编译不能通过
  • 非检查性异常:不处理编译可以通过,如果有抛出直接抛到控制台
  • 运行时异常: 就是非检查性异常
  • 非运行时异常: 就是检查性异常

       这两个可以不用细分,在官方文档中,主要分为异常和错误,从之前的概念中我们已经得知在Java设计中,Object是万物的父类,即根类.可以注意到平常所用到的类除了第三方外都是继承自Object类中,异常也不类外

       看下从APi文档中找到的异常类

       Throwable是Java语言中所有错误和异常的Throwable类,只有作为此类或子类的实例对象才可以使用,即Throwable是所有异常的父类,

     而Throwable的直接子类有两个 一个错误即Error 一个 异常即Exception,

Q:它们有什么区别呢  

       先来看看异常的表现形式,下面的代码作用为了去重并输出自定义对象储存的内容.当然用set集合更好,但是输出的时候下标范围+1,编译阶段没有发生任何问题,也没有提醒,说明是逻辑上是没有问题的,但是运行的时候却挂了,因为判断的时候引用了超出了集合的范围的元素:


import java.util.ArrayList;
//这里有class Teacher 里面有两个属性 name 和age
public class Test2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ArrayList<Teacher> tc=new ArrayList<Teacher>();
		Teacher teacher1=new Teacher("张三",11);
		Teacher teacher2=new Teacher("张三一",15);
		Teacher teacher3=new Teacher("张三一",12);
		Teacher teacher4=new Teacher("张三三一",11);
		Teacher teacher5=new Teacher("张三一",15);
		tc.add(teacher1);
		tc.add(teacher2);
		tc.add(teacher3);
		tc.add(teacher4);
		tc.add(teacher5);
		ArrayList<Teacher> tc2=new ArrayList<Teacher>();	
		for(int x=0;x<tc.size()+1;x++) {//这里集合tc的下标+1,超出了范围
			while(tc2.contains(tc.get(x))==false) {
				tc2.add(tc.get(x));
			}
		}
		System.out.println(tc2);
	}

}

结果报错

        在API文档中看下,这个异常的信息IndexOutOfBoundsException 

 

        这里我们可以看见,它继承自RuntimeException 而RuntimeException继承自Exception异常类

再观察下Error类

 

引入一个概念:

Error:           所有的编译时期的错误和系统错误由Error抛出的,表示故障是在虚拟机自身或者虚拟机运行时发生的,这些错误是不可查的,它们在应用程序的控制和处理能力之 外,而且大多数是程序运行时不允许出现的状况.对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况.

Exception:   异常子类,它规定的异常是程序本身可以处理的异常,异常和错误的区别是,异常是可以被处理的,而错误是没法处理的.

而我们一般所研究的则是可以处理的异常.

二   异常

Exception

捕获异常

使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方:

        try {
            for(int x=0;x<2321002235515;x++) {
                System.out.println(x);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

try里面放的是可能发生异常的代码段, 一般来说, try里面不要放太多的代码,一方面如果代码多了, 我们是不容易发现出现问题的代码,不好去定位问题,一方面也不美观. 而Catch 语句放要捕获异常类型的声明。

上面的代码是有问题的,因为x小于的数,已经超出x的范围,已经是不能运行

public class Test10 {
    public static void main(String[] args) {
        int [] arr= {1,2,3};
        try {
            System.out.println(arr[3]);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
}


再看看这段代码数组下标最大为2,我输出了arr[3],是没有这个元素的,所以我用try将它抓起.

结果:

这种方法我们称它为捕获异常

一般来说,正确的try...catch结构是这样的

public class Test10 {
	public static void main(String[] args) {
		int [] arr= {1,2,3};
		try {
			System.out.println(arr[3]);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally {
			System.out.println("结束啦");
		}
		
	}
}

try..catch...finally  有一点要注意finally关键字里的代码块一定会执行,无论是否捕捉到异常.除非一种情况,就是JVM虚拟机停止运行了. 

此外finally这个结构里,有一些相关的逻辑题可以去做,能更加深入了解这个概念

比如(https://blog.csdn.net/WYpersist/article/details/80710352)

final finalze finally的区别等

 

多重捕获

      一个catch代码块后还有多个catch的情况,我们称它为多重捕获,这时如果 catch不是对应的异常,继续在第二个catch里寻找

try{
   // 程序代码
}catch(异常类型1 异常的变量名1){
  // 程序代码
}catch(异常类型2 异常的变量名2){
  // 程序代码
}catch(异常类型2 异常的变量名2){
  // 程序代码
}

 注意:

         如果父类抛出多个异常,则覆盖方法必须抛出那些异常的一个子集,不能抛出新异常。

       捕获异常时,大的异常(Exception类)放在下方,小的异常放在上方,否则,在异常捕获时,小的异常将不能被捕获,因为全在大的异常类中捕获到。即: 如果多个 catch 块中的异常出现继承关系,父类异常 catch 块放在最下面。

 throws/throw 

如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法的尾部。

也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。

一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。

class a{
	void b() throws Exception{//这里可以抛出多个异常, 逗号隔开
		throw new	Exception();//这里抛一个异常,所以实现里也必须有个异常抛出
	}
}
public class Test10 {
	public static void main(String[] args) throws Exception  {
		a a=new a();
/*		try {
			a.b();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}//如果没有try catch 则会报错,必须在方法后抛出一个异常  
*/		a.b();
	}
}

 Q:throws和throw区别

从上面的代码我们也看到,两者都是抛出异常.

throws:

  • 抛出在方法声明上,方法后面跟异常类名,且可以多个中间逗号隔开
  • 表示抛出异常的可能性,交给调用者去处理

throw 

  • 抛出在方法体中,方法体中跟的是异常对象名 new xxException()
  • throw表单抛出异常的肯定性,有了这个后面必须做出处理
  • throw抛出的异常,交给方法体重语句处理
  • throw后只能跟一个异常对象

自定义异常类

自定义异常有几个要求.

  • 所有异常都必须是 Throwable 的子类。
  • 如果希望写一个检查性异常类,则需要继承 Exception 类。
  • 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。

可以像下面这样定义自己的异常类:

class MyException extends Exception{ }

只继承Exception 类来创建的异常类是检查性异常类。

我们自定义的异常类和其它任何类没有什么区别,包含有变量和方法。

class a extends Exception{
	void b() {
		System.out.println("我是b方法");
	}
}
public class Test10 {
	public static void main(String[] args)   {
		a a=new a();
		a.b();
	}
}

 这时候我们可以理解下自定义异常类的作用,不光用于抛出错误时候的异常,也可以用来处理异常,像银行取钱大于账户的余额当以当做异常,游戏的暴击,登录登出提示等等.关于使用方法我们可以再构思构思.

                                                                                                                                                                                            End

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值