Java基础day10笔记:异常(finally)|异常处理语句的几种格式|覆盖时的异常特点

    01-面向对象(异常-finally)

        还是以之前那个程序为例。我们回想起来,以前在进行异常处理的时候,除了try、catch,是不是还有一部分叫finally呀?

        我们把finally也加进去。 

        finally中存放的是一定会被执行的代码。

        测试了两次,一次是传错误的值,发生异常的情况;一次是传正确的值,没有异常的情况,发现finally都执行到啦:

         那么,有一个问题,程序发生异常了,这两句话都会执行到:

        那这两句话有什么区别吗?

        我们来做一个小测试,在程序发生异常的时候,我们希望程序在这里结束,不要往下执行了, 加一句return语句:

        运行结果是这样的:

        我们发现,"over"没有执行,而“finally”依然执行了。return代表着结束这个主函数,而“over”是主函数中的语句,所以没有被执行。

        既然finally始终都会被执行到,那么它存在的意义是什么呢?

        我们来用一个实际需求来说明它存在的作用。

        我们写程序,去连接数据库。数据库里存储了n多的数据,我们从主机发一个请求到服务器里面去,首先要做的是不是连接呀?

        连接好之后,使用完服务器里的数据,我们要及时断开。因为服务器的连接数是有限的,就像CPU的处理能力是有限的一样,如果我们始终和它连接着不断开,会耗费服务器的资源,占用服务器的连接,害其他想使用服务器的宝宝不能及时连接上。

        注意哦,不论是否成功取到服务器中的数据,我们结束后都要及时断开哦!

        对数据库的使用需要经历这三个过程:

        但是在第二步的时候,可能会出现一些异常,比如要删除的数据不存在啦、要添加的数据不符合规则啦这种奇奇怪怪的情况。出现异常之后,程序会结束掉,但是作为一个文明有爱的宝宝,我们关闭数据库的操作也要正常进行呢!

        这个时候就需要用到finally啦,我们这样来写(只写了大意,省略了一些内容):

        因此,finally灰常重要!

        在写到关于异常的处理,如果没有做finally的处理,没有进行资源的关闭,这个程序就是有问题的,面试官会因此认为你缺乏编程经验。后果好严重呀。

        finally代码块:定义一定执行的代码。

        通常用于关闭资源。

        资源一定要关闭掉,否则它的运行压力会非常大。

        再说说这个异常,我们可以把它抛出去吗?

        我们来思考一下:你在调用我的功能往数据库里面存数据,(也就是我在操作数据库,你只要调用我就行啦)。你把数据给我,我把结果给你就OK。这个时候数据库发生问题了,我把问题抛给你,你能解决吗?

        你是调用我的人,你把数据给我了,我来操作数据库,现在数据库发生问题了,我把数据库异常抛给了你,这不合适呀。因为你只是拿数据的人,你根本不懂怎么操作数据库,我却把我的问题丢给了你,我很坏坏!所以这样不好的!

        这样做的问题:

        1,我打破了我这个程序的封装性,暴露出了它的内容到别人那里去。

        2,我把我的问题丢给了你,而你不会解决。

        所以,还是负责操作数据库的我,来对数据库异常进行处理,这才是最好的安排。

        这样来写:

        先处理数据库异常,将数据库异常处理完之后,再向外抛一个异常,并把这个异常标识到方法上:

        而你在调用我的方法的时候,数据库异常你处理不了,但是这个异常就要交由你来处理啦。(数据库异常你处理不了是正常的,但是添加的数据不符合规则等等,这种问题,就是你可以处理的啦)

        所以开发是要分层次的,模块化的开发,我就负责处理数据库的功能,你就负责数据的部分(数据的获取、返回之类的),将数据获取到,校验就是你的事,最终你是不是把数据要给我,我把它放到数据库里面去,或者说,你需要什么数据跟我说,我去数据库里面帮你找。

        举个例子帮助理解哦:

        仓库管理员和销售员。销售需要一批货,卖出去,难道需要销售亲自去仓库里面取货吗?如果这样做,过程就会很繁琐。所以将销售和仓库分开,销售来面向客户,需要什么货,让仓库管理员去取,仓库管理员是面向仓库的。

        现在,销售需要10箱货,叫仓库管理员去取货。仓库管理员到仓库之后发现,昨天下大雨,仓库漏水了,把货全都淹了,货不能用了。这个时候,仓库管理员需要跟销售说“仓库漏水了,怎么办呀?”吗?不需要的。仓库内部的事情,由仓库管理员来处理。漏水的问题需要仓库管理员来处理,这不是销售可以处理的事,他只需要告诉销售“没有货哦。”就可以啦。

        就像上面这两句话:我们先对仓库的异常问题进行处理,然后将问题报出去。但是不需要将本层的问题报出去,只报一个对方可以识别的问题就可以了。

        这就叫做问题的封装。有些问题我们需要内部进行处理,处理完之后,我们告诉对方处理的结果就好了。至于原因,愿意说就说,不愿意说就算啦。

        那这样可以吗:

        仓库管理员把仓库修好了,但是没有告诉销售没有货。销售既没有拿到货,也不知道发生了什么,没有收到任何消息。

        这个问题是有关联性的,仓库管理员却没有将关联性的信息提供出去。

        所以不可以这样的,这两句话的内容都要做到哦。

    02-面向对象(异常-处理语句其他格式)

        异常处理语句的几种格式:

        使用的时候择其一就好啦。

        说一个小问题:

        这样编译能通过吗?

        不能哦。因为在函数内抛,函数上要标识呢。

        那这样写编译可以通过吗:

        能。因为问题在内部可以解决了,外部就不知道了。原则是:只要问题可以被解决,问题就可以不声明。问题没有被解决,就要声明在函数上。

        什么叫问题可以解决了?有catch就叫问题可以解决了~(catch真好~)

        再来,抛一个e,编译能通过吗?

        不能。

        因为抓住了一个问题,又抛了一个问题。

        那这样呢,能通过吗?

        能哦。因为它在catch中,只要被处理了就行。

        接着再看,这样可以编译通过吗:

        问题被处理了吗?没有catch就没有被处理。没处理的话,就要在函数上标识异常。这里并没有标识出去,所以不能编译通过。

        那这里写finally有什么用呢?

        注意,在这个功能内部,有可能会访问到一些其他资源,但是这个资源产生一些问题,并不在这个资源中处理。但是,我还是要关资源。产生不产生问题不管它,资源都要关掉。产生问题呢,丢给调用者去处理,这个功能不管,但是资源要先关掉,因为对方获取到这个问题之后,他有可能也不会关资源。所以,try和finally是可以在一起的,finally可以用于关闭资源(或者说一定会执行的代码)。

        如果在一个功能当中,定义了一些必须要执行的代码。那么就可以用try-finally的形式,将一定要执行的代码放在finally当中。

        记住一点:catch是用于处理异常。如果没有catch就代表异常没有被处理过,如果该异常是检测时异常,那么必须声明。

    03-面向对象(异常-覆盖时的异常特点)

        注意哦,异常声明的时候是不是声明在函数上呀?而函数有一个特性就叫做覆盖。

        那么,异常在子父类覆盖中的体现是什么样呢?

        异常在子父类中覆盖中的体现:

        1,子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。

        举例:

        B异常是A异常的子类。

        这是为什么呢?父类已经有问题了,子类在继承父类的时候,不能比父类还有问题,只能说是和父类一样的问题,或者是父类问题的子问题。

        我们用一个例子来说明:

        我们定义了一个Test类,其中有一个function方法,它的function方法接收了Fu类的引用,调用了Fu类的show方法。

        function调用的是一个抛出异常的方法,是不是要么抛要么try呀?

        我们先try一下:

        然后在主函数中创建Test对象,调用function方法就好啦。

        过了一段时间,来了一个Zi类,写了一个show方法把父类Fu的这个方法覆盖掉了,他抛出的是C异常。

        我们现在调用function的时候给里面传new Zi()(属于多态)。

        传了new Zi()之后会发生什么现象呢?

        Test类中的f.show()运行的将是Zi类的show方法,而Zi类的show方法抛出的是C异常,它能够处理吗?

        不能处理。这就叫做,早期的程序,不能处理后续产生的新异常。

        所以,不可以让子类抛新异常,只能够抛可以处理的异常。

        如果,Zi类在覆盖Fu类的show方法之后,真的发生了C异常,就必须在内部处理,不能抛哦!

        2,如果父类方法抛出多个异常,子类在覆盖该方法时,只能抛出父类异常的子集。

        3,如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类方法发生了异常,就必须要进行try处理,绝对不能抛。

    04-面向对象(异常-练习)

        问题描述:

        先要对这个程序进行基本设计。

        这个面积功能我们该如何定义呢?我们发现,可以把面积功能先提取出来,这个面积呢,我们可以视为图形当中的拓展功能。(图形可以画出来,但不一定需要求面积,所以是拓展功能)

        那么,我们可以把它定义成接口。

        接口Shape:

        长方形Rec类:

        创建Rec对象,并调用getArea方法。

        我们传入了负数值,这显然不合常理:

        该怎么解决呢?

        以前还比较青葱的我们会这样干:

        这么做很笨笨哒~

        为什么说这么做很笨笨,编译运行:

        这样有意义吗?

        没有,而且它是错的。按理说,传了-3和4,这个长方形就不应该存在,更别说调用面积了,所以r.getArea()方法是不应该运算的,这才是对的。

        刚刚那种笨笨方法,叫做正常流程代码和问题处理代码结合得非常紧密,阅读性比较差。而且,当发生错误之后,处理方法不仅仅是一个简单的输出语句,而是一大堆处理方法,也就是会有一大堆代码来处理这些问题。当这些代码都集中在一起的时候,阅读起来会非常痛苦。

        那么怎么办呢?

        我们可以只保留正常流程的代码,当异常发生的时候,我们到异常发生的位置,再去看处理代码。这是不是就方便多啦?

        所以,异常的产生可以让正常流程代码和异常处理代码相分离。

        我们现在定义一个非法值的异常:

        然后将异常在这里抛出:

        主函数中用try-catch语句来写:

        编译运行:

        我们再来分析一下:

        如果真的出现了问题,传入了-3和4,长方形就没有建立成功,求面积也是没有意义的,后面再用catch来处理,有意义吗?没有。

        try-catch后面还有很多关于这个长方形的代码,下面的处理是不是全没有意义呀?那怎么办呢?

        让异常继承它,RuntimeException:

        一旦发生这个问题,我不告诉你,我就让你的程序停掉,因为数据非法了。数值都非法了,我还如何运算呢?没办法运算呀。而这个问题是你造成的,你造成的问题已经使得我的运算无法继续,那我就不运算辣!我也是有脾气的,哼!

        这个时候,程序就被停掉,代码需要被修正。

        这就是继承RuntimeException的原因。

        这里也不需要标识啦:

        不标识的话,主函数中调用的时候就不需要处理了,因为它根本就不知道会发生问题:

        此时编译运行,结果就靠谱啦:

        程序直接结束,由虚拟机来处理。处理完告诉你,你出现非法值啦,在29行和51行,你赶紧把这个值改掉辣!

        所以就要修改代码了。

        用户在使用Rec对象的时候,就需要判断一下,他往里面传的值必须保证是符合的值才能往里面传。

        再写一个圆形Circle类:

        在主函数中调用:

        编译运行:

        我们又有一个问题,那这样写的话,我们还写这个自定义异常NoValueException做什么呢?

        需要写哒,因为自定义异常中会有我们自己的特有内容。而且,如果直接是RumtimeException异常,我们不能具体的看出是哪一个异常。如果我们能够起一个更有意义的名字,比如这里的NoValueException,是不是就更加方便阅读啦?

        所以,我们通常会起一个特有的名称,就知道发生了什么问题啦。

        这叫做对问题名称的描述。

        所以,在这里,我们还是建议,写成NoValueException:

        这样运行的时候抛出的就是NoValueException啦。这样名称会更直观一些:

        这种是RuntimeException,当然,如果其他可以处理的对象,就需要在方法上声明,并在调用的时候写try-catch语句来处理。注意,将正常流程写在try中,将处理过程写在catch中,这样正常流程和异常处理的代码就成功分离啦,阅读性会更好。

        以后注意啦,写代码的时候会经常碰到问题,碰到问题怎么办呢?用异常来描述,封装成对象。问题也是个对象呢。

    05-面向对象(异常-总结)

        异常:

        是什么?是对问题的描述。将问题进行对象的封装。

        异常体系:

                Throwable

                        |--Error

                        |--Exception

                                |--RuntimeException

        异常体系的特点:异常体系中的所有类以及建立的对象都具备可抛性,也就是说可以被throw和throws关键字所操作。注意,只有异常体系具备这个特点。

        throw和throws的用法:

        throw定义在函数内,用于抛出异常对象。

        throws定义在函数上,用于抛出异常类,可以抛出多个用逗号隔开。

        当函数内容有throw抛出异常对象,并未进行try处理,那么必须要在函数上声明,否则都会编译失败。

        注意:RuntimeException异常除外。也就说,函数内如果抛出的是RuntimeException异常,函数上可以不用声明。

        如果函数声明了异常,调用者需要进行处理,处理方法可以throws可以try。

        异常有两种:

        1,编译时被检测异常

                该异常在编译时如果没有处理(没有抛也没有try),编译失败。

                该异常被标识,代表这可以被处理。

        2,运行时异常(编译时不检测)

                在编译时,不需要处理,编译器不检查。

                该异常的发生,建议不处理,让程序停止。需要对代码进行修正。

        异常处理语句: 

        有三种结合方式:

        1,try和catch:

        2,try和finally:

        3,try、catch、finally:

        注意:1.finally中定义的通常是关闭资源代码,因为资源必须释放。

        另外,注意在下面这个例子中这两种语句的不同:

         2,finally只有一种情况不会执行。当执行到System.exit(0);的时候,finally不会执行。

        自定义异常:

                定义类继承Exception或者RuntimeException

                1,为了让该自定义类具备可抛性

                2,让该类具备操作异常的共性方法

                当要定义自定义异常的信息时,可以使用父类已经定义好的功能。

                比如异常信息会传递给父类的构造函数:

        自定义异常的好处:

        自定义异常是按照Java的面相对象思想,将程序中出现的特有问题进行封装。

        异常的好处:

                1,将问题进行封装。

                2,将正常流程代码和问题处理代码相分离,方便于阅读。

        异常的处理原则:

                1,处理方式有两种:try或者throws

                2,调用到抛出异常的功能时,抛出几个,就处理几个。

                        这时会出现一个try对应多个catch的情况。

                3,多个catch,父类的catch放到最下面。

                4,catch内,需要定义针对性的处理方式。不要简单的定义printStackTrace,或者输出语句。也不要不写。(因为但凡出现问题,将不会有任何的提示和日志文件保留,会导致这个问题就过去了)

                        当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。

                        如果该异常处理不了,但并不属于该功能出现的异常。

                        可以将异常转换后,再抛出和该功能相关的异常。

                        或者异常可以处理,但需要将异常产生的和本功能相关的问题提供出去。

                        当调用者知道,并处理,也可以将捕获异常处理后,转换新的异常。

        异常的注意事项:

               在子父类覆盖时:

                1,子类抛出的异常必须是父类的异常的子类或者子集。

                2,如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try不能抛。

    06-面向对象(练习四)

        这一节将有一大串截屏,因为不想在这些小练习题上耗费太多时间,就先截下来,以后闲暇时间可以慢慢做着玩儿~

        不想看题之间把这段划过去就OK啦。 

        编译失败。没有再func方法上声明该异常。应改成:

        如果func方法上声明了该异常,结果是:B C D

        考的是子类的实例化过程。

        结果:Test Demo Test

        编译失败:因为A接口中并未定义func方法,这个方法是子类特有的。

        A B

        编译失败,因为A接口中没有定义test方法。

        B C 5

        编译失败,非静态内部类中不可以定义静态成员。

        内部类中如果定义了静态成员,该内部类必须被静态修饰。

        4 5 showzi showzi

        B C D

        编译失败。因为傅雷中缺少空参数的构造函数。

        或者子类应该通过super语句指定要调用的父类中的构造函数。

        编译失败。因为子类父类中的get方法没有覆盖。但是子类调用的时候不能明确返回的值是什么类型。所以这样的函数可以存在子父类中。

        编译失败。因为打印“A”的输出语句执行不到。

        记住:throw单独存在,下面不要定义语句,因为执行不到。

        编译失败。多个catch时,父类的catch要放在下面。

        134 13423

        4

    

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 引言 在程序运行过程中(注意是运行阶段,程序可以通过编译),如果JVM检测出一个不可能执行的操作,就会出现运行时错...
    Steven1997阅读 2,385评论 1 6
  • 八、深入理解java异常处理机制 引子try…catch…finally恐怕是大家再熟悉不过的语句了, 你的答案是...
    壹点零阅读 1,516评论 0 0
  • packagetestexcrpltiom; importjava.text.ParseException; im...
    猿学阅读 1,431评论 0 2
  • Java中的异常和处理详解 简介 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异...
    Richard2016阅读 238评论 1 0
  • 今天跟老公开车去4S店里选车牌号,去的时候我感觉不是特别舒服,心里就开始打退堂鼓,想着全程都让老公开车吧。因为之前...
    Super_Luna阅读 162评论 0 0