Exception(Java异常)

来源:互联网 发布:精点数据 编辑:程序博客网 时间:2024/05/21 08:55
/*
异常。
Java运行时期发生的问题就是异常。


Java中运行时发生的除了异常Exception还有错误Error。


异常:通常发生可以有针对性的处理方式的。
错误:通常发生后不会有针对性的处理方式。
Error的发生往往都是系统级别的问题,都是jvm所在系统发生的并反馈给jvm的。
无法针对处理,只能修正代码。


*/

class ExceptionDemo 
{
public static void main(String[] args) 
{
int[] arr = new int[1024*1024*100];//OutOfMemoryError 


System.out.println(arr[0]);
System.out.println(arr[3]);//该句运行时发生了ArrayIndexOutOfBoundsException,导致程序无法继续执行。程序结束。
System.out.println("over");
}

}

/*
异常的发生细节。
*/


class Demo
{
/*
对给定的数组通过给定的角标获取元素。
*/
int getElement(int[] arr,int index)
{


/*
1,没有找到4个角标。运行时发生了问题,这个问题JVM认识。
这个问题java本身有描述:描述内容有:问题的名称,问题的内容,问题的发生位置。
既然有这么多的信息。java就将这些信息直接封装到对象中。ArrayIndexOutOfBoundsException
*/
int element = arr[index];//throw new ArrayIndexOutOfBoundsException(index);
return element;
}
}




class ExceptionDemo2 
{
public static void main(String[] args) 
{
Demo d = new Demo();
int[] arr = {34,12,67};
int num = d.getElement(arr,4);//收到 new ArrayIndexOutOfBoundsException(index); 抛出jvm。jvm进行最终处理。将问题的名称,信息,位置都显示屏幕上。
System.out.println("num="+num);
System.out.println("over");
}
}

/*
异常的应用:


在编写程序时,必须要考虑程序的问题情况。
举例:卖水果功能需要传递钱参数,有可能有假币。
所以定义定义程序需要考虑程序的健壮性。


加入一些逻辑性的判断。








*/
class Demo
{
/*
对给定的数组通过给定的角标获取元素。
*/
int getElement(int[] arr,int index)
{
/*
jvm出了问题,自己打包对象并抛出。
但是它所提供的信息不够给力。想要更清晰,需要自己写。
它的抛出不满足我们的要求。准备自己抛。
*/
if(arr==null)
{
throw new NullPointerException("arr指向的数组不存在");
}


if(index<0 || index>=arr.length)
{
//该条件如果满足,功能已经无法继续运算。这时 就必须结束功能,并将问题告知给调用者。这时就需要通过异常来解决。
//怎么用呢?
//1,创建一个异常对象。封装一些提示信息(自定义)。
//2,需要将这个对象告知给调用者。怎么告知呢?怎么将这个对象传递到调用者处呢?通过关键字throw就可以完成。 throw 异常对象;
//3,throw用在函数内,抛出异常对象,并可以结束函数
throw new ArrayIndexOutOfBoundsException("错误的角标,"+index+"索引在数组中不存在");
}


int element = arr[index];
return element;
}
}




class ExceptionDemo3 
{
public static void main(String[] args) 
{
Demo d = new Demo();
int[] arr = {34,12,67};
int num = d.getElement(null,2);
System.out.println("num="+num);
System.out.println("over");
}
}

class Person
{
private String name;
private int age;
Person(String name,int age)
{
//加入逻辑判断。
if(age<0 || age>200)
{
/*
这样做虽然可以编译并运行看到提示消息,但是问题却没有发生,程序还在继续执行。并打印p对象。
这是不合理的。人对象初始化过程中已经出了问题,为什么要会对人对象操作?
所以应该将问题暴露出来,让使用该程序的调用者知道
所以要使用异常来解决。
*/
// System.out.println("年龄数值错误");
// return;//终止初始化。


throw new IllegalArgumentException(age+",年龄数值非法");
}
this.name = name;
this.age = age;
}
//定义Person对象对应的字符串表现形式。覆盖Object中的toString方法。
public String toString()
{
return "Person[name="+name+",age="+age+"]";
}
}




