一个程序开发出来以后,不管是用户仍是程序员,都但愿它稳定地运行,然而程序毕竟是人写的,人无完人哪能不犯点错误呢?就算事先考虑得完美无缺,揣着一笔巨款跑去岛国买了栋抗震性能良好的海边别墅,谁料人算不如天算,碰到猴年马月赶上了一场大海啸,整个别墅被冲到山上去了。计算机程序也是如此,不论是人为的错误,仍是意外的风险,都会致使程序在运行时异常退出。引发程序异常的缘由多种多样,就已经介绍过的知识点而言,主要有这么几种可能发生异常的状况:数学运算异常、数组越界异常、字符串与日期格式异常、空指针异常、类型转换异常等等,接下来分别进行详细说明。html
一、数学运算异常
最多见的算术异常当为除数为零,众所周知,在除法运算中除数是不能为零的,纵使数学家规定一除以零的结果等于无穷大,但是计算机该如何表达无穷大呢?要知道我的电脑的内存总共才几个G。既然有限的内存容纳不了无限的大小,想让程序计算一除以零就是不可能的事情了。接下来不妨经过一个除数为零的Java程序验证看看,测试用的方法代码示例以下:java
// 测试算术异常:除数为0 private static void testDivideByZero() { int one = 1; int zero = 0; int result = one / zero; System.out.println("divide result="+result); }
运行以上的测试代码,果不其然观察到了异常日志“java.lang.ArithmeticException: / by zero”,可见除数为零是不正确的写法。
另外一种算术异常也跟无限有关,像一除以三的结果为三分之一,使用小数表达的话即是0.33333333……这样的无限循环小数。固然因为浮点类型和双精度类型有精度限制,所以使用浮点数抑或双精度数存放三分之一,都只会精确到小数点后若干位,并不存在无限循环的问题。麻烦出在大小数BigDecimal上面,由于大小数默认是绝对精确的,只要开发者不指定大小数的精度位数,则系统会竭尽所能把大小数的精确值原本来本地表达出来。那么问题就来了,三分之一的数值乃无限循环小数,小数点后面的3有无限多个,似此无限的位数,依旧让有限的内存徒呼奈何。下面即是经过大小数计算一除以三的代码例子:程序员
// 测试算术异常:商是无限循环小数 private static void testDivideByDecimal() { BigDecimal one = BigDecimal.valueOf(1); BigDecimal three = BigDecimal.valueOf(3); BigDecimal result = one.divide(three); System.out.println("sqrt result="+result); }
运行上面的除法代码,可见程序仍然打印了异常日志“java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.”,意思是无限小数无法用精确的十进制数来表达。数组
二、数组越界异常
假设某个数组只有三个元素,正常状况可以访问第一个、第二个和第三个元素,要是程序强行访问第四个元素,系统该怎么办?总不能无中生有变戏法变出一个吧,计算机程序可不是魔术师,它找不到第四个元素就崩溃退出了。好比如下的数组访问代码就重现了这个问题:ide
// 测试越界异常:下标超出数组范围 private static void testArrayByIndex() { int[] array = {1, 2, 3}; int item = array[3]; System.out.println("array item="+item); }
运行以上的测试代码,程序果真输出了异常信息“java.lang.ArrayIndexOutOfBoundsException: 3”,此处的下标3表明数组的第四个元素,而该数组总共只有三个元素。
不光是数组存在越界异常,容器里的清单List也存在一样的问题,由于清单的索引相似数组的下标,一旦寻求访问的元素索引超出了清单大小,程序运行时也会扔出数组越界异常。用于演示经过索引访问清单元素的代码示例以下:工具
// 测试越界异常:索引超出清单范围 private static void testListByIndex() { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Integer item = list.get(5); System.out.println("list item="+item); }
运行上述的清单访问代码,依然可见程序扔出的异常描述“java.lang.ArrayIndexOutOfBoundsException: 5”,表示索引为5的位置已经超出了当前数组(实际上是清单)的边界。性能
三、字符串与日期格式异常
调用String类的format方法进行字符串格式化之时,每种格式定义与数据类型是一一对应的,例如%d对应整型数,%s对应字符串,%b对应布尔值等等。因此格式化的参数值必须和它的格式要求相符,假若两者匹配不了,这可如何是好?譬如原先定义的参数格式为%d,表示此处指望格式化一个整型数,结果后面的参数列表却传入某个字符串,难道字符串要格成整数?恐怕只能让程序嗝屁了。不信请看下面的字符串格式化代码:测试
// 测试格式异常:字符串格式非法 private static void testStringByFormat() { String str = String.format("%d", "Hello"); System.out.println("str="+str); }
运行上面的格式化代码,毫无疑问程序没法正常运行,只能无奈地打印异常日志“java.util.IllegalFormatConversionException: d != java.lang.String”。
不仅仅字符串有格式要求,日期时间也有格式要求,若是须要把日期数据转换成字符串类型,就得在构造SimpleDateFormat实例时书写正确的时间格式,一个字很少一个字很多,假若把分钟格式mm误写为mi,试试看程序会怎么运行如下的时间转换代码?spa
// 测试格式异常:日期格式非法 private static void testDateByFormat() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mi:ss"); String strDate = sdf.format(new Date()); System.out.println("strDate="+strDate); }
因为时间格式指定的分钟代号mi有误(正确的应为mm),所以运行以上的测试代码,程序也只能乖乖地打印出错信息“java.lang.IllegalArgumentException: Illegal pattern character 'I'”,表示mi里面的字母I是非法的格式字符。指针
四、空指针异常
面向对象的前提是有这个对象,比如这个春节你妈喊你带上对象回家过年,可要是对象连影都见不着,你妈给你对象准备的嘘寒问暖就都泡汤了。在Java代码里面,除了少数几个基本类型,其他绝大多数类型必须先给对象建立实例,而后才能访问该对象的各项成员属性和成员方法。假如不给对象分配实例,就想牵起对象的小手,系统会果断地告诉你:门都没有!譬如经常使用的字符串类型,不论是new出一个字符串实例,仍是硬塞给它一个双引号括起来的具体串,都算做分配了对象实例。若是声明字符串对象时啥都不干,或者随便填了个null,那真是对不起了,程序认为该对象没有初始化,就不会给它分配存储空间。后面的代码再想操做这个对象的时候,找不到对象地址只能报空指针异常了,有关的异常重现代码以下所示:
// 测试空指针异常:对象不存在 private static void testStringByNull() { String str = null; int length = str.length(); System.out.println("str length="+length); }
运行如上的测试代码,观察到打印的异常信息为“java.lang.NullPointerException”,显然被系统揪到了偷懒的小辫子。
五、类型转换异常
在运用多态技术的时候,经常将某个父类实例转换成子类的类型,以便调用子类自身的方法。但这得确保原来的父类实例来自于该子类才行,倘使父类实例来自另外一个子类B,代码却想把它强行转换为子类A,也就是俗称的张冠李戴,系统天然不容许这种胡搅蛮缠的状况。尽管开发者通常不会糊涂,但是难保偶尔脑壳抽筋,好比数组工具Arrays的asList方法返回一个清单对象,乍看过去与列表类型ArrayList是一个家伙,谁知真要转换类型的话,程序竟然会不认帐!这里转换清单类型的代码示例以下:
// 测试类型转换异常:原始数据与目标类型不匹配 private static void testConvertLyList() { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); ArrayList<Integer> arrays = (ArrayList<Integer>) list; System.out.println("arrays size="+arrays.size()); }
运行上述的类型转换代码,结果输出异常日志“java.lang.ClassCastException: java.util.Arrays$ArrayList cannot be cast to java.util.ArrayList”,没想到此列表非彼列表,当真是大意不得。
更多Java技术文章参见《Java开发笔记(序)章节目录》