异常介绍当程序运行过程中抛出异常后程序就自动退出下面的代码就不执行了。如果抛出异常的问题是个致命的问题就会导致系统崩溃。所以java设计提出了一个异常处理机制来解决这个问题。异常处理机制如果程序员认为某段程序可能会出现异常可以使用try{...}catch{...}来捕获异常。捕获到的异常可以自己需要的方式进行处理。基本概念在java语言中将程序执行中发生的不正常情况称之为“异常”。开发过程中语法错误、编译错误不属于异常逻辑错误可能导致运行时异常。。程序运行过程中的异常分为两大类Error(错误):java虚拟机无法解决的严重问题程序会崩溃。如jvm系统内部错误、StackOverflowError[栈溢出]等。Exception: 其它因编程错误或者偶然的外部因素导致的一般性问题可以使用针对性的代码处理。如空指针异常、试图读取不存在的文件、网络连接中断等。Exception也分为两大类编译异常运行时异常异常体系图Throwable类是所有异常类的基类它实现了Serializable接口。Error类是所有Error异常类的基类非运行时异常直接继承Exception或其子类但不继承RuntimeException。这两个类同时继承了Throwable类。运行时异常类都会继承RuntimeException类,所以RuntimeException类是所有运行时异常类的基类。运行时异常类编译器检查不出来。一般是指编译时程序逻辑错误是程序员应该避免其出现的异常。所以一般不作处理因为这样的类异常很普遍若全处理可以对程序的可读性和运行效率产生影响。编译时(非运行时)异常类都会继承Exception类。编译时(非运行时)异常类是编译器要求必须处理的异常。常见异常1. 运行时异常非受检RuntimeException及其子类编译器不强制处理通常是程序员逻辑错误应通过编码避免。异常类含义典型触发场景ArithmeticException算术运算异常整数除以 0int a 1 / 0;注意1.0 / 0得Infinity不抛NullPointerException空指针异常调用null对象的方法/字段、访问null数组元素、自动拆箱null包装类ArrayIndexOutOfBoundsException数组下标越界int[] a new int[3]; a[3] 1;StringIndexOutOfBoundsException字符串下标越界abc.charAt(5)、abc.substring(2, 5)IndexOutOfBoundsException索引越界父类集合越界list.get(10)NegativeArraySizeException数组长度为负new int[-1];ArrayStoreException数组元素类型不兼容存入的对象类型与数组声明类型不符Object[] a new String[2]; a[0] Integer.valueOf(1);ClassCastException类型转换异常强制转换失败Object o s; Integer i (Integer) o;o null时不会抛结果为nullNumberFormatException数字格式异常字符串转数字失败Integer.parseInt(abc);IllegalArgumentException方法接收到不合法参数Thread.sleep(-1)、new ArrayList(-1)IllegalStateException对象状态不适合当前操作Iterator在remove()前未next()IllegalMonitorStateException监视器状态错误未持有对象锁就调用obj.wait()/notify()/notifyAll()或未在synchronized块内IllegalThreadStateException线程状态不适合当前操作对已启动的线程再次调用start()UnsupportedOperationException不支持该操作Arrays.asList(...)返回的固定大小 List 调用add()ConcurrentModificationException并发修改异常用 for-each 遍历集合时直接list.remove()应用Iterator.remove()SecurityException安全异常安全管理器SecurityManager拒绝访问受限资源文件、网络、反射、系统属性等沙箱环境 / 启用 SecurityManager 时访问受限资源OutOfMemoryErrorError而非ExceptionJVM 无法分配内存无限创建大对象、堆内存耗尽不要catch它应排查内存泄漏StackOverflowErrorError栈深度超限无限递归无终止条件2. 受检异常非运行时异常Exception的子类但不继承RuntimeException编译器强制要求要么try-catch捕获要么在方法签名上throws声明否则编译不通过。异常类含义典型触发场景IOExceptionI/O 操作异常父类读写文件失败、流已关闭、网络中断FileNotFoundException文件未找到IOException子类new FileInputStream(不存在.txt)EOFException输入未完成即遇文件结尾IOException子类DataInputStream.readInt()读到文件末尾仍继续读ClassNotFoundException找不到指定类类加载阶段Class.forName(com.xxx.NotExist)反射/驱动加载时类不在 classpathInterruptedException线程在sleep/wait/join中被中断调用thread.interrupt()打断阻塞中的线程捕获后应Thread.currentThread().interrupt()恢复中断标志CloneNotSupportedException对象未实现Cloneable接口却调用clone()class A {}后new A().clone()Object.clone()是protected且检查接口NoSuchMethodException反射时找不到指定方法clazz.getMethod(notExist)普通方法调用编译期就检查不会抛这个IllegalAccessException反射访问无权访问的成员非 public 且未setAccessible(true)field.get(obj)访问 private 字段NoSuchFieldException反射找不到字段clazz.getField(notExist)InstantiationException反射创建实例失败clazz.newInstance()作用于接口/抽象类/无无参构造SQLException数据库访问异常连接失败、SQL 语法错误ParseException解析异常java.textnew SimpleDateFormat(yyyy-MM-dd).parse(abc)异常处理当程序发生异常时分为两种方式处理异常try…catch…finallytry{//代码可能有异常}catch(Exceptione){//如果有异常捕获到异常。可以写多个catch。//当异常发生时系统将异常封装成Exception 对象e传递给catch//得到异常对象后程序员自己处理}finally{//finally可以不写//不管try代码块是否有异常发生始终要执行finally。//所以通常将释放资源的代码放在finally}注意细节:如果异常发生了try语句块中的异常发生的语句之后的代码不会被执行。会直接进入到catch代码块中执行完成之后还会继续执行try...catch之外的代码。不管try代码块是否有异常发生始终要执行finally。有极少数情况不执行System.exit()/Runtime.halt()JVM 崩溃如 StackOverflowError 后再次出错、OOM 直接 kill 进程线程被强制终止已废弃的Thread.stop可以捕获多个异常即写多个catch语句要求子类在前面父类异常在后面。如果发生异常只会进入第一个匹配的 catch 分支。否则父类在前导致子类 catch 永远不可达可以进行try-finally组合使用这种组合的意思是不做异常处理但是要做别的一些事情。由于没有捕获异常所以异常最终会throw给JVM程序会直接崩溃。一道练习题:publicclassException2{publicstaticvoidmain(String[]args){System.out.println(method());}publicstaticintmethod(){inti1;try{i;//2String[]stringsnewString[3];if(strings[1].equals(tom)){System.out.println(strings[1]);}else{strings[3]light;}return1;}catch(ArrayIndexOutOfBoundsExceptione){return2;}catch(NullPointerExceptione){returni;//由于finally没有return语句jvm底层会先将i保存到temp中执行finally语句块然后返回temp}finally{i;System.out.println(ii);}}}throws将异常抛出由上层调用者来处理最顶级的处理者就是JVM。在方法声明中使用的throws语句可以声明抛出异常列表列表中的异常是平级的throws后面的异常类型可以是方法中产生的异常也可以是它的父类。使用细节子类重写父类的方法时子类重写的方法所抛出的异常类型要么和父类抛出异常一致要么为父类抛出的异常类型的子类型。子类抛出的异常类型父类抛出的异常类型运行时异常根本不需要 throws 声明编译器不检查若未处理会沿调用栈自动向上传播最终由 JVM 处理终止当前线程。自定义异常当程序中出现了某些错误但该错误信息并没有在Throwable子类中描述处理这个时候可以自己设计异常类用于描述该错误信息。步骤:1定义类自定义异常类名程序员自己写继承Exception或RuntimeException2 如果继承Exception属于编译异常。如果继承RuntimeException属于运行异常一般来说继承RuntimeException一般使用throw关键字抛出异常。//测试类publicclassCustomException{publicstaticvoidmain(String[]args){ThrowAgeExceptionexnewThrowAgeException();try{ex.throwsExceptionMethod();}catch(AgeExceptionme){System.out.println(AgeException:me.getMessage());}}}//抛出异常类classThrowAgeException{publicvoidthrowsExceptionMethod(){intage180;if(!(age20age120)){thrownewAgeException(年龄不合法);}}}//自定义类classAgeExceptionextendsRuntimeException{privateStringmessage;publicAgeException(Stringmessage){super(message);this.messagemessage;}OverridepublicStringgetMessage(){returnthis.message;}}throws和throw区别练习题说出下面程序可能出现的异常publicstaticvoidmain(String[]args){if(args[4].equals(john)){System.out.println(AA);}else{System.out.println(BB);}Objectoargs[2];Integeri(Integer)o;}1.如果args为空数组越界异常、空指针异常。2.Integer i (Integet)o会出现类型转换异常。
阅读完成 · 觉得有帮助?