class ExceptionDemo4 
{
public static void main(String[] args) 
{
Person p = new Person("xiaoming",-20);
System.out.println(p);
}

/*
ExceptionDemo4.java中的异常,不好认,能不能定义一个符合我的程序要求的问题名称。


异常的信息都可以自定义,那么异常的名字是否可以定义呢?是否可以定义成更符合自己程序的阅读呢?


之前的几个异常都是java通过类进行的描述。并将问题封装成对象,这是符合面向对象思想。
其实:异常就是将问题封装成了对象


所以我也准备对自己所需要的问题进行类的描述。




发生编译失败:
ExceptionDemo5.java:43: 错误: 不兼容的类型
                        throw new NoAgeException(age+",年龄数值非法");
                              ^
  需要: Throwable
  找到:    NoAgeException
1 个错误


不兼容,不明白,查阅,提示中说需要Throwable,啥东西?
搜索API。看到Throwable描述。发现。它是异常和错误的超类(父类)
原来它是异常体系的顶层类
Throwable
|--Error
|--Exception




通过阅读:自定义异常被抛出,必须是继承Throwable,或者继承Throwable的子类。
该对象才可以被throw抛出。


原来这个异常体系具备一个特有的特性:可抛性:可以被throw关键字操作


继承选择父类时,更为确切是继承Exception。
但是发现编译又一次失败了。


ExceptionDemo5.java:62: 错误: 未报告的异常错误NoAgeException; 必须对其进行捕获或
声明以便抛出
                        throw new NoAgeException(age+",年龄数值非法");
                        ^
1 个错误


通过这个编译失败提示,发现自定义的异常和之前所使用的异常(空指针异常,角标越界异常,无效参数异常有不同)
抛出哪些异常没有这个失败提示?那么之前的异常和自定义的异常有什么区别呢?
通过查看api的继承体系发现,之前的异常都是Exception下面的RuntimeException子类的子类。
阅读RuntimeException描述中有明确说明,这个运行时异常以及其子类都无需进行声明


可以将自定义的异常继承RuntimeException.


*/
//自定义异常。描述Person的年龄数值非法。
/**
只要是本项目的Person的年龄出现非法值就会发生该异常。
*/
class NoAgeException extends RuntimeException
{
/*
为什么要定义构造函数,因为看到Java中的异常描述类中有提供对问题对象的初始化方法
*/
NoAgeException()
{
super();
}


NoAgeException(String message)
{
super(message);// 如果自定义异常需要异常信息,可以通过调用父类的带有字符串参数的构造函数即可
}
}


class Person
{
private String name;
private int age;
Person(String name,int age)
{
//加入逻辑判断。
if(age<0 || age>200)
{
throw new NoAgeException(age+",年龄数值非法");
}
this.name = name;
this.age = age;
}
//定义Person对象对应的字符串表现形式。覆盖Object中的toString方法。
public String toString()
{
return "Person[name="+name+",age="+age+"]";
}
}

/*
ExceptionDemo5.java中涉及的问题:
1,继承Exception和继承RuntimeExcpetion为什么差距这么大?
2,啥是捕获,啥是声明?






*/


class Demo
{
void show()
{
//如果在函数内抛出Exception//编译失败,因为编译器在检查语法时发生了错误。
/*
该程序已经出现问题,Java认为这个程序本身存在隐患,
需要捕获或者声明出来(你要么把问题处理,要么把问题标识出来让调用知道)
*/
// throw new Exception();


/*
为什么抛出RuntimeException,不需要捕获,不要声明呢?
不是功能本身发生的异常,而是因为比如调用者传递参数错误而导致功能运行失败。
这时也是问题,需要通过异常来体现,但是这个异常不要声明出来的。
声明的目的是为了让调用者进行处理。
不声明的目的是不让调用者进行处理,就是为了让程序停止,让调用者看到现象,并进行代码的修正。★★★★★


原理异常分两种:
1,编译时异常:编译器会检测的异常。
2,运行时异常:编译器不会检测的异常。不需要声明。声明也可以,如果声明了,无外乎就是让调用者给出处理方式。
ArrayIndexOutOfBoundsException
IllegalArgumentException
NullPointerException
ClassCastException




*/
throw new RuntimeException();
}
}


class ExceptionDemo6 
{
public static void main(String[] args) 
{
System.out.println("Hello World!");
}
}


class ExceptionDemo5 
{
public static void main(String[] args) 
{
Person p = new Person("xiaoming",-20);
System.out.println(p);
}
}


}

