个人关于异常的小笔记

一、什么是异常

什么是异常,java提供异常处理机制有什么用?

程序在执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常。

无论是错误还是异常都是可抛出的,只要错误发生,java程序只有一个结果那就是终止程序的执行,退出jvm。

错误是不能够处理的

java语言是很完善的语言,提供了异常的处理方式,程序在执行过程中出现了不正常情况java把该异常信息打印输出到控制台,供程序员参考。程序员看到异常信息之后,可以对程序进行修改,让程序更加的健壮。

总结:

什么是异常:程序执行过程中的不正常情况。

异常的作用:增强程序的健壮性。

异常中的关键字:try、catch、finally、throws、throw

try、catch、finally:异常捕捉

throws:在方法声明位置上使用,表示上报异常信息给调用者。

throw:手动抛出异常。

二、异常的存在形式

在java语言中异常是以什么形式存在的呢?

public class Exception {
    public static void main(String[] args) {
        //通过异常“实例化”异常对象
        NumberFormatException nfe = new NumberFormatException("数字格式化异常!");
//        java.lang.NumberFormatException:数字格式化异常发生了!
        System.out.println(nfe);
        //通过异常类创建异常对象
        NullPointerException npe = new NullPointerException("空指针异常发生了!");
//        java.lang.NullPointerException:空指针异常发生了!
        System.out.println(npe);
    }
}

通过以上代码我们了解到了:

1、异常在java中以类的形式存在,每一个异常都可以创建异常对象。

2、在JVM观察到异常信息后,会new异常对象。

异常分为编译时异常(ExceptionSubClass)与运行时异常 (RuntimeException)

编译时异常(ExceptionSubClass):所有Exception的直接子类,都叫做编译时异常。编译时异常是在编译阶段发生的吗?不是。编译时异常是表示必须在编写程序的时候预先对这种异常进行处理,如果不处理编译器报错。(发生概率较低)

运行时异常 (RuntimeException):所有的RuntimeException及子类都属于运行时异常。运行时异常在编写程序阶段,你可以选择处理,也可以不处理。(发生概率较高)

编译时异常和运行时异常,都是发生在运行阶段。编译阶段异常是不会发生的。

编译时异常因为什么而得名 ?

因为编译时异常必须在编译(编写) 阶段预先处理,如果不处理编译器报错,因此得名。

所有异常都是在运行阶段发生的。因为只有程序运行阶段才可以new对象。

因为异常的发生就是new异常对象。

三、异常处理的两种方式

一、在方法声明的位置上,使用throws关键字,抛给上一级

(谁调用我,我就抛给谁。抛给上一级。)

二、使用try..catch语句进行异常的捕捉。

(这件事发生了,谁也不知道,因为我给抓住了)

思考:

异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常同样有两种方式。

注意:

java中异常发生之后如果一直上抛,最终抛给了main方法,main方法继续向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果。终止java程序的执行。

关于编译时处理异常示例:

public class Exception {
    public static void main(String[] args) {
        // main万法中调用doSome()方法
        // 因为doSome()方法声明位置上有:throws ClassNotFoundException我们在调用doSome()方法的时候必须对这种异常进行预先的处理。
        // 如果不处理,编译器就报错。
        // 编译器报错信息: Unhandled exception: java.Lang.CLassNotFoundException
        doSome();
    }
​
    /**
     *doSome方法在方法声明的位置上使用了:throws ClassNotFoundException
     * 这个代码表示doSome()方法在执行过程中,有可能会出现CLassNotFoundException异常。
     * 叫做类没找到异常。这个异常直接父类是:Exception,所以CLassNotFoundException属于编译时异常
     * @throws ClassNotFoundException
     */
    public static void doSome () throws ClassNotFoundException{
        System.out.println("doSome!!!!");
    }
}

处理方法1、在方法声明的位置上继续使用: throws,来完成异常的继续上抛。抛给调用者。

public class Exception {
    public static void main(String[] args) throws ClassNotFoundException{
        doSome();
    }
    public static void doSome () throws ClassNotFoundException{
        System.out.println("doSome!!!!");
    }
}

处理方法2、try...catch进行捕捉。

