【JAVA】 03-Java中的异常和包的使用


链接:

目录:

<>


  • <>

内容待整理:

异常

异常和错误的发生和区别

  • 异常:java运行期间发生的问题就是异常。

  • 错误:

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

异常发生的过程

  • 示例:对给定数组,通过给定的角标获取元素。当角标越界时,异常发生的过程:

  • 两个报错位置:

    • 一个类中的主函数调用语句 int num = getElement(arr, 4);
    • 另一个类中的被调用语句 int element = arr[index];
  • 具体发生过程:

    • 被调用函数中:

      没有找到4的角标,运行时发生了问题,这个问题JVM认识
      这个问题java本身有描述,描述内容有: 问题的名称,问题的内容,问题的发生位置
      既然有这么多信息,java就将这些信息直接封装到对象中:对象名 -- ArrayIndexOutOfBoundsException
      throw new ArrayIndexOutOfBoundsException(index);//问题对象。函数到这里就结束了。
      jvm将问题抛给调用者main。
    • 主函数中:

      主函数就收到了越界异常对象。没有处理
      main函数就会继续抛出调用者jvm
      jvm收到问题后,就做出了最终的处理方式。
      将问题对象中的名称、信息、问题的位置,都显示在屏幕上,让软件使用者知道。
      同时,让程序提前终止。
    • tips -- 两个调用者:

      • 函数的调用者:main函数
      • main函数的调用者:JVM

异常的简单应用

  • 考虑异常的必要性:

    • 在编写程序时,必须要考虑程序的问题情况。
    • 举例:卖水果功能需要传递钱参数,有可能有假币。
    • 所以定义程序需要考虑程序的健壮性。
    • 处理:加入一些逻辑性的判断。
  • 注:编译--检查语法错误,运行--传值等,故是在运行时报异常

  • 角标越界和空指针异常的自定义

    • 主函数调用:int num = d.detElement(arr, 3)

      • 当arr=null,空指针异常;当索引实参小于0或大于等于arr长度,角标越界异常。
    • 几种非异常抛出的处理的不合理之处:

      • 若仅打印提示语句,则下面的语句仍执行,不可。这一步已经错了,应该停止程序
      • 若return -1,return表示程序正常结束,不可。这一步已经错了,无法继续执行,必定不能正常结束。
    • 逻辑判断+异常抛出格式:

      if(....){ new throw XxxXxx("..."); }
    • 空指针异常示例:

      throw new NullPointerException("arr指向的数组不存在");
    • 数组角标越界异常示例:

      throw new ArrayIndexOutOfBoundsException("错误的角标, "+index+"索引在数组中不存在");
  • 无效参数异常

    • 定义Person对象、构造函数初始化时判断年龄值age是否符合规范

    • 逻辑判断+异常抛出

      if(age<0 || age>200){ new throw IllegalArgumentException(age+",年龄数值异常"); }
    • 注:新学一个异常,通过查阅API文档中“空指针异常”的父类的子类找到

    • 注:发现大部分异常都可以传String类型的参数来辅助说明

异常的自定义&体系&问题解决

  • 在自定义异常的过程中遇到问题、解决问题的历程和经验

    • 自定义class NoAgeException -- 报错:不兼容 -- 引出Throwable
    • Throwable首字母大写,猜测是类或接口 -- 查阅API文档 -- Throwable是异常和错误的超类
    • Throwable说明:自定义异常被抛出,必须继承Throwable或其子类 -- Throwable有两个子类:Error和Exception
    • 选择性地继承Exception:class NoAgeException extends Exception -- 报错:未报告的异常错误,必须对其进行捕获或声明
    • 对照之前的几个java定义好的异常,查阅其API文档:这几个异常的父类都是RuntimeException
    • 查阅RuntimeException的API文档:RuntimeException执行时,异常以及其子类都无需进行声明 -- 对应错误提示“声明”二字
    • 自定义异常类改为继承RuntimeException:class NoAgeException extends RuntimeException -- 可以抛出,但没有显示实参信息
    • 查阅java定义好的异常的源码:发现其构造函数中带String参数的都继承了父类 super(s); -- 加入super(s)后可以正确抛出并显示提示信息了
  • 问题解决tips:

    • 分析错误提示,提取关键词
    • 查阅API文档并阅读
    • 查阅源码并分析、仿写
  • 自定义异常类最终版:

    class NoAgeException extends RuntimeException{ NoAgeException(){ super(); } NoAgeException(s){ super(s); } }

