目录
一、异常的捕获
1.1. 多个异常,一次捕获
1.2. 异常之间的父子关系
1.3. finally
二、自定义异常
一、异常的捕获
1.1. 多个异常,一次捕获
由于Exception类是所有异常类的父类,因此可以用这个类型表示捕捉所有异常。也就是说,编译器会告诉你有风险,但就是不告诉你风险是啥。这种写法呢,我们不推荐
public class Main { public static void main(String[] args) { int[] arr = {1, 2, 3}; try { System.out.println("before"); arr = null; System.out.println(arr[100]); System.out.println("after"); } catch (Exception e) { e.printStackTrace(); } System.out.println("after try catch"); }}
1.2. 异常之间的父子关系
如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误。来看下面的代码,因为NullPointerExceptions是RuntimeException的子类,在运行的时候,直接会被第一个catch所捕获,第二个异常就相当于没写。
public class Main { public static void main(String[] args) { try { throw new NullPointerException(); } catch (RuntimeException e) { System.out.println("捕获运行时异常"); e.printStackTrace(); } catch (NullPointerException e) {//Exception 'java.lang.NullPointerException' has already been caught System.out.println("捕获空指针异常"); } }}
1.3. finally
在写程序时,有些特定的代码,不论程序是否发生异常,都需要执行,比如程序中打开的资源:网络连接、数据库 连接、IO流等,在程序正常或者异常退出时,必须要对资源进进行回收。另外,因为异常会引发程序的跳转,可能 导致有些语句执行不到,finally就是用来解决这个问题的。
语法规则:
try{ //可能发生的异常;} catch(异常类型 e){ //对捕获的异常进行处理;} finally{ //此处的语句无论是否发生异常,都会被执行到;}
我们来用下面的代码来举例
public class Main { public static void main(String[] args) { try { //执行一些逻辑完毕之后,可能释放一些资源; //释放资源的操作可能会抛出一些异常,为了避免异常导致程序崩溃,可以使用try-catch if (cond1) { return; } if (cond2) { throw new Exception("某些未知异常"); } release(); } } private static void release() { }}
如果说资源没有及时释放,那么后期别人使用的时候就会很糟糕。针对这种情况,我们要在第一个if里面也调用一下release,或者抛出异常的时候,我们再后面也加上一个catch来捕获我们抛出的异常。
public class Main { public static void main(String[] args) { try { //执行一些逻辑完毕之后,可能释放一些资源; //释放资源的操作可能会抛出一些异常,为了避免异常导致程序崩溃,可以使用try-catch if (cond1) { release(); return; } if (cond2) { throw new Exception("某些未知异常"); } release(); } catch (Exception e){ release(); } } private static void release() { }}
这样的方法看似可以解决问题,但是代码的可维护性比较低。比如说,我们多个人一起来写代码,一个人写了,其他人不知道需要调用或者加上其他分支。这时候我们就可以用finally解决。按照下面的代码,无论try-catch语句如何执行,都会执行finally。
public class Main { public static void main(String[] args) { try { //执行一些逻辑完毕之后,可能释放一些资源; //释放资源的操作可能会抛出一些异常,为了避免异常导致程序崩溃,可以使用try-catch //出现异常或者遇到return语句,是资源无法释放 if (cond1) { release(); return; } if (cond2) { throw new Exception("某些未知异常"); } } catch (Exception e){ }finally { release(); } } private static void release() { }}
public class Main { public static void main(String[] args) { try { //执行一些逻辑完毕之后,可能释放一些资源; //释放资源的操作可能会抛出一些异常,为了避免异常导致程序崩溃,可以使用try-catch //出现异常或者遇到return语句,是资源无法释放 int a = 1; int b = 2; if (a < b) { throw new NullPointerException("a小于b"); } } catch (Exception e){ e.printStackTrace(); }finally { release(); } } private static void release() { System.out.println("release释放资源"); }}
我们来看下面一段代码,老铁们来猜一下运行结果是多少。
public class Main { public static int func(){ try{ return 10; } catch(Exception e) { return 20; } finally { return 30; } } public static void main(String[] args) { System.out.println(func()); }}
我们可以看到结果是30,这是因为执行到try的时候,本来该返回10,但是我们一定需要执行finally语句,返回值30就会把之前的10覆盖。如果我们把try语句里面改成抛出一个异常,那么同理,catch语句的返回值20也会被30覆盖。
二、自定义异常
Java 中虽然已经内置了丰富的异常类, 但是并不能完全表示实际开发中所遇到的一些异常,此时就需要维护符合我 们实际情况的异常结构。实际中,经常需要根据业务类型自定义异常。比如我们在进行登陆的时候,用户输错了密码出现的异常或者是网络不好出现的掉线异常。
那我们如何自定义异常呢?异常本质是类,我们自己写一个类,让这个类继承Java标准库里面的异常(如Exception、RuntimeException)。下面我们来讲一下登录系统。
首先我们先来设置登录系统
//设置登录系统class Login{ private String username = "crane"; private String password = "24170"; public void login(String username,String password){ if (!username.equals(this.username)) { System.out.println("用户名错误!"); return; } if(!password.equals(this.password)){ System.out.println("密码错误!"); } System.out.println("登录成功"); }}
我们再定义异常类。
//创建异常类class UsernameException extends Exception{}class PasswordException extends Exception {}
下面再对异常进行抛出
public void login(String username,String password) throws UsernameException,PasswordException{ if (!username.equals(this.username)) { throw new UsernameException(); } if(!password.equals(this.password)){ throw new PasswordException(); } System.out.println("登录成功"); }}
以下是完整代码:
//创建异常类class UsernameException extends Exception{}class PasswordException extends Exception {}//设置登录系统class Login{ private String username = "crane"; private String password = "24170"; public void login(String username,String password) throws UsernameException,PasswordException{ if (!username.equals(this.username)) { throw new UsernameException(); } if(!password.equals(this.password)){ throw new PasswordException(); } System.out.println("登录成功"); }}public class Main { public static void main(String[] args) { Login lg = new Login(); try { lg.login("night", "123456"); } catch (UsernameException e){ System.out.println("用户名错误"); } catch (PasswordException e){ System.out.println("密码错误"); } }}