异 常

--java.lang.Throwable:

Throwable:可抛出的。

|--Error:错误,一般情况下,不编写针对性的代码进行处理,通常是 jvm 发生的,需要对程 序进行修正。
|--Exception:异常,可以有针对性的处理方式

这个体系中的所有类和对象都具备一个独有的特点;就是可抛性。

可抛性的体现:就是这个体系中的类和对象都可以被 throws 和 throw 两个关键字所操作。

throw 与 throws 区别:

throws 是用来声明一个方法可能抛出的所有异常信息,而 throw 则是指抛出的一个具体的异常 类型。此外 throws 是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理。 throw 用于抛出异常对象,后面跟的是异常对象;throw 用在函数内。 throws 用于抛出异常类,后面跟的异常类名,可以跟多个,用逗号隔开。throws 用在函数上。

throws 格式:方法名(参数)throws 异常类 1,异常类 2,..... throw:就是自己进行异常处理,处理的时候有两种方式,要么自己捕获异常(也就是 try catch 进行捕捉),要么声明抛出一个异常(就是 throws 异常~~)。

Throws抛出异常的规则:

1: 如果是不可查异常(unchecked exception),即Error、RuntimeException或它们的子类,那么可以不使用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。 2: 如果一个方法可能出现可查异常(checked exception),要么用try-catch语句捕获,要么用throws子句声明将它抛出,否则会导致编译错误。 3: 只有当抛出了异常时,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出。 4: 调用方法必须遵循任何可查异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。

例子1

package com.softeem.wolf.exception;
 
/**
 * Created by 苍狼
 * Time on 2021-10-28
 */
public class ExceptionTest02 {
    public static void main(String[] args) {
        System.out.println("程序执行开始的地方...");
        try{
            method1();
        } catch (ArithmeticException e){
            System.out.println("我来解决这个问题了...");
        } finally {
            System.out.println("我是main中finally执行的代码.....");
        }
 
        System.out.println("main方法执行的最后一个方法....");
    }
 
    public static void method1() throws ArithmeticException{
        int a = 10;
        int b = 0;
        System.out.println("进入异常的开头....");
        System.out.println(a/b);
        System.out.println("try结束所执行的.....");
        System.out.println("正常执行");
        System.out.println("我是method1()最后执行的代码....");
    }
}

结果

程序执行开始的地方...
进入异常的开头....
我来解决这个问题了...
我是main中finally执行的代码.....
main方法执行的最后一个方法....

例子2

package com.softeem.wolf.exception;
 
/**
 * Created by 苍狼
 * Time on 2021-10-28
 */
public class ExceptionTest02 {
    public static void main(String[] args) throws ArithmeticException{
        System.out.println("程序执行开始的地方...");
        try{
            method1();
        } finally {
            System.out.println("我是main中finally执行的代码.....");
        }
 
        System.out.println("main方法执行的最后一个方法....");
    }
 
    public static void method1() throws ArithmeticException{
        int a = 10;
        int b = 0;
        System.out.println("进入异常的开头....");
        System.out.println(a/b);
        System.out.println("try结束所执行的.....");
        System.out.println("正常执行");
        System.out.println("我是method1()最后执行的代码....");
    }
}

结果

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.softeem.wolf.exception.ExceptionTest02.method1(ExceptionTest02.java:23)
    at com.softeem.wolf.exception.ExceptionTest02.main(ExceptionTest02.java:11)
程序执行开始的地方...
进入异常的开头....
我是main中finally执行的代码.....
Throws抛出异常的规则:

throw总是出现在方法体中,用来抛出一个Throwable类型的异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。

我们知道,异常是异常类的实例对象,我们可以创建异常类的实例对象通过throw语句抛出。该语句的语法格式为:

throw new exceptionname;

例如抛出一个IOException类的异常对象:

throw new IOException;

要注意的是,throw 抛出的只能够是可抛出类Throwable 或者其子类的实例对象。下面的操作是错误的,因为String 不是Throwable 类的子类。

throw new String("exception");

如果抛出了可查异常,则还应该在方法头部声明方法可能抛出的异常类型。该方法的调用者也必须检查处理抛出的异常。

如果所有方法都层层上抛获取的异常,最终JVM会进行处理,处理也很简单,就是打印异常消息和堆栈信息。如果抛出的是Error或RuntimeException,则该方法的调用者可选择处理该异常。

throw的示例

package com.softeem.wolf.exception;
 
/**
 * Created by 比特聚客
 * Time on 2022-07-01
 */
public class ExceptionTest02 {
    public static void main(String[] args) throws ArithmeticException{
        System.out.println("程序执行开始的地方...");
        try{
            method1();
            //当这里有异常发生时, 后面的代码也都不会执行, 这里指的就是method1()方法有异常
            //System.out.println("这里的代码不会在执行了...");
        } catch (ArithmeticException e){
            System.out.println("解决异常");
        } finally{
            System.out.println("我是main中finally执行的代码.....");
        }
        System.out.println("main方法执行的最后一个方法....");
    }
 
    public static void method1(){
        int a = 10;
        int b = 0;
        System.out.println("进入异常的开头....");
        throw new ArithmeticException();
        //System.out.println("这里不能再写程序了....");
    }
}

程序执行开始的地方...
进入异常的开头....
解决异常
我是main中finally执行的代码.....
main方法执行的最后一个方法....

代码分析: main方法开始执行, 执行开头语句, 然后调用method1()方法, 进入method1()方法, 但执行到throw new ArithmeticException(); 退出执行, 这里注意(throw new ArithmeticException(); 后面不能再继续写程序了, 会报错), 然后跳到main方法, main方法对它进行了解决, main方法的程序正常执行.

