异常?你确定都掌握了吗?直接把它拿捏了

目录

异常

1.1 基本概念

1.2 编译时异常和运行时异常

1.3 对异常的处理

1.4 深入try...catch异常

1.4.1 try...catch的格式

1.4.2 关于try...catch

1.4.3 JDK新特性

1.5 上报和捕捉如何选择

1.6 getMessage()方法和printStackTrace()方法

1.7 finally子句

1.8 final、finally和finalize的区别

1.9 自定义异常

1.9.1 自定义异常的步骤

1.9.2 栈内存程序的改进

1.10 子类重写的方法抛出编译异常只能更少/小不能更多


异常

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

以下程序执行过程中发生了不正常的现象,而这种不正常的情况称为异常

java把异常信息打印到控制台,供程序员参考,程序员看到异常信息之后可以对其进行修改,使程序更加健壮

public static int divide(int a,int b){
    try{
        int c = a / b;
        //程序执行到此处表示以上代码没有发生异常,表示执行成功
        return 1;
    }catch(Exception e){
        //程序执行到此处表示以上程序出现了异常
        //表示执行失败
        return 0;
    }
}

2)异常信息如何产生的?

JVM虚拟机在处理到异常的时候会new一个异常对象,并且JVM将new的异常对象抛出,打印输出到控制台了;

1.1 基本概念

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

编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错;

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

1.2 编译时异常和运行时异常

编译时异常(受检异常、受控异常)发生概率较高,需要在运行之前对其进行预处理;

运行时异常(未受检异常、非受控异常)发生概率较低,运行之前不需要进行预处理;

1.3 对异常的处理

1)在方法声明的位置上,使用throws关键字;【抛给上一级,谁调用我,我就抛给谁;抛给上一级同样有两种方式】

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

2)使用try..cathch语句进行异常的捕捉;【这件事发生了谁也不知道,因为我给抓住了】

public class Sttt{
    public static void main(String[] args) {
        System.out.println(100/0);
//程序执行到此发生ArithmeticException异常,底层new了一个ArithmeticException异常对象,然后抛给了main方法,main方法最后无法处理,将异常抛给了JVM,JVM最终终止了程序的执行
        System.out.println("helloworld");
    }
}
//ArithmeticException 继承 RuntimeException,属于运行时异常,在编写程序时不需要对这种异常进行预先处理
public class Sttt{
    public static void main(String[] args)throws ClassNotFoundException//处理方式1 {
        doSome();//因为doSome方法()的声明位置上有 throws ClassNotFoundException 所以在调用的时候要对这种异常进行预先的处理,不处理,编译器会报错
    
        //Alt + 回车 可以生成
        
        try {
            doSome();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }//处理方式2
    }
}
public static void doSome() throws ClassNotFoundException{
//ClassNotFoundException类没找到异常,父类是Exception,所以属于编译时异常
}

3)在抛出异常时,可以抛出该异常的父对象

throws后面可以写多个异常,并且用逗号隔开;

一般不建议在main方法上使用throws,因为这个异常如果真的发生了,一定会抛给JVM,JVM只能终止

异常处理机制的作用就是提高程序的健壮性,保证程序出现了异常也能执行,所以main方法中的异常建议是使用try...catch进行捕捉。main不要继续上抛了

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

1.4 深入try...catch异常

1.4.1 try...catch的格式

try{
    //try尝试
    m1();
}catch(FileNotFoudException e){
    //catch是捕捉异常之后走的分支
    System.out.println("文件不存在,可能路径写错了,也可能该文件被删除了");
}

1.4.2 关于try...catch

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

2、catch可以写多个,便于程序的调试,catch写多个的时候从上到下,必须遵守从小到大

1.4.3 JDK新特性

try{
    
}catch(FileNotFoundException|ArithmeticException|NullPointerException e){
​
}

1.5 上报和捕捉如何选择

如果希望调用者来处理,则选择throws上报

1.6 getMessage()方法和printStackTrace()方法

public class Sttt{
    public static void main(String[] args) {
        //这里为了测试两个方法,而new的异常对象,但是没有吧异常对象抛出,JVM认为是一个普通的java对象
        NullPointerException e =new NullPointerException("空指针异常!");
        //获取异常简单描述信息:这个信息实际上就是构造方法中的String参数
        String msg = e.getMessage();
        System.out.println(msg);
        e.printStackTrace();//打印异常信息,java后台打印异常堆栈信息的时候采用了异步线程的方式打印的
    }
}

1.7 finally子句

1)在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块的代码出现了异常,

2)finally子句必须和try一起出现,不能单独编写;

3)finally语句通常使用在完成资源的释放/关闭,因为finally语句块中的代码比较有保障,即使try语句块中的代码出现异常,finally中的代码也会正常进行

4)try语句块即使有return,那么finally也会执行,只有当System.exit(0)退出JVM时,才不会执行finally

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
​
​
public class Sttt{
    public static void main(String[] args) {
        FileInputStream fis = null;//声明位置放到try外面,这样才能在finally中使用
        try{
            FileInputStream fis = new FileInputStream("D:\java\javase");
                    //开始读文件
                    String s = null;
                    //这里空指针异常
                    s.toString();
                    //流用完需要关闭,因为流是占用资源的
                    //即使上面程序出现异常,流也必须关系
                    //放在这里有可能关不了
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }catch (NullPointerException e){
            e.printStackTrace();
        }finally {
            //流的关闭放到这里比较保险
            //finally中的代码是一定会执行的
            //即使try中出现了异常
            if(fis != null)//避免空指针异常
                try{
                    //close()方法有异常,采用捕捉的方式
                    fis.close();
                } catch(IOException e){
                    e.printStackTrace();
                }
        }
    }
}

