什么是异常
异常,就是不正常的意思。java中的异常指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。
异常的体系:
异常的根类是 java.lang.Throwable ,其下有两个子类。
- Error:严重错误Error,无法通过处理的错误,只能事先避免。
- Exception:表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的。
常见的一个异常(数组越界)
public class Test {
public static void main(String[] args) {
int []a = {1,2,3};
System.out.println(a[3]);
}
}
看上述代码,由于数组下标从零开始,因此数组a的最大下标为a[2],不存在a[3],出现异常情况,异常信息如下。
异常分类:
- 编译时期异常:checked异常。在编译时期,就会检查,如果没有处理异常,则编译失败。(如日期格式化异常)
- 运行时期异常:runtime异常。在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)。(如数学异常)
异常的处理:
1.抛出异常throw
public class Test {
public static void main(String[] args) {
int []a = {1,2,3};
int result = getElement(a,2);
System.out.println(result);
}
public static int getElement(int[] arr,int index){
//判断 索引是否越界
if(index<0 || index> (arr.length-1)){
throw new ArrayIndexOutOfBoundsException("异常,数组越界");
}
return arr[index];
}
}
声明异常throws:
将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理(稍后讲 解该方式),那么必须通过throws进行声明,让调用者去处理。 关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常)。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class Test {
public static void main(String[] args) throws FileNotFoundException {
readFile();
}
public static void readFile() throws FileNotFoundException {
InputStream is = new FileInputStream("E:/zzg/ch01.txt");
}
}
捕获异常:try catch
前面讲到的throw和throws都是声明异常,不对异常进行处理,而try catch是对异常有针对性的进行捕获,可以对出现的异常进行指定方式的处理。
try{
//编写可能会出现异常的代码
}catch(异常类型 e){
//处理异常的代码
}
import java.io.FileNotFoundException;
public class Test {
public static void main(String[] args) {
//捕获异常
try {
read("b.txt");
} catch (FileNotFoundException e) { //定义异常类型
System.out.println(e); //输出异常的信息
}
System.out.println("over");
}
//存在异常
public static void read(String path) throws FileNotFoundException {
if (!path.equals("a.txt")) { //如果不是 a.txt这个文件就抛出异常
throw new FileNotFoundException("文件不存在");
}
}
}
finally:
有一些特定的代码无论异常是否发生,都需要执行,例如关闭某个资源,而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。
finally的语法: try...catch....finally:自身需要处理异常,最终还得关闭资源。
import java.io.FileNotFoundException;
public class Test {
public static void main(String[] args) {
try {
read("a.txt");
} catch (FileNotFoundException e) {
System.out.println(e);
} finally {
System.out.println("关闭资源");
}
}
public static void read(String path) throws FileNotFoundException {
if (!path.equals("a.txt")) { //如果不是 a.txt这个文件,抛出异常
throw new FileNotFoundException("文件不存在");
}
}
}
自定义异常:
前文讲述的数组越界,文件不存在等异常都是java自定义好的异常,而实际开发过程中,我们要根据实际情况来自定义异常,比如昵称已存在等。
异常类如何定义:
- 自定义一个编译期异常: 自定义类并继承于 java.lang.Exception 。
- 自定义一个运行时期的异常类:自定义类 并继承于 java.lang.RuntimeException。
练习,如果输入同样的昵称,则给出异常提示:用户名已注册。
首先的,定义登陆异常类,继承Exception
public class RegisterException extends Exception{
//无参构造
public RegisterException(){
}
//message 为异常提示
public RegisterException(String message) {
super(message);
}
}
然后进行测试:
public class Test {
//假设数据库中已经存在了这些名字
private static String[] names = {"bill","hill","jill"};
public static void main(String[] args) {
try{
// 可能出现异常的代码
checkUsername("bill");
System.out.println("注册成功");//如果没有异常就是注册成功
}catch (RegisterException e){
//处理异常
e.printStackTrace();
}
}
//判断当前注册账号是否存在
public static boolean checkUsername(String uname) throws RegisterException {
for (String name : names) {
if(name.equals(uname)){ //如果名字在这里面 就抛出登陆异常
throw new RegisterException("改昵称已被注册");
}
}
return true;
}
}
当我们输入了一个新的昵称时,此时便不会抛出异常,则“注册成功”就会被打印;而如果输入了旧的昵称,就会抛出异常,异常后面的语句也就不会执行,故打印异常信息。
成功注册:
异常: