java中的异常

异常

:Java 运行时期发生的问题就是异常。

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

异常

:通常发生可以有针对性的处理方式的

错误

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

class ExceptionDemo
{
    public static void main(String[] args)
    {
        int [] arr =new int[4];
        int [] arr1 =new int[100000000000000];//ExceptionDemo.java:7: 错误: 过大的整数: 100000000000000
        System.out.println(arr[0]);
        System.out.println(arr[3]);//发生了ArrayIndexOutOfBoundsException,数组角标越界,导致程序无法执行,程序结束。

    }
}

ArrayIndexOutOfBoundsException浅析


没有找到4这个角标,运行时发生了问题,这个问题jvm认识,这个问题jvm本身有描述:
描述内容:问题的名称,问题的内容,问题的发生位置
既然有这么多的信息,java就将这些信息直接封装到对象中->ArrayIndexOutOfBoundsException
jvm需要将问题抛给调用者main,main函数就接收到越界异常对象,没有处理main函数就会继续抛出调用者jvm。
jvm收到问题后,就会做出最终的处理凡是,将问题对象中的名称,信息,问题的位置,都会显示在屏幕上,让软件使用者知道,同时让程序提前终结。

异常的应用

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

class Demo

{

    /* 
        对给定的数组通过给定的角标获取元素。
    */
    int getElement(int[] arr,int index)
    {
        /*
            jvm除了问题,自己打包对象并抛出。
            但是它提供得信息不够给力,想要更清晰,想要自己写。
            它的抛出不满足我们的要求,准备自己抛。
        */
        if(arr==null)
        {
            throw new NullPointerException("arr指向的数组不存在");
        }
        if(index<0||index>=arr.length)
        {
            //该条件如果满足,功能已经无法继续运算。
            //这时就必须结束功能,并将问题告知调用者,这时就需要通过异常来解决。
            //1,创建一个异常对象,封装一些提供信息(自定义)。
            //2,需要将这个对象告知给调用者,怎么告知呢,怎么将这个镀锡传递个给调用者处呢?
            //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={12,34,45};
        int num=d.getElement(arr,4);
        System.out.println("num ="+num);
    }
}
class Person
{
    private String name;
    private int age;
    Person(String name,int age)
    {
        if(age<0||age>200)
        {
            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",-12);
        System.out.println(p);
    }
}

自定义异常的信息

,那么异常的名字是否可以定义呢?是否可以定义更符合自己程序的阅读呢?
之前的几个异常都是java通过类进行类进行的描述,并将问题封装成对象,这是符合面向对象的思想。
其实,异常就是将问题封装成对象。
所以我也准备将自己所需要的问题进行类的描述。

发生编译失败:
ExceptionDemo5.java:28: 错误: 不兼容的类型: NoAgeException无法转换为Throwable
throw new NoAgeException(age+”,年龄数值非法”);
^
1 个错误
需要Throwable,查阅API,知道Throwable是异常和错误的超类。
原来它是异常体系的顶层类。
Throwable
|–Error
|–Exception
了解到,自定义异常被抛出,必须要继承Throwable,或者继承Throwable的子类
该对象才可以被throw抛出。
原来这个异常体系具有一个特有的特性,可抛性,可以被throw关键字操作。

继承选择父类时,更为确切得是继承Exception。
但是还是编译失败。错误如下:
ExceptionDemo5.java:43: 错误: 未报告的异常错误NoAgeException; 必须对其进行捕获或声明以便抛出
throw new NoAgeException(age+”,年龄数值非法”);
^
1 个错误

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

//自定义异常,描述Person的年龄数值非法。
/*
只要时本项目的Person的年龄出现非法值就会发生该异常
 */
class NoAgeException extends RuntimeException
{
    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+"]";
    }
}
class ExceptionDemo5
{
    public static void main(String[] args)
    {
        Person p=new Person("xiaoming",-12);
        System.out.println(p);
    }
}

ExceptionDemo5.java中涉及的问题:

1,继承Exception和继承RuntimeException的区别?

2,什么是捕获,什么是声明?

class Demo
{
    void show()
    {
        //如果在函数内抛出Exception,编译失败,因为编译器在检查语法时发生了错误。
        /*
            该程序中已经出现问题,Java认为这个程序本身存在隐患。
            需要捕获或者声明出来(要么把问题处理,要把问题标识出来让调用者知道)
        */
//      throw new Exception();
        /*
        为什么抛出RuntimeException,不需要捕获,不要声明呢?
        不是功能本身发生的异常,而是因为比如调用者传递参数错误而导致功能运行失败。
        这时也是问题,需要通过异常来体现,但是这个异常不要声明出来的。
        声明的目的是为了让调用者进行处理。
        不声明的目的是不让调用者进行处理,就是为了让程序停止,让调用者看到现象,并进行代码的修正。

        原理异常两种:
        1,编译时异常,编译器会检测的异常。
        2,运行时异常,编译器不会检测的异常,不需要声明,声明也可以,就是让调用者给出处理方式
        ArrayIndexOutOfBoundsException
        IllegalArgumentException
        ClassCastException
        NullPointerException
        */
        throw new RuntimeException();
    }
}

声明和捕获

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

捕获:Java中对异常有针对性的语句进行捕获。
语句:

try

{
//需要被检测的语句
}

catch(异常类 变量)

{
//异常的处理语句。
}

finally

{
//一定会被执行的语句。
}

class Demo
{
    /*
    如果定义功能时有问题发生需要报告给调用者,可以通过在函数上使用throws关键字
    */
    void show()throws Exception
    {
        throw new Exception();
    }
}

class ExceptionDemo7
{
    public static void main(String[] args)//throws Exception//在调用者上继续声明。
    {
        Demo d=new Demo();
        try{
            d.show();//当调用了声明异常方法时,必须有处理方式,要么捕获,要么声明。
        }
        catch(Exception e)//括号中需要定义什么呢?对方抛出的是什么问题,在括号中就定义了什么问题的引用
        {
            System.out.println("异常发生了");
        }
        System.out.println("over");
    }
}
class NoAgeException extends RuntimeException
{
    NoAgeException()
    {
        super();
    }
    NoAgeException(String message)
    {
        super(message);//如果自定义异常需要异常信息,可以通过调用父类的带有字符串参数的构造函数即可。
    }
}
class Person
{
    private String name;
    private int age;
    /*
        构造函数到底是抛出这个NoAgeException是继承Exception呢?还是继承RuntimeException呢?
        继承Exception,必须要throws声明,一声明就告知调用者进行捕获,一旦问题处理了调用者的程序会继续执行。
        但是如果使用到了Person对象的数据,导致都是失败的。
        继承RuntimeException,不虚要throws声明的,这时调用是不可能编写捕获代码的,因为调用根本就不知道有问题
        一旦发生NoAgeException,调用者程序会停掉,并将jvm将信息显示到屏幕,让调用者看到问题,修正代码。
    */
    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+"]";
    }
}
class ExceptionDemo8
{
    public static void main(String[] args)
    {
        try
        {
            Person p=new Person("xiaoming",-12);
            System.out.println(p);
        }
        catch(NoAgeException e)
        {
            System.out.println("异常了");
        }
        System.out.println("over");
    }
}