处理方式有两种:1、捕捉;2、抛出。

对于捕捉:java 有针对性的语句块进行处理。

try { 
 需要被检测的代码; 
} 
catch(异常类 变量名){ 
 异常处理代码; 
} 
fianlly{ 
 一定会执行的代码; 
}

定义异常处理时,什么时候定义 try,什么时候定义 throws 呢?
功能内部如果出现异常,如果内部可以处理,就用 try;
如果功能内部处理不了,就必须声明出来,让调用者处理。使用 throws 抛出,交给调用者处理。 谁调用了这个功能谁就是调用者;

自定义异常的步骤:

1:定义一个子类继承 Exception 或 RuntimeException,让该类具备可抛性(既可以使用 throw 和 throws 去调用此类)。
2:通过 throw 或者 throws 进行操作。

异常的转换思想:当出现的异常是调用者处理不了的,就需要将此异常转换为一个调用者可以处 理的异常抛出。

try catch finally 的几种结合方式:
try {

}
catch(Exception ex) {

}
finally {

}
try{

}
catch(Exception ex) {

}
try {

}
finally {

}

这种情况,如果出现异常,并不处理,但是资源一定关闭,所以 try finally 集合只为关闭资源。
记住:finally 很有用,主要用户关闭资源。无论是否发生异常,资源都必须进行关闭。
System.exit(0); //退出 jvm,只有这种情况 finally 不执行。

注意:

如果父类或者接口中的方法没有抛出过异常,那么子类是不可以抛出异常的,如果子类的覆 盖的方法中出现了异常,只能 try 不能 throws。
如果这个异常子类无法处理,已经影响了子类方法的具体运算,这时可以在子类方法中,通 过 throw 抛出 RuntimeException 异常或者其子类,这样,子类的方法上是不需要 throws 声明的。

异常练习1

AgeExeption
public class AgeException extends RuntimeException{
   public AgeException() {
   }

   public AgeException(String message) {
       super(message);
   }
}


SexException
public class SexException extends RuntimeException{
   public SexException() {
   }

   public SexException(String message) {
       super(message);
   }
}
Student
public class Student {
   private String name;
   private String sex;
   private int age;


   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public String getSex() {
       return sex;
   }

   public void setSex(String sex) {
       if(!sex.equals("男")&&!sex.equals("女")){
           throw new SexException("性别异常");
       }
       this.sex = sex;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       if(age<15||age>50) {
           throw new AgeException("年龄异常");
       }
       this.age = age;
   }
}

测试类
public class Test {
   public static void main(String[] args) {
       Student student = new Student();
       try{
           student.setAge(100);
       } catch (AgeException e) {
           System.out.println(e.getMessage());
       }
   }
}

异常练习2

  • 写一个方法实现用户登录,传入用户名和密码
  • 如果用户名错误,就抛出自定义登录异常(LoginException),异常信息为用户名不存在。
  • 如果密码错了就也抛出登录异常,异常信息为密码错误
  • 如果用户名和密码都对了,输出: 欢迎xxx

说明:正确用户名和密码都是admin

//编译时异常
public class LoginException extends Exception {
   public LoginException() {
       super();
   }

   public LoginException(String message) {
       // 一定要调用父类的构造方法
       super(message);
   }
}

public class TestDemo {
   // a)提供一个用于登陆的方法login(String name,String pwd),在放方法中
   public static void login(String name, String pwd) throws LoginException {
       // i.如果用户名错误,就抛出自定义登陆异常(LoginException),异常信息为用户名不存在
       if (!"admin".equals(name)) {
           throw new LoginException("用户名:" + name + "不存在");
       }
       // ii.如果密码错了就也抛出登陆异常,异常信息为密码错误.
       if (!"admin".equals(pwd)) {
           throw new LoginException("密码错误");
       }
       // iii.如果能来到下面,就说明用户和密码都是对的,输出: 欢迎xxx
       System.out.println("欢迎" + name);
   }

   public static void main(String[] args) {
       try {
           // i.调用login方法,传入错误用户名,运行程序,报运行时异常,然后注释这行代码
            login("admin", "123456");
           
           // ii.调用login方法,传入正确用户名,错误的命名,运行程序,报运行时异常,然后注释这行代码
           // login("admin", "123");
           // iii.调用login方法,传入正确的用户名和密码
          //ogin("admin", "admin");
       } catch (LoginException e) {
           e.printStackTrace();
       }
   }
}

异常练习3

模拟注册用户,按照以下要求实现相关功能:
  • 提示用户在控制台输入手机号码,并接收
  • 判断该手机号码是否是11位,是否都是数字,其余可以不做判断,如果不符合任意一项,则提示用户"注册用户失败"
  • 将手机号的后四位获取出来输出到控制台上

提示:使用异常解决验证手机号是数字的问题

public class Test {
   public static void main(String[] args) {
       //接收键盘录入的手机号
       System.out.println("请录入手机号:");
       String phone = new Scanner(System.in).next();

       //手机号是否为11位、手机号是否为纯数字
       if(phone!=null && phone.length()==11 && validate(phone)){

           System.out.println("手机号末尾4位数字:"+phone.substring(7));

       }else {
           System.out.println("注册用户失败!");
       }
   }

   //验证手机号是否为纯数字
   public static boolean validate(String phone) {
       try {
           //String -> long
           long num = Long.parseLong(phone);
           /*如果字符串不是纯数字,转换为long类型时,会引发异常*/
       } catch (Exception e) {
           //String转long类型发生异常时,不是数字,就返回false
           return false;
       }
       //当String转long类型没有任何问题,说明是数字,返回true
       return true;
   }
}
Last Updated 10/25/2025, 5:44:13 AM