一、程序的错误类型
程序的错误可以抽象分为三类:语法错误、运行错误和逻辑错误
1、语法错误(编译时)
由于编程中输入不符合语法规则而产生的(即敲代码时没留意敲错了)
程序编译就通不过,程序不能运行起来。此类错误最简单,调试起来比较容易。
编译诊断的语法错误分为3种:致命错误、错误、警告。
(1)致命错误:编译被迫中止,只能重新启动编译程序。
原因(编译程序内部发生的错误)
解决方法(编译前先保存源程序)
(2)错误:产生这类错误时,编译程序会出现报错提示
原因(语法不当)
解决方法(根据提示对源程序进行修改即可)
(3)警告:这些警告中有些会导致错误,有些可以通过。
原因(怀疑被编译程序有错,但是不确定)
解决方法(根据提示进行查看修改即可)
2、运行错误(运行时)
程序在运行过程中出现的错误。
程序运行的时候出现错误,导致程序被迫终止,此类错误有特定的发生条件。
所以能够准确的定位错误代码段,调试也比较方便。
(可能相关部分没配好,典型:数据库连不上,导致下面的操作无法继续)
例如:除数为0 、数组下标越界、文件打不开、磁盘空间不够、数据库连接错误等。
此类错误发生时,编译平台会提示相应的信息,对于常规的错误会有比较精确地提示
3、逻辑错误(运行后)
程序运行后没有得到设计者预期的结果,说明程序存在逻辑错误。(莫名其妙那种)
程序运行没出错,但是结果不是用户想要的
分为两种情况:
A、能够看出错误。比如查询工资大于5000的人员名单,却出现了3000的;
B、看不出错误。后果很严重:比如大型运算中,值值相关,一值出错导致最后数值误差过大,就得从头排查错误。
例如:使用了不正确的变量,指令的次序错误,循环的条件不正确,程序设计的算法考虑不周全等。
通常,逻辑错误也会附带产生运行错误。
在一般情况下,编译器在编译程序时,不能检测到程序中的逻辑错误,也不会产生逻辑错误的提示,因此逻辑错误比较难排除,需要程序员仔细的分析程序,并借助集成开发环境提供的调试工具,才能找到出错的原因,并排除错误。
二、Java的异常处理(错误处理)
程序的错误就是通常的异常,也叫Exception。
对于语法错误,java编译系统在编就能发现检查出错误。
对于运行错误,Java语言中异常使用一个专门的类来表示一种特定的异常情况,在系统中传递的异常情况就是该类的对象
这个体系就是Java语言中的异常类体系。 (异常类 属于运行错误这一块)
对于逻辑错误,编译系统是无法发现错误的,需要人为去发现排除错误。
1、java异常类
Java的异常是一个对象,所有的异常都直接或间接地继承Throwable类。
为了方便对于这些可传递对象的管理,Java API中专门设计了java.lang.Throwable类
只有该类子类的对象才可以在系统的异常传递体系中进行。
Throwable类的继承层次结构如下:
Throwable下有 ERROR( 一般为系统方面的错误 ) 和 EXCEPTION( 一般为程序方面的错误 )
EXCEPTION下有 非运行时异常 和 运行时异常(RUNTIMEEXCEPTION)
Throwable类的两个子类分别是:
1)Error类
该类代表错误,指程序无法恢复的异常情况。
对于所有错误类型以及其子类,都不要求程序进行处理。
常见的Error类例如内存溢出StackOverflowError等。
2)Exception类
该类代表异常,指程序有可能恢复的异常情况。
该类就是整个Java语言异常类体系中的父类。
使用该类,可以代表所有异常的情况。
在这些异常类中,根据是否是程序自身导致的异常
将所有的异常类分为两种:
a) RuntimeException及其所有子类
属于程序运行时异常,也就是由于程序自身的问题导致产生的异常(代码本身)
例如数组下标越界异常ArrayIndexOutOfBoundsException等。
该类异常在语法上不强制程序员必须处理,不处理也不会出现语法错误。
b) 其它Exception子类
属于程序外部的异常,也就是由于某些外部问题导致产生的异常(其他没配好)
例如文件不存在异常FileNotFoundException等。
该类异常在语法上强制程序员必须要处理,不处理则定会出现语法错误。
2、常见的error类
异常类名 |
用途 |
LinkageError |
动态链接失败 |
VirtualMachineError |
虚拟机错误 |
AWTError |
AWT错误 |
3、常见运行时异常类
异常类名 |
用途 |
ArithmeticException |
数学运算异常,如除数为零异常 |
IndexOutOfBoundsException |
下标越界异常,如集合、数组等 |
ArrayIndexOutOfBoundsException |
访问数组元素的下标越界异常 |
StringIndexOutOfBoundsException |
字符串下标越界异常 |
ClassCaseException |
类强制转换异常 |
NullpointerException |
程序访问空数组元素,空方法,空对象时报错 |
4、常用的非运行时异常
异常类名 |
用途 |
ClassNotFoundException |
指定类或接口不存在的异常 |
IllegalAccessException |
非法访问异常 |
Ioexception |
输入输出异常 |
FileNotFoundException |
找不到指定文件的异常 |
ProtocolException |
网络协议异常 |
SocketException |
Socket操作异常 |
MalformedURLException |
统一资源定位符(URL)的格式不正确异常 |
5、Java的异常处理机制描述如下:
1) 系统寻找相应的代码来处理这一异常,在方法的调用栈中查找
从产生异常的方法开始进行回朔,寻找包含相应异常处理方法 的过程称为捕获(catch)异常如该异常未进行成功捕获,则程序将终止运行。
2) 运行时发生异常,则生成该异常的对象(包含异常详细信息),并把它交给系统
系统寻找相应的代码来处理这一异常。
我们把 生成异常对象并把它交给系统 的过程称为 抛出(throw)异常
异常捕获和处理
格式:
try{
可能抛出异常的程序块;
}
catch (异常类1 异常变量) {
捕捉异常类1的处理程序段;
}
catch (异常类2 异常变量) {
捕捉异常类2的处理程序段;
}
finally{
一定会运行的程序代码;
}
try块——捕获异常:监控代码块是否发生异常,发生异常将抛出异常类所产生的对象并立刻结束执行,而转向异常处理catch部分。
(未try的异常,一律由java编译系统自动将异常对象抛出)
catch块——处理异常:抛出的异常对象
如果异常对象属于catch内所定义的异常类,则捕获并进入catch代码段继续运行程序
如果异常对象不属于catch中所定义的异常类,则进入finally块继续运行程序。
finally块——最终处理:无论是否发生异常都会执行的语句块。
比如执行关闭打开的文件、删除临时文件,关闭数据库连接等操作。
catch可以有多个,try和finally只能有一个
try后面必须要跟catch、finally其中的一个
定义多个catch可精确地定位java异常
异常类常用方法
常用非法 |
用途 |
Void String getMessage() |
返回异常对象的一个简短描述 |
Void String toString() |
获取异常对象的详细信息 |
Void printStackTrace() |
在控制台上打印异常对象和它的追踪信息 |
捕获异常实例
public classTryCatchDemo{
public static void main(String args[]){
try {
int a=8,b=0;
int c=a/b;
System.out.print(c);
}
catch(ArithmeticException e) {
System.out.println("发生的异常简短描述是:"+e.getMessage());
System.out.println("发生的异常详细信息是:"+e.toString());
}
}
}
程序执行结果:
发生的异常简短描述是:/ by zero // getMessage() 获取异常提示
发生的异常详细信息是:java.lang.ArithmeticException: /by zero // e.toString()转字符串输出
如果没有try catch, 系统执行时出现错误的提示如下:
Exception inthread "main"java.lang.ArithmeticException: / by zero
at MathException.main(MathException.java:4)
意思为:在类java.lang.ArithmeticException主线程中“main”方法中出现异常:除数为零
6、异常的抛出
1) 系统自动抛出异常
比如上面的例子就是系统自动抛出异常,通过try catch捕获异常对象,并继续相应的处理。
2) 通过关键字throw显性抛出异常对象(1主动抛出系统异常 2异常自定义抛出异常)
在程序中生成自己的异常对象,即异常可以不是出错产生,而是人为编写代码主动抛出。
异常抛出的语法:
throws子句的方法声明的一般格式如下:
条件{ throw new 异常类(“提示”);}
其中异常类必须Throwable类及其子类。
<类型说明> 方法名(参数列表) throws <异常类型>
{
方法体;
}
1主动抛出异常
例子:
class ThrowException{
static void throwOne(int i) throws ArithmeticException { //throwOne(int i)为方法名和参数
if(i==0)
{
throw new ArithmeticException("i值为零"); //如果i == 0 抛出提示为"i值为零"的异常
}
}
public static void main(String args[]){
try { throwOne(0); } //捕获异常段
catch(ArithmeticException e){
System.out.println("已捕获异常: "+e.getMessage());
}
}
}
运行结果:
已捕获异常:i值为零
2 自定义异常抛出异常
自定义类的格式如下:
class 异常类名 extends Exception
{
……
}
例子:
//MyExceptionDemo.java
package myexceptiondemo;
class MyException extends Exception { //自己写的异常类,MyException
private int detail; //定义整形属性 detail
MyException(int a) //有参方法
{ detail = a; } //参数值赋给属性detail
public String toString() {
return "参数不能大于10";
}
}
class MyExceptionDemo{
static void pd(int a) throws MyException {
System.out.println( "用户参数:"+a );
if(a > 10){ //如果a大于10,则抛出异常
throw newMyException(a);
}
System.out.println("常规退出 "); //else
}
public static void main(String args[]){
try {
pd(1); //给参,a小于10,常规退出
pd(20); //给参,a大于10,抛出异常
}
catch (MyException e)
{ System.out.println("已捕捉,提示: " +e); }
}
}
运行结果如下:
用户参数:1
常规退出
用户参数:20
已捕捉,提示:参数不能大于10为