有关异常的处理、捕获、抛出、自定义
异常处理
什么时候使用异常
Throwable
Error 错误 无法专门处理
Exception 异常
受检异常 编译的时候,必须处理的异常,可以使用try-catch捕获异常,也可以通过throws在方法中声明抛出异常
非受检异常(运行时异常)
捕获异常 更重要
try-catch-finally
catch可以有多个,catch和finally至少存在一个
如果代码出现异常,异常代码后的代码不再执行,直接跳转到对应的catch代码块进行操作
不管代码是否有异常,finally中的逻辑都会执行,哪怕使用了return (使用System.exit() 退出程序,finally中代码不会执行)
package com.qfedu.exception; public class App2 { public static void main(String[] args) { // TODO Auto-generated method stub int a = 10; int b = 0; // 针对可能出异常的代码使用try包起来 // 如果出异常,使用catch捕获异常 // 出现异常后,出现异常的代码,后续的代码不会执行,跳转到catch语句块,执行其中的代码 // 如果try括住的代码正常执行,不会进行catch代码块 // 可以写多个catch 捕获不同的异常,如果代码发生异常,和catch后的异常进行比对, // 符合哪个具体的异常就进入哪个catch代码块中 // 针对需要具体处理的异常,通过在catch后这是具体的异常可以捕获,但是我们不可能预见所以可能的异常, // 这时,就可以使用catch捕获Exception类型的异常,防止遗漏 // 注意:父类的Exception异常一定要放在所有catch代码块的最后 // 实际开发中,一般报异常了,会将异常信息记录到日志系统 try { int c = a / b; System.out.println(c); // String str = null; String str = "hello"; System.out.println(str.length()); // ClassCastException Object o = "hello"; Integer i = (Integer)o; } catch(ArithmeticException e) { System.out.println("除0错误"); } catch(NullPointerException e) { System.out.println("空指针异常"); } catch(Exception e) { // 打印异常的栈跟踪信息 e.printStackTrace(); System.out.println("未知异常"); } } }
package com.qfedu.exception; public class App4 { public static void main(String[] args) { // TODO Auto-generated method stub // 不管代码是否异常,最终都会执行finally代码块中逻辑 // 在try或catch的代码块中,即使使用了return,finally代码块中的逻辑也会执行 // 使用System.exit()情况下,退出整个程序,finally中逻辑不会执行 try { int a = 10 / 3; System.out.println(a); // return; // 退出程序 // System.exit(0); } catch (Exception e) { System.out.println(e.getMessage()); return; } finally { System.out.println("finally"); } // 了解 // 语法上catch可以不写,如果不写,无法捕获异常,异常就会自动往上层抛,本例中,抛给jvm进行处理 try { int b = 10 / 0; } finally { System.out.println("finally2"); } } }
抛出异常
声明方法时,通过throws指定抛出的异常
在方法中,通过throw抛出异常
package com.qfedu.throwes; public class App { public static void main(String[] args) { // TODO Auto-generated method stub // main方法中调用test1() 方法, // test1()没有捕获异常并处理,当test1()发生异常时,将异常对象往上抛 // 本例中,test1()中发生的异常抛给main()方法 // main()中也没有捕获异常进行处理,main()方法将异常继续往上抛,最终抛给jvm,由jvm处理异常 // test1(); try { // test2(); test3(); } catch(ArithmeticException e) { System.out.println(e.getMessage()); } catch(Exception e) { System.out.println("未知异常"); } } public static void test1() { int a = 10 / 0; System.out.println(a); } // 在方法中,声明需要抛出的异常,针对受检异常相对多些 public static void test2 () throws ArithmeticException { // int a = 10 / 0; // System.out.println(a); String str = null; System.out.println(str.length()); } // 在方法中通过throw 抛出异常 ,针对自定义异常,针对需要改变运行流程的情况,使用相对多些 public static void test3() { try { int a = 10 / 0; } catch(ArithmeticException e) { throw e; } } }
自定义异常
继承Exception或者RuntimeException
一般结合throw一起使用,通过自定义异常,可以实现终止业务逻辑的功能
package com.qfedu.customerex; // 如果继承Exception类,在其他地方创建并抛出异常类对象,默认会报错(当成受检异常进行处理) // 个人建议,继承RuntimeException public class LoginException extends RuntimeException{ // 针对异常信息的编码值 private int code; // 异常信息 private String msg; public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public LoginException(int code, String msg) { super(msg); this.code = code; this.msg = msg; } }
package com.qfedu.customerex; public class App2 { public static void main(String[] args) { // TODO Auto-generated method stub try { login(null, "1235"); System.out.println("合法用户"); } catch (LoginException e) { // System.out.println(e.getMsg()); System.out.println(e.getMessage()); } } // 借助抛异常的方式,终止程序的后续逻辑 public static void login(String name, String password) { if(name == null || name.isEmpty()) { // 创建了一个自定义异常的对象,然后通过throw抛出 throw new LoginException(101, "请输入用户名"); } if(password == null || password.isEmpty()) { throw new LoginException(102, "请输入密码"); } if(!(name.equals("admin") && password.equals("123"))) { throw new LoginException(103, "用户名或者密码错误"); } } }