异 常
--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;
}
}
