—— 目录 ——
◉ 异常与错误
错误(Error) 是程序中遇到的使整个程序崩溃的情况,有的能在编译阶段被发现,如 死循环
能被IDEA发现;有的在运行阶段出现,如:内存泄漏
异常(Exception) 是程序中不可避免但可以预先知道并处理的情况。
◉ 异常的分类
异常分为两种:
- 运行时异常(RuntimeException): 在运行时出现的异常
如用户输入异常
、数值除0异常
等
这种异常在编译时可以不作处理,发现错误后直接交给虚拟机JVM处理并结束程序 - 必检查异常(CheckedException): 这是在编译阶段就会要求处理的异常,否则编译不通过,如 IO流异常中的
文件找不到异常
这种异常要求程序员必须先做出处理
◉ 异常的处理
处理方式也有两种:
- try-catch-finally 处理: 对可能出现异常的语句放在 try 中,把异常出现后应该做出的动作放在 catch 中,最后把需要释放的资源放在 finally 中
这样使得即使异常出现,也不会直接交给虚拟机JVM,程序不会中止继续执行 - throws 抛出异常: 如果不知道如何处理或者不想处理异常,可以将异常抛给上级调用者,由调用者进行 try-catch 处理
但当调用者一个一个都不想处理都往外抛的话,最终会抛给虚拟机JVM处理,这时如果异常出现就只能程序中止了
try-catch-finally 处理
public static void main(String[] args) {
File file = new File("D://test.txt");
InputStream is = null;
try {
is = new FileInputStream(file);
} catch (FileNotFoundException e) {
System.out.println("找不到此文件!");
}finally
{
if(is!=null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这是一个必检查的IO异常
- try 中可能存在的异常是
FileNotFoundException
文件找不到异常(如文件名写错了) - catch 中打印出错误提示,也可以用
e.printStackTrace();
打印异常信息。 - finally 中释放了资源,由于又使用到 IO 流,还得加上一个处理 IO 的异常
try-with-resources 语句
JDK7 以后,资源释放可以放在 try 的括号中,简写成:
public static void main(String[] args) {
File file = new File("D://test.txt");
try (
InputStream is = new FileInputStream(file);
/* 资源 ... */
) {
/* 操作资源 ... */
} catch (FileNotFoundException e) {
System.out.println("找不到此文件!");
} catch (IOException e) {
e.printStackTrace();
}
}
需要释放的资源可以放在 try 后边的括号中,等运行完毕后资源会自动被释放掉
括号中资源的作用域依旧是整个 try 块
catch 可以有多个,且先出现的是小异常,大异常必须在后面出现
如 IOException
是 FileNotFoundException
的父类,它放在前面会导致编译不通过。也可以只写 IOException
一个,就能捕获到它及所有子类的异常了
通常可以小异常在前,最后加一个 Exception
捕获所有异常
这种写法可以对已经预测的异常做出相应处理,对可能遗漏的异常进行捕捉
throws 处理
public static void main(String[] args) {
try {
test();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void test() throws IOException
{
File file = new File("D://test.txt");
InputStream is = new FileInputStream(file);
/* 操作资源 ... */
}
将异常抛出,调用时再处理异常
main 方法中可再次将异常抛出,这次由于 mian 方法由虚拟机JVM的调用,所以是直接抛给虚拟机,如果异常出现程序将中止
public static void main(String[] args) throws IOException {
test();
}
◉ 自定义异常
定义方式:
public class MyException extends RuntimeException
{
// 添加一个无参构造器
public MyException()
{
super();
}
// 添加一个带信息的构造器
public MyException(String message)
{
super(message);
}
}
将类继承 Exception 或 RuntimeException 或者其他子类
区别是继承 RuntimeException 为非必须检查异常,除此之外都必须检查
使用:
public static void main(String[] args) throws MyException{
test(-1);
}
public static void test(int a)
{
if(a<0) throw new MyException("不能小于0");
}
throw 用于创建一个异常。这里直接抛出了
注意:RuntimeException 可以不显示写上 throws ,只要没有用 try-catch 进行捕获,就会默认抛出。就如上面一样没有写throws默认抛出(main 后边的 throws 也可不写)
public static void test(int a)
{
try {
if(a<0)
throw new MyException("不能小于0");
}catch (MyException e) {
/* 处理 ... */
}
}
也可以直接捕获,不过通常是直接抛出
◉ finally 的执行机制(面试)
注意 finnally 的执行机制:
无论是 try 执行还是 catch 执行,finally 都会在最后执行一次。
哪怕在 try 和 catch 中有 return 语句,在执行到 return 语句时,都会先放弃然后去执行 finally 语句,直到 finally 执行完毕后再回去执行 return 语句
所以在 finally 中最好不写 return 语句,执行顺序没把握好就会出现奇怪的事
但,如果再 try 或者 catch 中遇到了 exit ,那么 finally 中的代码就不会执行了
ublic static void main(String[] args) {
System.out.println(test(2));
}
public static int test(int a)
{
try {
if(a<0) {
throw new MyException("不能小于0");
}
return a;
}catch (MyException e) {
/* 处理 ... */
return -1;
}finally
{
System.out.println("haha");
}
}
运行结果:
haha
2
◉ throws 和 throw 的区别
- throws 写在方法名的括号后面,表示抛出一个异常给上级调用者
- throw 写在方法体中,表示创建一个异常对象供以使用。常用于手动抛出(自己定义的)异常
◉ final,finally 和 finalize 的区别
- final 用于声明,表示被声明的 属性、方法和类 一旦复制便不可以再被改变
- finally 是异常处理的一部分,表示无论异常与否总会被执行,常用来释放资源等善后处理
- finalize 是Object类的一个方法,垃圾回收器在回收对象时,会调用被回收对象的这个方法,相当于
垃圾的遗言,在垃圾被回收时最后做的善后处理
◉ 面试常见异常
非运行时异常
① IOException
输入输出异常
② ClassNotFoundException
找不到类异常
运行时异常
① ArrayIndexOutOfBoundsException
数组越界异常,如:
int[] a = new int[2];
a[3] = 1;
② ArithmeticException
算数运算异常,如:除0
System.out.println(1/0);
③ ArrayStoreException
数组存储异常,如:
Object[] o = new String[2];
o[0] = new Integer(1);
④ NullPointerException
空指针异常,如:
String a = null;
a.toString();
⑤ ClassCastException
强制类型转化异常,如:
Object o = new String();
Integer i = (Integer) o;
粼粼水波,沙沙作响,捕捉到微风异常!(寒冰小澈)