需求:有一些特定的代码块无论异常是否发生,都需要执行。
因为异常会引发程序跳转,导致有些语句执行不到,无法满足这个需求。
异常捕获处理时java提供解决方案。
try catch finally
finally 就是解决这个问题,这个代码块中存放的代码都是一定会被执行的。

应用场景

定义一个功能往数据库中添加数据。

 void add(Data data)
 {
    1,连接数据库。
    try{
    2,添加数据。//添加数据时发生了异常情况,throw new SQLException();程序跳转。
            //而断开连接必须要执行,应为不执行,连接资源在浪费。
            //无论是否发生问题,都要执行断开连接的动作,从而释放资源。

        }catch(SQLException)
            {
            //解决数据库的问题。
            //同时将问题告诉调用者。
            throw new NoAddException();
        }
        finally{
            3,断开连接。
        }
  }

总结
finally的使用场景.
只要程序中使用了具体的资源(数据库资源,IO资源,网络连接socket等)需要释放,都必须定义在finally中,你在定义程序,只要问题发生与否,指定程序都需要执行时,就定义在finally中。

class NoShowException extends Exception
{
    NoShowException(String message)
    {
        super(message);
    }
}
class Demo
{
    void show(int num)throws NoShowException
    {
        if(num<0)
            throw new Exception(num+",数值非法");
        System.out.println("show..."+num);
    }
}
class ExceptionDemo9
{
    public static void main(String[] args)
    {
        Demo d=new Demo();
        try{
            d.show(5);

        }catch(NoShowException e)
        {
            System.out.println(e.toString());//打印的是异常名称+异常信息。
            //如果异常发生,处理完毕后,希望功能结束。
            //return;

            //注意:有一种情况发生,finally也不会执行。
            System.exit(0); //退出jvm.
        }
        finally
        {
            System.out.println("hello...");
        }
        System.out.println("over");
    }

    Test t=new Test();
    int num=t.show(-4);
    System.out.println("num"+num);
}



class Test 
{
    int show()
    {
        try{
            if(true)
                throw new Exception() ;
            return 4;
        }catch(Exception e)
        {
            System.out.println(e.toString);
            return 200;
        }
        finally{
            System.out.println("finally ...");
            return 100;
        }
    }
}

try catch finally 组合方式