编译时的异常和运行时的异常的区别

  • 异常分为两种:编译时异常和运行时异常

    • 编译时异常:编译器会检测的异常。(语法范围,必须捕获或声明)

    • 运行时异常:编译器不会检测的异常。不需要声明。

      • 如果声明了,就需要调用者给出处理方式。
  • 列举几种常见的运行时异常:

    • IllegalArgumentException
    • NullPointerException
    • IndexOutOfBoundsException
    • ClassCastException
  • Exception需要声明而RuntimeException不需要捕获或声明:

    • 不是功能本身发生的异常,而是因为比如调用者传递参数错误而导致功能运行失败,则不需要声明。
    • 这时也是问题,需要通过异常来体现,但是这个异常不需要声明出来。
    • 声明的目的是为了让调用者进行处理。
    • 不声明的目的是不让调用者进行处理,就是为了让程序停止,让调用者看到现象,并进行代码的修正。
      • 对于“代码修正”,Error同样是代码修正,但是Error是系统底层抛出的,一般是严重错误;而运行时异常是合理范围之内,和底层没有关系。

声明和捕获

  • 声明

    • 将问题标识出来,报告给调用者。
    • 如果函数内通过throw抛出了编译时异常,而没有捕获,那么必须通过throws进行声明(表示这个方法有可能有问题),让调用者去处理。
    • 格式:类名后不加空格直接跟throws+异常类
    • 示例:
      void show(int x)throws Exception
      Person(String name, int age)throws NoAgeException
    • 注:调用者(如主函数)选择捕获处理时不需要在调用者(如main后)加声明,而抛异常的函数仍需要throws声明,否则报错。
  • 捕获

    • java中对异常有针对性的语句
    • 语句:
      try{ //需要被检测的语句。}
      catch(异常类 变量) //参数 { //异常的处理语句。}
      finally{ //一定会被执行的语句。 }
    • 注1:其中catch语句的参数“异常类”为声明中throws后面跟的异常类
    • 注2:其中finally语句块可以省略
    • 注3:python中的类似语句块:try.. except.. else...(else可省略)
  • tips:

    • 编译器先检查语法等问题,最后才检查异常问题,故当看到编译失败显示的是异常错误,那么恭喜,说明其他的都没问题了。
  • 示例思考:构造函数到底抛出NoAgeException继承Exception呢?还是RuntimeException呢?

    • 继承Exception,则:

      • 必须要throws声明,一声明就告知调用者进行捕获,一旦问题处理了调用者的程序会继续执行
      • 但是如果后面使用到了Person对象的数据,会导致全都失败
    • 继承RuntimeException,则:

      • 不需要throws声明的,这时调用是不可能编写捕获代码的,因为调用根本就不知道有问题
      • 一旦发生NoAgeException,调用者程序会停掉,并由jvm将信息显示到屏幕上,让调用者看到问题,并修正代码

运行时异常的应用

  • 预判需要编译时异常还是运行时异常

    • 案例1:长方形长和宽的数值异常 -- 运行时异常,仅声明
    • 案例2:毕老师讲课时电脑蓝屏,重启处理 -- 编译时异常,捕获
    • 调用到了声明异常的方法,到底是捕获还是声明?
      • 有具体的捕获处理方法吗?有,捕获;没有,声明。
      • 可以处理,重启就可以了,重启是电脑的功能。

异常的转换

  • 案例2:当多个异常,且存在不能处理的异常时:异常的转换

  • 一个方法可以通过throws声明多个问题

    public void run()throws LanPingException, MaoYanException
  • 对于声明多个异常的方法,在处理时,需要定义多个catch与之对应

  • 注意<面试多见>:可以一个try多个catch,存在子父类异常时,子类上,父类下

    • 因为catch是顺序执行的,父类上则子类执行不到了
  • 区分能处理异常和能处理因此异常导致的异常

    • 不能处理“冒烟”,但是可以处理冒烟导致的“课程停止”异常
    • 在冒烟中抛“课时停止”,并在主函数中catch“课程停止”异常并进行处理(“换老师”)
    • 不要抛对方不能处理的异常:存钱时,不要跟储户说金库门坏了,说对他的钱的处理方式。

throw和throws的区别:

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

finally的使用

  • 作用:存放一定会执行到的语句

    • 当catch中有return时,在return之前,会先执行完finally中的语句,再return
  • 只有一种情况发生时,finally也不执行(需要把上面的return注释掉)

    • System.exit(0);//退出JVM

finally的应用场景

  • 只要程序中使用到了具体的资源(数据库连接,IO资源,网络连接socket等)
    需要释放,都必须定义在finally中。(只有在这儿才能真正被释放)
  • 在定义程序时,只要问题发生与否,指定程序都需要执行时,就定义在finally中
  • 注意:面试会考的tips:

    • finally代码块仅在catch的return之前执行,即return前的语句都执行完成后再执行finally。
    • finally代码块中如果有return,则提前结束功能,catch中的return就执行不到了。
    • 能结束函数的语句,除了return,还有异常。抛异常也可以结束。

try catch finally组合方式

  • 1、try catch:

    • 对代码进行异常检测,并对检测的异常传递给catch处理,叫做:异常捕获处理。
      (注:有catch才叫捕获处理,没catch写try也没用)
      void show()throws?
      //声明不声明需要看捕获的异常是否有处理方式
      //如果有,不声明;如果没有,要抛出的那种,就要声明。
  • 2、try finally:

    • 对代码进行异常检测,检测到异常后,因为没有catch,所以一样会被默认jvm抛出, 叫做:异常没有捕获处理。
    • 但是功能所开启的资源需要进行关闭,所以有finally。
      void show()throws//没有catch,没有捕获处理,要声明
  • 3、try catch finally:

    • 检测异常,并传递给catch处理,并定义资源释放(最常见的)
  • 4、try catch1 catch2 catch3...

    • catch取决于抛多少个异常,针对性处理

异常在覆盖中的细节

异常在继承或实现中的使用细节:重点掌握

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

package的使用

  • 对于多个类,为了便于管理(类的同名情况),所以java提供了一个解决方案
  • 包机制:落实到操作系统上,就是文件夹。
    对Java的文件进行分文件夹管理。
  • 包的定义:使用关键字 package。

  • 包的作用:

    • 1、对类文件进行管理。
    • 2、给类文件提供了名称空间。
      package mypack;//包名中的所有的字母都小写
      package mypack.haha.hehe.xixi;//多级包时,加句点

包与包之间的访问

  • 总结:

    • "找不到符号DemoA":类名写错,有了包的类,类名:包名.类名 -- 这才是类的全名称
    • "程序包packa不存在":包在当前目录下没有找到,set classpath=d.myclass
    • 包与包之间的类在访问时,被访问的类以及成员都必须public修饰
  • 注意事项:

    • 被public修饰的类或者接口所属的java文件名必须和类或接口的名称一致。否则编译失败。

包与包之间的继承

  • 父类可以给其他包中的子类提供一种特殊的权限protected
    只有继承为子类后,才可以访问的权限。
  • 包与包之间访问,只有两种权限可用,public protected(该权限只能给不同包中的子类使用)
  • 保护权限开发用的不多,必须先继承才能用。包与包之间用不了,本包可以。

import关键字

  • import -- 导入

  • import作用:

    • 包的出现,导致类的名称过长,书写不方便
    • import作用简化类名书写,省略包名。
    • 注:import不是必须要写。不写import,则直接写全包名即可。
  • 一般一个程序中:仅写一个package并且放在程序首行,但是可以写多个import
  • 一个包中需要的类很多时,写通配符星号即可 import packa.*;
    真正开发时,不建议用星号,有几十个就写几十个(高级编辑器一个快捷键解决)
  • 特殊情况一:包中包,多级包时

    • 若只import第一层包名,则包中包下的类文件不可用
    • 明确了使用的类所属的包,而不会导入包中子包中的类
    • 正确方式:import 包1.包2.包n.*
    • 注意:导包 -- 导入的是包中的类,不是包中的包
  • 特殊情况二:不同包中有相同名称的类。

    • 使用该类时,必须指定包名,否则区分不出来,产生了不确定性

jar包

  • Jar包:java中的压缩包。

    • 读法:架包,勾包
    • 使用不给力,但是真实开发必须用。
  • 打压缩包:javac -cvf xx.jar xxx

    • c:创建新的归档文件
    • v:创建过程中显示详细信息在屏幕上
    • f:归档文件的名称要明确“xx.jar”
    • 最后生成一个xx.jar压缩包
  • 打压缩包后,java运行:直接将jar导入到classpath路径即可正常使用
    • 设置classpath路径:set classpath=.\xx.jar
    • java pack.JarDemo可正常运行

END

优质内容筛选与推荐>>
1、ajax中的一些小问题
2、100 美妙设计的iPhone应用程序网站系列(四)
3、GO--未来十年的编程语言
4、(转)Nginx优化教程 实现突破十万并发
5、最近一直在看模式,越来越感觉到了模式的思想是太好了


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号