5)面试题

java的语法规则:

方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法)

return语句一旦执行,整个方法必须结束

public class Sttt{
    public static void main(String[] args) {
​
        System.out.println(m());//结果是100
    }
    public static int m(){
        int i= 100;
        try{
            //这行代码出现在 int i = 100;的下面,所以最终结果必须是返回100
            //return 语句还必须保证是最后执行的,一旦执行,整个方法结束
            return i;
 //这里可以理解为自上而下i已经传入了return中但是还没有执行,所以后面的finally无论在return前怎么改变i的值,return i都不会改变
        }finally{
            i++;
        }
    }
}

反编译的代码

public static int m{
    int i = 100;
    int j = i;
    i++;
    return j;
}

1.8 final、finally和finalize的区别

final

final是一个关键字。表示最终的、不可变的

final int i = 100;

finally

finally也是一个关键字。和try连用,使用在异常处理机制当中

finally语句块中的代码一定会执行的

try{
​
}finally{
    
}

finalize()

finalize()是Object类的一个方法,作为方法名出现,所以finalize是标识符

finalize()方法是JVM的GC垃圾回收器负责调用

1.9 自定义异常

1.9.1 自定义异常的步骤

第一步:编写一个类继承Exception或者RubtimeException

第二步:写两个构造方法,一个无参构造方法和一个有参构造方法

注意:throw在手动抛异常的时候使用throws表示上报异常信息给调用者

public class Sttt{
    public static void main(String[] args) {
        //new了一个异常对象(没有手动抛出)
        MyException e = new MyException("用户名不能为空");
        //打印异常信息
         e.printStackTrace();
        //获取异常简单描述信息
        String msg = e.getMessage();
        System.out.println(msg);
    }
}
​
public class MyException extends Exception{
    public MyException(){
        
    }
    public MyException(String s){
        super(s);
    }
}

注册登录页面

public class Sttt{
    public static void main(String[] args) {
        UserService userService = new UserService();
        try {
            userService.register(null,"123");
        }catch (IllegalNameException e){
            System.out.println(e.getMessage());
        }
    }
}
class IllegalNameException extends Exception{
    public IllegalNameException() {
​
    }
    public IllegalNameException(String s) {
        super(s);
    }
}
class UserService {
​
    public void register(String username,String password) throws IllegalNameException {
        if(username == null||username.length()<6||username.length()>14){
            throw new IllegalNameException("用户名不合法!");
        }
        System.out.println("注册成功");
    }
}

1.9.2 栈内存程序的改进

public class Text {
    public static void main(String[] args) {
        //创建一个栈对象,初始化容量是10个
        Stack s = new Stack();
        s.push("12345ty");
        s.push(new Object());
        s.push(new Object());
        s.push(new Object());
        s.push(new Object());
        s.pop();
        s.pop();
        s.pop();
        s.pop();
        s.pop();
        s.pop();
        //可以使用for循环进行压栈和弹栈
    }
}
class Stack{
    //存储任何引用类型数据的数组
    private Object[] elements;
    //有参构造方法
    public Stack(Object[] elements) {
        this.elements = elements;
    }
    //无参构造方法
    public Stack() {
        //一维数组动态初始化
        //默认初始化容量为10
        this.elements = new Object[10];
    }
    //栈帧(永远指向栈顶元素)
    private int index=-1;


//压栈方法
public void push(Object obj) throws MystackQperationException{
    
    
                      //重点!!!!!!!!!!!!!
    if(this.index >= this.elements.length-1){
        throw new MystackQperationException("栈内存已满,压栈失败");
        //不要进行try...catch,自己new自己抓的操作,必须抛给调用者
    }//这里进行了改进
                      //重点!!!!!!!!!!!!!
    
    
    index++;
    elements[index] = obj;
    System.out.println(obj + "元素,压栈成功,栈帧指向" + index);
}
​
//弹栈方法
public void pop() throws MystackQperationException{
    
    
                    //重点!!!!!!!!!!!!!
    if(this.index <= -1) {
        //System.out.println("栈内存已空,弹栈栈失败");
        throw new MystackQperationException("栈内存已空,弹栈栈失败");  
    }
                    //重点!!!!!!!!!!!!!
    
    
    else
        System.out.println(elements[index] + "元素,弹栈成功,栈帧指向" + --index);
}
//自定义栈操作异常
public class MystackQperationException{
    public MystackQperationException{
        
    }
    public MystackQperationException(String s){
        super(s);
    }
}
//static实例变量的get方法
public Object[] getElements() {
    return elements;
}
//static实例变量的set方法
public void setElements(Object[] elements) {
    this.elements = elements;
}
//实例变量栈帧的get方法
public int getIndex() {
    return index;
}
//实例变量栈帧的set方法
public void setIndex(int index) {
    this.index = index;
}
}

1.10 子类重写的方法抛出编译异常只能更少/小不能更多

class Animal{
    public void doSome(){
    
    }
    public void doOther() throws Exception{
    
    }
}
class Cat extends Animal{
    public void doSome() throws Exception{
        //编译报错
    }
    public void doOther() throws Exception{
        //编译正常
    }
    public void doOther(){
        //编译正常
    }
    public void doOther() throws NullPointerException{
        //编译正常
    }
    public void doSome() throws RuntimeException{
        //运行编译子类可以正常抛出更多,而编译异常不行
    }
}

评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖虎不秃头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值