public class Exception {
    public static void main(String[] args) {
        try {
            doSome();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    public static void doSome () throws ClassNotFoundException{
        System.out.println("doSome!!!!");
    }
}

注意:只要异常没有捕捉,采用上报的方式,此方法的后续代码不会执行。另外需要注意,try语句块中的某一行出现异常,该行后面的代码不会执行。try..catch捕捉异常之后,后续代码可以执行。

一个方法体中的代码出现异常之后,如果继续上报的话,此方法结束

四、try...catch

1、catch后面的小括号中的类型可以是具体的异常类型,也可以是该异常类型的父类型

2、catch 可以写多个。建议catch的时候,精确的一个一个处理。这样有利于程序的调试。

3、catch写多个的时候,从上到下,必须遵守从小到大。

public class Exception {
    public static void main(String[] args) {
        try{
            FileInputStream fis = new FileInputStream("MySQL");
        } catch (IOException e){
            System.out.println("文件报错了");
        } catch (FileNotFoundException e){
            System.out.println("文件不存在");
            //这里会报错,因为IOException的范围比FileNotFoundException的范围大,但异常的书写顺序必须遵守从小到大。
        }
    }
}

五、try...catch中的finally子语句

在finally子句中的代码是最后执行的,并且是一定会执行的,即使try 语句块中的代码出现了异常。 finally 子句必须和try一起出现,不能单独编写。

import java.io.FileInputStream;
import java.io.IOException;
​
public class Exception {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try{
            //创建输入流对象
            fis = new FileInputStream("D:\\Java笔记\\java中的随机数.md");
            String s = null;
            //这里出现空指针异常
            s.toString();
            System.out.println("Hellow! World");
        } catch (IOException | NullPointerException e){
            e.printStackTrace();
            System.out.println("这里");
        } finally {
            //finally代码是一定会执行的,即使try语句块出现了异常
            if (fis != null){
                System.out.println("未访问成功");
                try{
                    //流使用完要关闭,因为流会占用资源
                    fis.close();
                } catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
}

六、final、finally、 finalize之间的区别

final关键字:

final修饰的类无法继承

final修饰的方法无法覆盖

final修饰的变量不能重新赋值

finally关键字:

和try一起联合使用

finally语句块中的代码是必须执行的

finalize标识符

是一个object类中的方法名

这个方法是由垃圾回收器GC负者调用的

七、如何自定义异常

1、编写一个类继承Exception或RuntimeException。

2、提供两个构造方法,一个无参数的,一个带有String参数的。

//编写一个类继承Exception
public class MyException extends Exception{
    //提供两个构造方法,一个无参数的,一个带有String参数的
    public MyException() {
    }
    public MyException(String message) {
        super(message);
    }
}

//编写一个类继承RuntimeException
public class MyRuntimeException extends RuntimeException{
    //提供两个构造方法,一个无参数的,一个带有String参数的
    public MyRuntimeException() {
    }
​
    public MyRuntimeException(String message) {
        super(message);
    }
}

public class ExceptionTest {
    public static void main(String[] args) {
        //只new了异常对象没有手动抛出
        MyException ME = new MyException("这是一个编译时异常");
        MyRuntimeException MRE = new MyRuntimeException("这是一个运行时异常");
        //打印异常堆信息
        MRE.printStackTrace();
        ME.printStackTrace();
    }
}

八、异常作业练习

01、程序开始执行时,提示用户输入“用户名”和“密码"信息。

注册时用户名要求长度在[6-14]之间,小于或者大于都表示异常。

完成注册的方法放到一个单独的类中。

异常类自定义即可。

public void register(String username, String password){ //这个方法中完成注册 }

编写main方法,在main方法中接收用户输入的信息,在main方法中调用UserService的register方法完成注册。

解答:

UserService类

public class UserService {
    String name;
    String password;
​
    /**
     *
     * @param username 用户名
     * @param password 密码
     * @throws MyException 当用户名为null,或者用户名长度小于6,或者长度大于14,都会出现该异常!
     */
    public void register(String username, String password) throws MyException{
        //判断用户名是否合法,长度必须在6~14之间
        if(null == username || username.length() < 6 || username.length() > 12){
            throw new MyException("对不起您输入的用户名不合法");
        } else {
            //程序能到这说明用户名合法
            System.out.println("恭喜您注册成功");
        }
    }
}

MyException类

/**
 * 自定义异常
 */
public class MyException extends Exception{
    public MyException(){
​
    }
    public MyException(String message){
        super(message);
    }
}

RegisterTest类

import java.util.Scanner;
​
public class RegisterTest {
    public static void main(String[] args) {
        //接受用户键盘输入
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入您的用户名");
        String admin = sc.next();
        System.out.println("请输入您的密码");
        String password = sc.next();
        //创建UserService对象
        UserService rt = new UserService();
        try {
            rt.register(admin, password);
        } catch (MyException e) {
            //获取异常的信息
            System.out.println(e.getMessage());
        }
    }
}

02、写一个类Army,代表一支军队,这个类有一个属性weapon数组w(用来存储该军队所拥有的所有武器)

该类还提供一个构造方法,在构造方法里通过传一个int类型的参数来限定该类所能拥有的最大武器数量,

该类还提供一个方法addweapon(Weapon wa),表示把参数wa所代表的武器加入到数组w中。

在这个类中还定义两个方法attackAll()让w数组中的所有武器攻击;

以及moveAll( )让w数组中的所有可移动的武器移动。

写一个主方法去测试以上程序。

提示:

Weapon是一个父类。应该有很多子武器。

这些子武器应该有一些是可移动的,有一些是可攻击的。

解答:

Army类

public class Army {
    Weapon[] w;
​
    /**
     * 编写有参构造方法来动态初始化w数组的长度
     * @param num 表示编写的数组的长度
     */
    public Army(int num){
        this.w = new Weapon[num];
    }
​
    /**
     * 编写方法来添加武器(将武器添加到w数组中)
     * @param wa 添加的武器的引用
     * @throws StackFull 这是一个添加达到最大值的异常,如果达到最大值则触发异常
     */
    public void addWeapon(Weapon wa) throws StackFull{
        for(int i = 0; i <= w.length - 1; i++){
            //if语句如果进行遍历查看后有空位的话,就将新武器放入到数组中
            if(null == w[i]){
                w[i] = wa;
                return;
            }
        }
        //如果程序执行到此处,代表武器没有添加成功。此时发生异常。
        throw new StackFull("对不起武器库已满");
    }
​
    /**
     * 移动武器的方法
     */
    public void moveAll(){
        for (int i = 0; i < w.length; i++){
            //用instanceof关键字判断Moveable是否为w数组的子类如果是则为true
            if (w[i] instanceof Moveable){
                //向下强转型
                Moveable move = (Moveable) w[i];
                move.Move();
            }
        }
    }
​
    /**
     * 武器的攻击方法
     */
    public void attackAll(){
        for (int i = 0; i < w.length; i++){
            //用instanceof关键字判断Shootable是否为w数组的子类如果是则为true
            if (w[i] instanceof Shootable){
                //向下强转
                Shootable shoot = (Shootable) w[i];
                shoot.Shoot();
            }
        }
    }
}

自定义异常StackFull类

public class StackFull extends Exception{
    public StackFull(){}
    public StackFull(String message){
        super(message);
    }
}

武器类Tank

public class Tank extends Weapon implements Moveable, Shootable{
    @Override
    public void Move() {
        System.out.println("坦克移动了");
    }
​
    @Override
    public void Shoot() {
        System.out.println("坦克射击了");
    }
}

武器类TripleA

public class TripleA extends Weapon implements Shootable{
    @Override
    public void Shoot() {
        System.out.println("高射炮开始射击!");
    }
}

武器类SST

public class SST extends Weapon implements Moveable{
    @Override
    public void Move() {
        System.out.println("运输机在移动");
    }
}

接口Moveable

public interface Moveable {
    void Move();
}

接口Shootable

public interface Shootable {
    void Shoot();
}

武器库类Weapon

public class Weapon {
}

测试类Test

public class Test {
    public static void main(String[] args) {
        //创建一个长度为3的武器库
        Army army = new Army(3);
        //初始化所有的武器对象
        Tank tank = new Tank();
        TripleA tripleA = new TripleA();
        SST sst = new SST();
        SST sst1 = new SST();
        try {
            //将武器放入武器库中
            army.addWeapon(tank);
            army.addWeapon(tripleA);
            army.addWeapon(sst);
            army.addWeapon(sst1);
        } catch (StackFull e) {
            //打印出异常信息
            System.out.println(e.getMessage());
        }
        //调用方法使武器移动与攻击
        army.moveAll();
        army.attackAll();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值