/*
声明和捕获。


声明:将问题标识出来,报告给调用者。
如果函数内通过throw抛出了编译时异常,而捕获,那么必须通过throws进行声明,让调用者去处理。


捕获:Java中对异常有针对性的语句进行捕获。
语句:
try
{
//需要被检测的语句。
}
catch(异常类 变量)//参数。
{
//异常的处理语句。
}
finally
{
//一定会被执行的语句。
}


*/




class Demo
{
/*
如果定义功能时有问题发生需要报告给调用者。可以通过在函数上使用throws关键字进行声明。


*/
void show(int x)throws Exception
{
if(x>0)
throw new Exception();
else
System.out.println("show run");
}
}




class ExceptionDemo7 
{
public static void main(String[] args)//throws Exception//在调用者上继续声明。 
{
Demo d = new Demo();
try
{
d.show(1);//当调用了声明异常的方法时,必须有处理方式。要么捕获,要么声明
}
catch (Exception ex)//括号中需要定义什么呢?对方抛出的是什么问题,在括号中就定义什么问题的引用。
{
System.out.println("异常发生了");
}
System.out.println("Hello World!");
}
}


class NoAgeException extends RuntimeException
{
/*
为什么要定义构造函数,因为看到Java中的异常描述类中有提供对问题对象的初始化方法。
*/
NoAgeException()
{
super();
}


NoAgeException(String message)
{
super(message);// 如果自定义异常需要异常信息,可以通过调用父类的带有字符串参数的构造函数即可。
}
}


class Person
{
private String name;
private int age;
/*
构造函数到底抛出这个NoAgeException是继承Exception呢?还是继承RuntimeException呢?
继承Exception,必须要throws声明,一声明就告知调用者进行捕获,一旦问题处理了调用者的程序会继续执行。
但是如果使用到了Person对象的数据,导致都失败的。
继承RuntimeExcpetion,不需要throws声明的,这时调用是不可能编写捕获代码的,因为调用根本就不知道有问题。
一旦发生NoAgeException,调用者程序会停掉,并有jvm将信息显示到屏幕,让调用者看到问题,修正代码。哦耶。


*/




Person(String name,int age)//throws NoAgeException
{
//加入逻辑判断。
if(age<0 || age>200)
{
throw new NoAgeException(age+",年龄数值非法");
}
this.name = name;
this.age = age;
}
//定义Person对象对应的字符串表现形式。覆盖Object中的toString方法。
public String toString()
{
return "Person[name="+name+",age="+age+"]";
}
}
class ExceptionDemo8
{
public static void main(String[] args) 
{
// try
// {
Person p = new Person("xiaoming",20);
System.out.println(p);
// }
// catch (NoAgeException ex)
// {
// System.out.println("异常啦");
// }



System.out.println("over");
}
}

/*
描述长方形,
属性:长和宽。
行为:获取面积。


考虑健壮性问题。
万一长和宽的数值非法。
描述问题,将问题封装成对象,用异常的方式来表示。
*/
/*
不知道要继承编译时异常还是运行时异常。


*/
class NoValueException extends RuntimeException
{
NoValueException()
{
super();
}
NoValueException(String message)
{
super(message);
}


}


class Rec
{
private int length;
private int width;
Rec(int length,int width)
{
if(length<=0 ||width<=0)
{
//抛出异常,但是不用声明,不需要调用者处理。就需要一旦问题发生让调用者端停止,让其修改代码。
throw new NoValueException("长或者宽的数值非法");
}
this.length = length;
this.width = width;
}
/**
定义面积函数。
*/
public int getArea()
{
return length*width;
}


}
class  ExceptionTest
{
public static void main(String[] args) 
{


Rec r = new Rec(-3,4);
int area = r.getArea();
System.out.println("area="+area);


}
}


/*
案例二:毕老师用电脑讲课。
两个对象:
老师:
属性:姓名。
行为:讲课。
电脑:
行为:运行。


考虑问题。
1,电脑蓝屏-->异常。


2,电脑冒烟-->异常。


*/
// 可以声明,让调用给出处理方式。
class LanPingException extends Exception
{
LanPingException()
{
super();
}
LanPingException(String message)
{
super(message);
}
}