1,

try catch

:对代码进行异常检测,并对检测的异常传递给catch处理。
异常捕获处理。

    void show()//不需要throws
    {
        try{
            throw new Exception();
        }catch(Exception e){

        }
    }   

2,

try finally

:对代码进行异常检测,检测到异常后因为没有catch,所以一样会被默认jvm抛出。
异常是没有捕获处理的。但是功能所开启的资源需要进行关闭,所有finally,只为关闭资源。

    void show()//需要throws
    {
        try{
            throw new Exception();
        }finally{

        }
    }

3,

try catch finally

检测异常,并传递给catch处理,并定于释放资源。

4,

try catch1 catch2 catch3

……

异常在继承或者实现中使用细节


1,子类覆盖父类方法时,如果父类的方法声明异常,子类只能声明父类异常或者该异常的子类,或者不声明
2,当父类方法声明多个异常子类覆盖时只能声明多个异常的子集
3,当覆盖的方法没有异常声明时,子类覆盖时是无法声明异常的
举例:父类存在这种情况,接口也有这种情况,
问题:接口中没有声明异常,而实现的子类覆盖方法时发生了异常,怎么办?
无进行throws声明,只能catch的捕获,万一问题处理不来呢?
catch中继续throw抛出,但是,只能将异常转换成RuntimeException子类抛出。

Interface Inter 
{
    public void show();
}
class Demo implement Inter
{
    public void show()
    {
        try{
            throw new Exception();
        }catch(Exception e)
        {
            code...;
            throw new RuntimeException("");//告知调用者,问题所在。
        }
    }
}

Test1

/*
案例一:
描述一个长方形。  
*/
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("wrong value");
        }
        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);
    }
}

Test2

/* 
案例二:毕老师用电脑讲课。
两个对象:
    老师:
        属性:name
        行为:讲课
    电脑:
        行为:运行。
考虑问题。
1,电脑蓝屏-->异常

2,电脑冒烟-->异常
*/
//可以声明,让调用者给出处理方式。
class LpException extends Exception
{
    LpException()
    {
        super();
    }
    LpException(String message)
    {
        super(message);
    }
}
class MyException extends Exception
{
    MyException()
    {
        super();
    }
    MyException(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 LpException,MyException//方法上可以通过throws声明多个异常
    {
        if(state==1)
            throw new LpException("电脑蓝屏了");

        if(state==2)
            throw new MyException("电脑冒烟了");
        System.out.println("笔记本电脑运行");
    }   
    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(LpException e)//LpException e=new LpException("电脑蓝屏了");
        {
            //重启
            System.out.println(e.toString());//异常的名称+异常的信息。
            //e.printStackTrace();
            book.reset();
        }
        catch(MyException e)
        {
            System.out.println(e.toString());
            test();
            //冒烟问题没有解决,继续声明throws出去。
            // throw e;
            throw new NoPlanException("课时停止"); //异常转换。
        }
        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("over");

    }
}


/*
throw和throws的区别?

1,throw用在函数内。
    throws用在函数上。


2,throw抛出的是异常的对象。
    throws是用于进行异常类的声明,后面异常类可以有多个,用逗号隔开。
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java异常机制是一种用于处理程序执行期间可能出现的错误情况的机制。Java异常分为两类:受检异常(Checked Exception)和非受检异常(Unchecked Exception)。其,受检异常必须在代码进行捕获和处理,否则编译器将会报错。而非受检异常则不需要在代码进行捕获和处理,但是如果不进行处理,会导致程序的异常终止。 Java异常机制通过抛出异常对象来表示程序出现的异常情况,通常情况下,异常对象包含了异常的类型、异常的消息以及异常发生的位置等信息。当程序执行过程出现异常情况时,就会抛出相应的异常对象,这个异常对象会被传递给调用栈上的上层方法,直到被捕获或者到达程序的顶层方法。 Java异常机制主要由三个关键字来实现:try、catch和finally。try块包含可能抛出异常的代码,catch块用于捕获并处理异常,finally块则用于执行一些必须要完成的代码,无论是否抛出异常都会执行。 下面是一个简单的Java异常处理的例子: ``` public class ExceptionDemo { public static void main(String[] args) { try { int num = Integer.parseInt(args[0]); System.out.println("10 / " + num + " = " + (10 / num)); } catch (ArithmeticException e) { System.out.println("除数不能为0"); } catch (NumberFormatException e) { System.out.println("请输入数字"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("请至少输入一个参数"); } finally { System.out.println("程序执行完毕"); } } } ``` 在这个例子,我们使用了try-catch-finally关键字来处理用户输入的参数,当输入参数不满足条件时,就会抛出相应的异常。catch块用于捕获并处理异常,finally块则用于执行一些必须要完成的代码,无论是否抛出异常都会执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值