零基础Java第二十二期:异常(二)
目录
一、异常的捕获
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("密码错误");
}
}
}