异常:
异常的体系:
|--Throwable:
|--Error:(大问题)通常出现重大问题如:运行的类不存在
或者内存溢出等。不编写针对代码对其处理
|--Exception:(小问题)运行时出错
|--Exception():无参构造器
|--Exception(String msg):带有消息文本的构造器
|--Exception(Throwable cause):带有起因的构造器
|--Exception(String msg, Throwable cause):有消息文本,也有起因的构造器。
异常体系的特点:
异常体系中的所有类,以及建立的对象都具备可抛性,也即是说可以被throw和throws关键字
操作,也只有异常体系具备这个特点
异常处理机制:
Java的异常处理机制可以让程序具有极好的容错性,让程序更加健壮。当程序运行出现意外情况时,
系统会自动生成一个Exception对象来通知程序,从而实现将"业务功能实现代码"和"错误处理代码"
分离,提供更好的可读性。
异常类方法介绍:
|--String getMessage(),获取异常信息,返回字符串
|--String toString(),获取异常类名和异常信息,返回字符串。
|--void printStackTrace(),获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
异常的分类:
|--编译时异常
该异常在编译时期,如果没有处理,编译失败。该异常被标识,代表可以被处理
|--运行时异常
在编译时不需要处理,编译器不检查。该异常的发生,建议不处理,让程序停止,需要对代码进行修正
异常的处理:
1:使用throws声明异常:
当方法不知道如何处理这种类型的异常,该异常应该由上一级调用者处理;如果main方法也不知道
如何处理这种异常,也可以使用throws声明抛出异常,该异常将交给JVM处理。JVM对异常的处理方
法是:打印异常跟踪栈信息,并终止程序。throws可以声明多个异常类,多个异常类之间以逗号隔
开。throws声明抛出的语法如下:
|--[修饰符] [返回值类型] [方法名] throws XXException, XXXException...{}
代码示例:
public class ThrowsTest{
public static void main(String[] args) throws IOException
{
FileInputStream fis = new FileInputStream("b.java");
}
}
上面程序使用了throws声明抛出IOException异常,一旦使用throws声明抛出异常,程序无需使用
try...catch来捕获异常。
使用throw抛出异常:
如果程序中的数据、执行与既定的业务需求不符而产生的异常,必须由程序员来决定抛出,系统无法
抛出这种异常。则应该使用throw语句,throw语句可以单独使用,它抛出的不是异常类,而是异常类
的实例,而且每次只能抛一个异常实例。格式如下:
|--throw new 异常类("描述信息");
代码示例:
/*
需求:求两个数的和,当一个数小于等于0的时候,抛出异常
*/
public class Deom{
public static void main(String[] args)
{
int sum = sum(-2, 3);
System.out.println(sum);
}
public static int sum(int a, int b)
{
if(a <= 0 || b <= 0)
throw new RuntimeException("出现负数");
return a + b;
}
}
throw和throws的区别:
|--throws:
声明,使用在函数()和{}之间,后面跟着异常类,可以有多个,逗号隔开
|--throw:
抛出,使用在函数内,后面跟着异常类对象
2:使用try...catch捕获异常
格式一:
try {
//需要被检查的代码
} catch()
{
//处理异常的代码(处理方式)
}
try块是监控区,在try中出现的异常会被捕获,然后送到catch之后,与catch所处理的异常类型进行比较,
如果匹配,那么就把异常对象交给catch了,然后调用catch块。注意,在try块中,出现了异常后,
在出现异常的位置直接跳转到catch中,而try后面的语句就不会在执行了。
格式二:
try{
//需要被检查的代码
}finally
{
//一定会执行的语句
}
格式三:
try
{
//需要被检查的代码
}catch(异常类 变量名)
{
//处理异常的代码(处理方式)
}finally
{
//一定会执行的语句
}
如果try中没有抛出异常,那么不会执行catch,但无论有无异常都会执行finally
如果try有异常,那么会执行catch,但有异常,也会执行finally
如果在finally之前有返回语句(return和抛出异常语句),那么会在返回之前先执行finally,然后再继续返回
|--示例代码:
public class Test7 {
public static void main(String[] args) {
int x = fun();
System.out.println("最終x的值是,x = " + x); //打印的值是6
}
@SuppressWarnings("finally")
public static int fun(){
int x = 0;
try{
//
x = 6;
return x;
}finally{
x = 10;
//将x的值输出,测试return是在finally执行后才返回
System.out.println("finally中的x執行了,x = " + x);//打印的值是10
}
}
}
|--finally中放什么样的代码
通常我们会用来断开外部资源绑定。例如我们的程序绑定了一个磁盘上的文件,
如果在方法返回之前,可以断开,那么就应该把断开的语句放到finally中,
这样可以保证断开的语句总是执行。
|--finally中不会执行的情况
finally遇见了System.exit(0)时,就不会再执行了。因为System.exit(0)会把JVM停止了。
使用try...catch处理异常注意事项:
在方法内部把异常处理掉,外界不知道内部的问题,也不会让调用者出现异常。
当声明多个异常,就对应要有几个catch块,父类的catch块要放到最后,catch内
需要定义针对性的处理方式,不要简单定义printStackTrace。当捕获的异常,本功能处理
不了时,可以继续在catch中抛出,如果该异常处理不了,但并不属于该功能出现的异常,
可以将异常转换后抛出
|--代码示例:
public class Teacher {
private String name;
private Computer cmpt;
public Teacher(){}
public Teacher(String name)
{
this.name = name;
cmpt = new Computer();
}
public void prelect() throws TeacherException
{
try {
cmpt.run();
} catch (LanPinException e) {
cmpt.reset();
} catch (MaoYanException e) {
practice();
//将异常转换抛出
throw new TeacherException("课时计划无法完成" + e.getMessage());
//System.out.println("");throw单独存在的时候,后面不能有语句
}
System.out.println("开始上课了");
}
public void practice()
{
System.out.println("做练习");
}
}
public class Computer {
private int state = 3;
public void run() throws LanPinException, MaoYanException
{
/*
通过改变状态值,来测试效果
*/
if(state == 2)
throw new LanPinException("蓝屏了");
if(state == 3)
throw new MaoYanException("冒烟了");
System.out.println("电脑运行了");
}
public void reset()
{
state = 1;
System.out.println("电脑重启");
}
}
/*
自定义异常类
*/
public class LanPinException extends Exception {
public LanPinException(String msg)
{
super(msg);
}
}
/*
自定义异常类
*/
public class MaoYanException extends Exception {
public MaoYanException(String msg)
{
super(msg);
}
}
/*
自定义异常类
*/
public class TeacherException extends Exception{
public TeacherException(){}
public TeacherException(String msg)
{
super(msg);
}
}
public class Test {
public static void main(String[] args) {
Teacher t = new Teacher("老师");
try {
t.prelect();
} catch (TeacherException e) {
System.out.println(e.toString());
System.out.println("换老师或者放假");
}
}
}
自定义异常:继承Exception和RuntimeException
因为项目中出现特有的问题,而这些问题本没有被java所描述,所以对于可以按照java的
封装思想,将特有问题进行自定义封装
|--如何进行自定义异常呢?
因为父类中已经将异常信息的操作做完了,所以子类只需在构造函数中 通过super()
把异常信息传递给父类进行初始化,子类就可以直接调用父类中的getMessage()获取
自定义的异常信息
|--继承Exception的原因:
异常体系有一个特点,异常类和异常对象都被抛出,他们都具有可抛性。
这个可抛性是Throwable体系中的独有特点,只有这个体系中的类和对象
才可以被throw和throws操作
代码示例:
public class Test {
public static void main(String[] arg)
{
try
{
DemoException d = new DemoException();
int result = d.result(5, -2);
System.out.println(result);
}
catch(FuShuException e)
{
System.out.println(e.toString());
System.out.println("出现负数了,值是:" + e.getValue());
}
System.out.println("over");
}
}
class DemoException
{
public int result(int a, int b)throws FuShuException //方法外部throws关键字声明有可能出问题
{
if(b < 0)
{
throw new FuShuException("被除数出现负数",b); //方法内部throw关键字抛出异常
}
return a/b;
}
}
class FuShuException extends Exception
{
private int value;
FuShuException(){}
FuShuException(String msg,int value)
{
super(msg);
this.value = value;
}
public int getValue()
{
return value;
}
}
RuntimeException:
Exception中有一个特殊的子类异常,RuntimeException,叫做运行时异常。
如果在函数内throw(抛出)该异常对象,无需在函数上throws(声明)该异常类;
如果在函数上声明该异常类,调用者无需处理。编译都通过。
代码示例一:
class Demo{
int div(int a, int b) //此处没有做任何操作,编译通过
{
if(b == 0)
throw new ArithmeticException("被0除了");
return a/b;
}
}
class ExceptionDemo{
public static void main(String[] args)
{
Demo d = new Demo();
int x = d.div(3,0);
System.out.println("x=" + x);
System.out.println("over");
}
}
代码示例二:
class Demo{
int div(int a, int b) throws ArithmeticException
{
return a/b;
}
}
class ExceptionDemo{
public static void main(String[] args) //此处没有申明异常,编译通过了
{
Demo d = new Demo();
int x = d.div(3,0);
System.out.println("x=" + x);
System.out.println("over");
}
}
上述程序之所以不用在函数进行申明,是因为不需要调用者处理。当该异常发生,希望
程序停止。因为在运行时出现了无法继续运算的情况,希望停止程序后对代码进行修正。
因此,自定义异常时,如果该异常的产生,无法再继续进行运算,就让自定义异常继承RuntimeException
|--代码示例:
public class Test {
public static void main(String[] arg)
{
try
{
DemoException d = new DemoException();
int result = d.result(5, -2);
System.out.println(result);
}
catch(FuShuException e)
{
System.out.println(e.toString());
System.out.println("出现负数了,值是:" + e.getValue());
}
System.out.println("over");
}
}
class DemoException
{
public int result(int a, int b) //不需要作处理
{
if(b < 0)
{
throw new FuShuException("被除数出现负数",b); //方法内部throw关键字抛出异常
}
return a/b;
}
}
class FuShuException extends RuntimeException //继承RuntimeException
{
private int value;
FuShuException(){}
FuShuException(String msg,int value)
{
super(msg);
this.value = value;
}
public int getValue()
{
return value;
}
}
异常在子父类中覆盖的体现:
1:子类在重写父类中的方法时,如果父类方法抛出异常,子类中重写的方法,
只能抛出父类的异常或者该异常的子类异常
|--举例说明:
class AException extends Exception{}
class BException extends AException{}
class CException extends Exception{}
class Fu{
void show() throws AException
{
}
}
class Zi{
/*
只能抛AException或者AException的子类异常BException
不能抛CException
*/
void show()throws AException//
{
}
}
2:如果父类方法抛出多个异常,那么子类再覆盖该方法时,只能抛出父类异常的子集
3:如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常
如果子类方法发生了异常,就必须要进行try处理,绝对不能抛
常见的异常:
1 OutOfMemoryError(内存溢出错误)
堆内存溢出
方法区溢出
2 StackOverflowError(调用栈溢出错误)
递归调用出了问题。
通常递归调用,都要有出口,而没有出口就会出现这个StackOverflowError错误!
3 NoSuchMethodError(没有这个方法错误)
原来有这个方法,所以依赖这个方法的类就编译通过了,但后来这个方法没了,那么原来依赖它的类只要运行就会出现这个错误。
4 NoClassDefFoundError(没有找到类错误)
原来依赖的类,现在已经不存在了,就会出现这个异常。
5 ArithmeticException(算术异常)
整数除以0
6 ArrayIndexOutOfBoundsException(数组下标越界异常)
通常我们也不会越界,但只要一使用循环,就不好控制。
7 ClassCastException
错误的强转!
Person p = new Person();
Student s = (Student)p;
8 IllegalArgumentException
非法参数异常!public void run(int f) {//参数表示方向,前1、后2、左3、右4
if(f < 0 || f > 4) {throw new IllegalArgumentException();}
}
public void setAge(int age) {
}
9 NullPointerException
Person p = null;//没有实例化
p.getName();//出现空指针异常