异常:
异常:是在运行时期发生的不正常现象。
在java中用类的形式对不正常情况进行了描述和封装对象。
描述不正常的情况的类,就称为异常类。
以前正常流程代码和问题处理代码相结合,现在将正常流程代码和问题处理代码分离,提高阅读性。
其实异常就是java通过面向对象的思想将问题封装成了对象。
用异常类对其进行描述。不同问题用不同的类进行具体的描述,比如角标越界,空指针等等。
异常体系:
最终问题(异常情况)就分成了两大类:Throwable(下面两种情况的父类):
|--1 一般不可处理的。Error
特点:是由jvm抛出的严重性的问题。
这种问题发生一般不针对性处理。直接修改程序。
|-- 2 可以处理的。Exception
无论error还是异常,都是问题,问题发生就应该可以抛出,让调用者知道并处理
该体系的特点在于Throwable及其所有的子类都具有可抛性。
可抛性到底指什么?怎么体现可抛性?
其实是通过两个关键字来体现--throws throw。凡是可以被这两个关键字所操作的类和对象都具备可抛性。
该体系的特点:
子类的后缀名都是用其父类名作为后缀,阅读性很强。
public class ExceptionDemo {
public static void main(String[] args) {
int[] arr=new int[1024*1024*800];//java.lang.OutOfMemoryError内存溢出
sleep(-5);//但是时间没有负数,所以应该抛出异常
}
public static void sleep(int time){
//之前的处理方法是:if,阅读性差
/* if(time<0){
处理方法
处理方法
处理方法
}
if(time>1000000){
处理方法
处理方法
处理方法
}*/
System.out.print("我睡。。。"+time);
}
public static void sleep2(int time){
//现在的处理方法是:封装成类,调用异常类
// if(time<0){
// 抛出 new FuTime();//就代码时间为负的情况,这个对象中会包含着问题的名称,信息,位置等信息。
// }
// if(time>1000000){
// 抛出 new BigTime();
// }
System.out.print("我睡。。。"+time);
}
}
class FuTime{
}
class BigTime{
}
异常对象的抛出:
一般异常都是程序默认抛出异常,即由所调用的类抛出异常给(主函数里的)调用者,调用者抛给jvm,jvm直接显示异常的细节到Console。
但是,异常也可以由程序员抛出:
class Demo{
public int method(int[] arr,int index){
if(arr==null){
throw new NullPointerException("数组的引用不能为空");
}
if(index>=arr.length){
throw new ArrayIndexOutOfBoundsException("数组角标越界了"+index);
}
if(index<0){
throw new ArrayIndexOutOfBoundsException("角标不能为负数"+index);
}
return arr[index];
}
}
public class lizi {
public static void main(String[] args) {
int[] arr=new int[3];
Demo d=new Demo();
int num = d.method(null,8);
//int num1= d.method(arr, 5);
//int num2= d.method(arr, -4);
}
}
运行:
自定义异常:
对于角标是整数不存在,可以用角标越界表示。
对于负数为角标的情况,准备用负数角标异常来表示。
负数角标这种异常在java中并没有定义过。
那就按照java异常的创建思想,面向对象,将负数角标进行自定义描述,并封装成对象。
这种自定义的问题描述称为自定义异常。
注意:如果让一个类成为异常类,必须要继承异常体系,因为只有成为异常体系的子类才有资格具备可抛性。 才可以被两个关键字所操作,throws、throw。
class FuShuIndexException extends Exception{
FuShuIndexException(){
}
FuShuIndexException(String s){
super(s);//原理看底下Person的例子
}
}
class Demo{
public int method(int[] arr,int index) throws FuShuIndexException{//声明抛出
if(index<0){
throw new FuShuIndexException("角标不能为负数"+index);
}
return arr[index];
}
}
public class lizi {
public static void main(String[] args) throws FuShuIndexException{//调用者也需声明抛出
int[] arr=new int[3];
Demo d=new Demo();
int num2= d.method(arr, -4);
}
}
/*
class Person{
private String name;
Person(String name){
this.name=name;
}
public String getName(){
return name;
}
}
class Student extends Person{
Student(String name){
super(name);
}
}
*/
运行:
Exception异常的分类:
1 编译时被检测异常:只要是Exception和其子类都是,除了特殊子类RuntimeException体系。 这种问题一旦出现,希望在编译时就进行检测,让这种问题有对应的处理方式。 这样的问题都可以针对性处理
声明的目的时让调用我们的调用者去处理问题
2 编译时不检测异常(运行时异常):就是Exception中的RuntimeException和其子类。这种问题的发生,无法让功能继续,运行无法进行,更多是因为调用的原因导致的,或者引发了内部状态的改变导致的。那么这种问题一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者对代码进行修正。
所以无需在throws子类句中进行声明(开发时比较常遇到)
所以自定义异常时,要么继承Exception,要么继承RuntimeException
throws和throw的区别:
1 throws使用在函数上;throw使用在函数内
2 throws抛出的是异常类,可以抛出多个,用“,”隔开;throw抛出的是异常对象。
class Demo{
public int method(int[] arr,int index)
{
if(arr==null){
throw new NullPointerException("数组的引用不能为空");
}
if(index>=arr.length){
throw new ArrayIndexOutOfBoundsException("数组角标越界了"+index);
}
return arr[index];
}
}
public class lizi {
public static void main(String[] args)
{
int[] arr=new int[3];
Demo d=new Demo();
int num = d.method(null,8);
}
}
异常捕捉:
异常处理的捕捉形式:
这是可以对异常进行针对性处理的方式。
具体格式是:
try{
//需要被检测异常的代码
}catch(异常类 变量){//该变量用于接收发生的异常对象
处理异常的代码
}finally{
//一定会被执行的代码
}
如果你内部能解决的问题就catch,如果解决不了就抛出去(try)让调用者处理
class FuShuIndexException extends Exception{
FuShuIndexException(){
}
FuShuIndexException(String s){
super(s);
}
}
class Demo{
public int method(int[] arr,int index) throws FuShuIndexException//声明抛出
{
if(index<0){
throw new FuShuIndexException("角标变成负数啦!!!");
}
return arr[index];
}
}
class CatchDemo1{
public static void main(String[] args)
{
int[] arr=new int[3];
Demo d=new Demo();
try{
int num = d.method(arr,-8);
System.out.print(num);
}catch (FuShuIndexException x){
System.out.println("message"+x.getMessage());
System.out.println("String"+x);//本来应该输出的是哈希值,这里默认调用toString
x.printStackTrace();//jvm默认的异常处理机制就是调用异常对象的这个方法
System.out.println("负数角标异常!!!");
}
System.out.println("over");
}
}
运行:
多catch情况:
class FuShuIndexException extends Exception{
FuShuIndexException(){
}
FuShuIndexException(String s){
super(s);
}
}
class Demo{
public int method(int[] arr,int index) throws FuShuIndexException//声明抛出
{
if(arr==null){
throw new NullPointerException("数组的引用不能为空");
}
if(index<0){
throw new FuShuIndexException("角标变成负数啦!!!");
}
return arr[index];
}
}
class CatchDemo1{
public static void main(String[] args)
{
int[] arr=new int[3];
Demo d=new Demo();
try{
int num = d.method(null,-8);
System.out.print(num);
}catch(NullPointerException y){
System.out.println(y.toString());
}
catch (FuShuIndexException x){
System.out.println("message"+x.getMessage());
System.out.println("String"+x);//本来应该输出的是哈希值,这里默认调用toString
x.printStackTrace();//jvm默认的异常处理机制就是调用异常对象的这个方法
System.out.println("负数角标异常!!!");
}/*catch(Exception e){//面试可能会有 除以上异常之外又有异常的情况下,就用这个catch,
//不管发生啥异常 全都接收,但必须放在最后一个catch之后
//一般情况下不会发生这种情况(除声明抛出异常的情况下,jvm还是报错的情况下)
//多catch下父类的catch放在最下面
}*/
System.out.println("over");
}
}
异常处理的原则:
1 函数内部如果抛出需要检测的异常,那么函数上必须要声明(throws),否则必须在函数内用try-catch捕捉,否则编译失败。
2 如果调用到了声明异常的函数,要么trycatch要么throws,否则编译失败。
3 什么时候catch,什么时候throws呢?
内容功部可以解决,用catch;解决不了,用throws告诉调用者,由调用者解决。
4 一个功能如果抛出多个异常,那么调用时,必须对应多个catch进行针对性的处理。内部有几个需要检测的异常,就抛出几个异常,抛出几个,就catch几个。
finally:
class Demo{
public int show(int index)throws ArrayIndexOutOfBoundsException//有了这个,主函数就得try了
{
if(index<0){
throw new ArrayIndexOutOfBoundsException("数组角标越界了"+index);
}
int[] arr=new int[3];
return arr[index];
}
}
public class FinnallyDemo {
public static void main(String[] args) {
Demo d=new Demo();
try{
int num =d.show(-1);
System.out.println(num);
}
catch(ArrayIndexOutOfBoundsException e){
System.out.println(e.toString());
//return ;//finally还是能执行到
System.exit(0);//退出jvm,finally就执行不到了
}finally{//开发的时候常用 通常用于关闭(释放)资源
System.out.println("finally");
}
System.out.println("over");
}
}
/*
连接数据库 数据库本身就有资源限制 所以浪费不得 所以一定要有finally
查询 可能过程中出问题了
关闭连接 -->但是这个无论怎样都要执行 所以定义在finally中
try catch finally 代码块组合特点:
1 try catch finally
2 try catch(多个)当没有必要资源需要释放时,可以不用定义finally。
3 try finally(常用) 异常无法直接catch处理,但是资源需要关闭。
void show() throws Exception{
try{
//开启资源
throw new Exception();//出现异常
}
finally{
//关闭资源
}
}
*/
应用:
/*
老师用电脑上课
问题领域中涉及两个对象
老师,电脑
分析其中的问题:
比如电脑蓝屏了。
*/
class LanPingException extends Exception{
LanPingException(String msg){
super(msg);
}
}
class MaoYanException extends Exception{
MaoYanException(String msg){
super(msg);
}
}
class NoWanChengException extends Exception{
NoWanChengException(String msg){
super(msg);
}
}
class Computer{
private int stats=2;//0,1,2
public void run()throws LanPingException,MaoYanException
{
if(stats==1)
throw new LanPingException("电脑蓝屏了");
if(stats==2)
throw new MaoYanException("电脑冒烟了");
System.out.println("电脑运行");
}
public void reset(){
stats=0;
System.out.println("电脑重启");
}
}
class Teacher{
private String name;
private Computer comp;
Teacher(String name){
this.name=name;
comp=new Computer();
}
public void prelect ()throws NoWanChengException{
try{
comp.run();
System.out.println("讲课");
}catch(LanPingException e){
System.out.println(e.toString());
comp.reset();
prelect();
}catch(MaoYanException e){
System.out.println(e.toString());
test();
//可以对电脑进行维修
// throw e;并不是捕捉到异常就的抛出去,有的这边无法解决就得定义别的异常
//比如电脑冒烟,公司无法远程解决修理,就导致课程无法完成异常,所以就把问题换成解决无法完成课程的问题并抛出解决,老师可以换台电脑
throw new NoWanChengException("课程无法完成"+e.getMessage());
}
}
public void test(){
System.out.println("大家练习");
}
}
public class YingYong {
public static void main(String[] args) {
Teacher t=new Teacher("老师");
try{
t.prelect();
}catch(NoWanChengException e){
System.out.println(e.toString()+"...");
System.out.println("老师换电脑");
}
}
}
/*
class NoAddException extends Exception{}
void addData(Data d)throws (SQLException换成)NoAddException
{
连接数据库
try{
添加数据,出现异常SQLException
}catch(SQLException e){
//处理代码 这种方式也叫做异常的封装,就是不该暴露的问题就没有必要暴露出去,即使暴露出去对方也没办法解决
throw new NoAddException
}finally{
关闭数据库
}
}
*/
运行:
异常注意事项:
1 子类在覆盖父类方法时,父类的方法如果抛出了异常,那么子类的方法只能抛出父类的异常或者该异常的子类。
2 如果父类抛出多个异常,那么子类只能抛出父类异常或者其子集。
简单说:子类覆盖父类只能抛出父类的异常或者子类或者子集。
注意:
如果父类没抛出异常,那么子类覆盖时绝对不能抛。就只能try。
网友评论