class MaoYanException extends Exception
{
MaoYanException()
{
super();
}
MaoYanException(String message)
{
super(message);
}
}
/*
讲课中冒烟,问题可以临时解决,是冒烟问题没有直接处理,所以就使用throws声明。
但是发现,这个问题不应该属于讲课的问题。调用讲课方法的调用者是处理不了这个冒烟问题的。
该调用者能处理的应该是冒烟导致的课程进行不下去的问题。
应该在列出一个异常。课时停止异常。


*/
class NoPlanException extends Exception
{
NoPlanException()
{
super();
}
NoPlanException(String message)
{
super(message);
}
}




class NoteBook
{
private int state = 2;
public void run()throws LanPingException,MaoYanException//方法上可以通过throws声明多个异常。
{
System.out.println("笔记本电脑运行");
if(state == 1)
throw new LanPingException("电脑蓝屏了");


if(state == 2)
throw new MaoYanException("电脑冒烟了");
}
public void reset()
{
state = 0;
System.out.println("电脑重启");
}
}
class Teacher
{
private String name;
private NoteBook book;
Teacher(String name)
{
this.name = name;
book = new NoteBook();
}
//讲课。
public void prelect()throws NoPlanException
{
/*
调用到了声明异常的方法,在这里到底是捕获好呢?还是声明好呢?
有具体的捕获处理方式吗?有,那就捕获,没有,那么声明
我可以处理,重启就可以了,重启是电脑的功能。
*/
try
{
book.run();//对于声明多个异常的方法,在处理,需要定义多个catch与之对应。
}

catch (LanPingException e)//LanPingException e = new LanPingException("电脑蓝屏了");
{
//重启。
System.out.println(e.toString());//异常的名称+异常的信息。
// e.printStackTrace();                     JVM中调用的就是这个函数
book.reset();
}
catch(MaoYanException e)//MaoYanException e = new MaoYanException("电脑冒烟了");
{
System.out.println(e.toString());
test();
//冒烟问题没有解决,继续声明throws出去。
// throw e;
// new 电脑维修部(book);//去修电脑。
// book = new NoteBook();
throw new NoPlanException(e.getMessage()+",课时停止");//异常转换。
    /*异常转换:当解决不了主方法时,可以将其转换成调用者可以理解的问题*/



}
System.out.println(name+"....讲课");
}
//留练习。
public void test()
{
System.out.println("做练习");
}
}


class ExceptionTest2 
{
public static void main(String[] args) 
{
Teacher t = new Teacher("毕老师");
try
{
t.prelect();
}
catch (NoPlanException e)
{
System.out.println(e.toString());
System.out.println("换老师");
}

System.out.println("Hello World!");
}
}

【总结】
异常:
1,异常:java中运行时出现的问题。
问题有两种:★★★★
异常:可以处理的。
错误:不用处理的,为啥?因为是系统底层发生。必须修改代码。
异常的发生的底层过程。


2,异常的应用:数组角标越界异常的手动抛出。
为了增加程序的健壮性。
功能通过return正常结束,如果问题发生导致了功能无法运算,需要通过throw来结束功能。




3,自定义异常。重点看ExceptionDemo5.java(遇到问题解决问题的思路) .★★★★★
3.1 为什么要自定义异常?
3.2 自定义异常到底该继承谁?
3.3 Exception和RuntimeException的区别?
编译时异常,运行时异常。
3.4 这两个异常到底什么时候用?
问题发生时,需要调用者给出具体的处理方式吗?
需要,编译时异常。
不需要,运行时异常。
4, 异常的声明和捕获。★★★★★
声明:throws。
到底是否需要声明呢?通过调用者是否需要给出处理方式而定。
捕获:try catch finally  catch才是真正的处理的异常的部分。没catch就没处理。


声明和捕获到底用哪个呢?
功能中如果可以解决问题用捕获,解决不了用声明。

5,异常的部分细节:★★★★★★★
1,一个功能可以声明多个异常。
2,对于多个异常声明,必须对应多个catch针对性处理。
3,catch中处理不了的异常可以继续抛出,也可以转换抛出。


6,throw和throws的区别?

/*
throw和throws的区别?


1,throw用在函数内。
throws用在函数上。
2,thorw抛出的是异常对象。
throws用于进行异常类的声明,后面异常类可以有多个,用逗号隔开。






*/






0 0
原创粉丝点击