异常分类
Java中,所有的异常对象都是派生于throwable
类的一个类实例,以下分为Error
和Exception
。其中Error
为Java运行时的内部错误和资源耗尽错误,用户无需在程序中捕捉或者抛出Error
。另外一种则为Exception
,用户需要对异常妥善处理。
检查异常和非检查异常
检查异常(checked)
一般是指程序不能直接控制的外界情况,是指在编译的时候就需要检查的一类Exception
,用户程序中必须采用try catch机制处理或者通过throws交由调用者来处理。这类异常,主要指除了Error以及RuntimeException及其子类之外的异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Test public void test2(){ FileInputStream fis = null;
try { File file = new File("hello.txt"); fis = new FileInputStream(file);
int data = fis.read(); while(data != -1){ System.out.print((char)data); data = fis.read(); } } catch (IOException e) { e.printStackTrace(); }finally { try { if(fis != null){ fis.close(); } } catch (IOException e) { e.printStackTrace(); } }
}
|
非检查异常(unchecked)
是指那些不需要在编译的时候就要处理的一类异常。在Java体系里,所有的Error
以及RuntimeException
及其子类都是unchecked异常。再形象直白的理解为不需要try
catch
等机制处理的异常,可以认为是unchecked的异常。
运行时异常和编译时异常
运行时异常
都是RuntimeException
类及其子类异常,例如NullPointerException
(空指针异常)、IndexOutOfBoundsException
(下标越界异常)等,这些异常是非检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
编译时异常
是RuntimeException
以外的异常,类型上都属于Exception
类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException
、SQLException
等以及用户自定义的Exception异常。
异常处理
异常捕获
try-catch-finally
try
: 可能出现异常的代码段
catch
: 对应的异常类型 变量名
多个异常的捕获(多个catch),如果多个异常出现继承关系,则需要将超类放在下方。
finally
: 一定会执行的代码段(在return、throw之前)
像数据库连接、输入输出流、网络编程中的Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放,此时的资源释放,就需要声明在finally中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| class Demo { int div(int a,int b) throws ArithmeticException,ArrayIndexOutOfBoundsException { int []arr = new int [a]; System.out.println(arr[4]); return a/b; } } class ExceptionDemo { public static void main(String[]args) { Demo d = new Demo(); try { int x = d.div(4,0); System.out.println("x="+x); } catch (ArithmeticException e) { System.out.println(e.toString()); } catch (ArrayIndexOutOfBoundsException e) { System.out.println(e.toString()); } catch (Exception e) { System.out.println(e.toString()); } System.out.println("Over"); } }
|
异常抛出
throws
通常在一个方法(类)的声明处通过 throws
声明方法(类)可能拋出的异常信息
throw
表示抛出一个异常类的对象,生成异常对象的过程,声明在方法体内
throws到最后,在main方法中需要try-catch捕获异常,否则报错。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class ExceptionTest2 {
public static void main(String[] args){ method3(); }
@Test public static void method3(){ try{ method2(); }catch (IOException e){ e.printStackTrace(); } }
@Test public static void method2() throws IOException{ method1(); }
@Test public static void method1() throws FileNotFoundException, IOException { File file = new File("hello.txt"); FileInputStream fis = new FileInputStream(file);
int data = fis.read(); while(data != -1){ System.out.print((char)data); data = fis.read(); } fis.close(); } }
|
如果父类中被重写的方法没有throws方法处理异常,则子类重写的方法也不能使用throws;
子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class OverrideTest { public static void main(String[] args) { OverrideTest test = new OverrideTest(); test.display(new Subclass());
}
public void display(SuperClass s){ try { s.method(); } catch (IOException e) { e.printStackTrace(); } }
}
class SuperClass{
public void method() throws IOException {
} }
class Subclass extends SuperClass{ @Override public void method() throws FileNotFoundException {
} }
|
自定义异常类
- 继承于现的异常结构:
RuntimeException
、Exception
- 提供全局常量:
serialVersionUID
- 提供重载的构造器
1 2 3 4 5 6 7 8 9 10 11 12
| public class EcDef extends Exception{ static final long serialVersionUID = -70348971455766939L;
public EcDef(){
}
public EcDef(String msg){ super(msg); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class EcmDef { public static void main(String[] args) { try{ int i = Integer.parseInt(args[0]); int j = Integer.parseInt(args[1]); int result = ecm(i, j); System.out.println(result); }catch (NumberFormatException e){ System.out.println("数据类型不一致!"); }catch(ArrayIndexOutOfBoundsException e){ System.out.println("缺少命令行参数!"); }catch(ArithmeticException e){ System.out.println("除0"); }catch(EcDef e){ System.out.println(e.getMessage()); } }
public static int ecm(int i, int j) throws EcDef{ if(i < 0 || j < 0){ throw new EcDef("分子或分母为负数了!"); } return i/j; } }
|