day11.异常

本文详细介绍了Java中的异常处理,包括编译时期异常和运行时期异常的区别,如何使用`throws`声明和`try...catch`处理异常,以及Object类的toString和equals方法的重写。此外,还涵盖了自定义异常和内存相关知识,以及finally关键字的使用和对象比较的最佳实践。
摘要由CSDN通过智能技术生成

day11.内部类_异常


今日重点:
  1.能分清编译时期异常和运行时期异常
  2.会使用throws处理异常
  3.会使用try...catch处理异常
  4.知道我们最终为啥要使用try...catch处理异常
  5.知道Object是谁
  6.知道Object中的toString方法作用以及重写toString方法之后的作用
  7.知道Object中的equals方法作用以及重写equals方法之后的作用

第一章.内存

1.this和super

在这里插入图片描述

2.static关键字内存图

在这里插入图片描述

第二章.异常

1.异常介绍

1.概述:代码出现了不正常的现象,在java中每一个异常都是java的一个一个的类,或者叫做异常对象
2.异常体系说明:
  Throwable:
     Error:错误 -> 好比是人得了癌症 -> 不能通过处理让代码变正常了,必须重新写
     Exception:异常(所有异常的父类) -> 好比是人得了感冒(能治) -> 可以通过处理,让代码变得正常
               a.编译时期异常:代码一写,jvm一编译,报红了 -> Exception以及Exception的子类(除了RuntimeException以及RuntimeException的子类)
                   
               b.运行时期异常:代码写的时候没事,但是已运行就报错(RuntimeException以及子类)

在这里插入图片描述

public class Demo01Exception {
    public static void main(String[] args){
        //Error
        //int[] arr1 = new int[999999999];//java.lang.OutOfMemoryError 
        
        //运行时期异常
        int[] arr2 = new int[3];
        System.out.println(arr2[3]);//ArrayIndexOutOfBoundsException
        
        /*
          编译时期异常-> 
          不是我们写的语法错误,
          而是人家底层给我们抛了一个编译时期异常对象,底层抛出的异常继承自Exception
          我们一用就出现了编译时期异常
         */
        //FileOutputStream fos = new FileOutputStream("day11_exception\\1.txt");
    }
}

1.ctrl+n -> 搜索所有的类(包括自己写的以及java提前定义好的)

2.异常出现的过程

在这里插入图片描述

3.创建异常对象(了解)

创建异常对象,是为了故意造异常,以便我们后续学处理异常

1.格式:
  throw new 异常对象()
public class Demo03Exception {
    public static void main(String[] args) {
        String s = "abc.txt";
        method(s);
    }

    public static void method(String s) {
        if (!s.endsWith(".txt")){
          //创建异常对象
            throw new NullPointerException();
        }
    }
}

4.异常处理方式(重点)

4.1 异常处理方式一_throws

1.格式:在参数后面
  throws 异常
public class Demo04Exception {
    public static void main(String[] args)throws FileNotFoundException {
        String s = "abc.txt1";
        /*
          method方法使用了throws异常处理方案
          往上抛异常,但是抛的是编译时期异常
          此异常让调用处接收了
          也就是说:method(s)接收了一个下面抛过来的编译时期异常
          所以此处爆红
         */
        add(s);

        System.out.println("删除功能");
        System.out.println("修改功能");
        System.out.println("查询功能");
    }

    public static void add(String s)throws FileNotFoundException {
        if (!s.endsWith(".txt")){
            //创建异常对象
            throw new FileNotFoundException();
        }
        System.out.println("我要执行");
    }
}

4.2 异常处理方式一_throws多个异常

1.格式:
  throws 异常1,异常2
      
2.注意:
  如果处理的多个异常之间,有子父类继承关系,我们可以直接抛父类异常
  如果不知道多个异常之间到底有没有子父类继承关系,我们可以直接抛Exception    
public class Demo05Exception {
    public static void main(String[] args)throws /*FileNotFoundException,*//*IOException*/Exception {
        String s = "abc.txt1";
        /*
          method方法使用了throws异常处理方案
          往上抛异常,但是抛的是编译时期异常
          此异常让调用处接收了
          也就是说:method(s)接收了一个下面抛过来的编译时期异常
          所以此处爆红
         */
        add(s);
    }

    public static void add(String s)throws /*FileNotFoundException,*//*IOException*/Exception {
        if (s==null){
            //创建异常对象
            throw new IOException("IO异常了");
        }

        if (!s.endsWith(".txt")){
            //创建异常对象
            throw new FileNotFoundException("文件找不到异常");//利用有参构造设置异常信息
        }

        System.out.println("我要执行");
    }
}

4.3 异常处理方式二_try…catch

1.格式:
  try{
      可能会出现异常的代码
  }catch(异常类型 对象名){
      处理异常的方案->开发中将异常信息保存到日志文件中
  }
public class Demo06Exception {
    public static void main(String[] args) {
        String s = "abc.txt1";
        try {
            //String s1 = null;
            //System.out.println(s1.length());//NullPointerException
            add(s);
        }catch (FileNotFoundException e){
            //如果try中的异常抓不到,try...catch外面的功能会受影响
            
            e.printStackTrace();//将异常详细信息打印出来
        }
        System.out.println("删除功能");
        System.out.println("修改功能");
        System.out.println("查询功能");
    }

    private static void add(String s) throws FileNotFoundException {
        if (!s.endsWith(".txt")) {
            throw new FileNotFoundException("文件找不到");
        }
        System.out.println("我要执行");
    }
}

4.4 异常处理方式二_多个catch

1.格式:
  try{
      可能会出现异常的代码
  }catch(异常类型 对象名){
      处理异常的方案->开发中将异常信息保存到日志文件中
  }catch(异常类型 对象名){
      处理异常的方案->开发中将异常信息保存到日志文件中
  }catch(异常类型 对象名){
      处理异常的方案->开发中将异常信息保存到日志文件中
  }...
      
2.注意:
  a.如果多个异常之间有子父类继承关系,先抓子类,再抓父类异常
  b.如果多个异常之间有子父类继承关系,我们可以直接抓父类异常
public class Demo07Exception {
    public static void main(String[] args) {
        String s = "abc.txt1";
        /*try {
            add(s);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e){
            e.printStackTrace();
        }*/

        //错误演示
        /*try {
            add(s);
        }catch (IOException e){
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }*/

        /*try {
            add(s);
        }catch (IOException e){
            e.printStackTrace();
        }*/

        try {
            add(s);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static void add(String s) throws FileNotFoundException, IOException {
        if (s == null) {
            //创建异常对象
            throw new IOException("IO异常了");
        }

        if (!s.endsWith(".txt")) {
            //创建异常对象
            throw new FileNotFoundException("文件找不到异常");//利用有参构造设置异常信息
        }

        System.out.println("我要执行");
    }
}

在这里插入图片描述

5.finally关键字

1.作用:一定会执行的代码块
2.使用:都是和try结合使用
public class Demo08Exception {
    public static void main(String[] args) {
        String s = "abc.txt1";
        try {
            method(s);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            System.out.println("我一定要执行,爱谁谁!");
        }
    }
    public static void method(String s)throws FileNotFoundException{
        if (!s.endsWith(".txt")){
            throw new FileNotFoundException("文件找不到异常");
        }
    }
}

//结果:
//	java.io.FileNotFoundException: 文件找不到异常
// 	我一定要执行,爱谁谁!
//流程:
//	try: 接受method方法抛出异常,执行catch捕获异常并执行异常,最终执行finally代码
public class Demo08Exception {
    public static void main(String[] args) {
        String s = "abc.txt1";
        try {
            String s1 = null;
            System.out.println(s1.length());//NullPointerException
            method(s);
        }catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            System.out.println("我一定要执行,爱谁谁!");
        }
    }
    public static void method(String s)throws FileNotFoundException{
        if (!s.endsWith(".txt")){
            throw new FileNotFoundException("文件找不到异常");
        }
    }
}

//结果:
// 	我一定要执行,爱谁谁!
//	java.lang.NullPointerException
//流程:
//	try: 接收到s1变量操作出现异常,去catch:查看对于异常类型处理方案结果没有。进行往下执行finally代码。jvm发现还没有处理异常终止程序并将异常信息打印出来
public class Demo09Exception {
    public static void main(String[] args) {
        int result = method();
        System.out.println(result);
        /*
        执行顺序:
        	程序入门是main方法
        	调用method()执行method()方法
                执行try代码里
                    定义空字符串赋值给变量s
                    调用变量s的属性-》发现出现错误是“空指针异常”
                jvm捕获异常执行到catch里发现return关键字(结束当前方法) 下面finally关键字执行不
                    如果执行catch代码会导致程序结束,没办法执行到finally
                    所以先执行finally代码,后在去执行catch代码
        结果:
        	我一定要执行
        	1
        */
    }

    public static int method() {
        try {
            String s = null;
            System.out.println(s.length());//空指针异常
            return 2;
        } catch (Exception e) {
            return 1;
        } finally {
            System.out.println("我一定要执行");
        }

    }
}

finally的使用场景:关闭资源

​ 堆内存中的对象由GC(垃圾回收器)回收,但是有很多对象,如:IO流对象,网编 Socket对象,数据库连接对象(Connection)等,GC无法回收,既然GC没有办法回收,我们只能自己关闭资源,销毁对象,所以我们可以将关闭资源,销毁对象的操作放到finally中

6.抛异常时注意的事项(扩展)

1.父类中的方法抛了异常了,那么子类重写此方法之后要不要抛呢?
  可抛可不抛
    
2.父类中的方法没有抛异常,那么子类重写此方法之后要不要抛呢?
  不要抛

7.try_catch和throws的使用时机

1.如果处理异常之后,还想让后续的代码正常执行,我们使用try...catch
2.如果方法之间是递进关系(调用),我们可以先throws,但是到了最后需要用try...catch做一个统一的异常处理

在这里插入图片描述

1.运行时期异常一般我们不处理,因为一旦有运行时期异常出现,肯定是代码写的有问题

2.编译时期异常我们肯定要处理,不处理爆红,代码爆红了,不处理还继续往下写,没意义

8.自定义异常

1.需求:键盘录入一个用户名,实现登录功能,如果登录失败,抛出LoginUserException
public class Demo11Exception {
    public static void main(String[] args) throws LoginUserException {
        //1.创建Scanner对象
        Scanner scanner = new Scanner(System.in);
        System.out.println("请您输入要登录的用户名:");
        String username = scanner.next();
        //2.定义一个字符串,代表已经注册过的用户名
        String name = "root";

        //3.判断
        if (username.equals(name)){
            System.out.println("登录成功");
        }else{
            //如果失败了,就创建异常对象
            throw new LoginUserException("登录失败");
        }
    }
}
public class LoginUserException extends Exception /*RuntimeException*/{
    public LoginUserException() {
    }

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

1.创建一个类

​ a.继承Exception,此时变成了编译时期异常

​ b.继承RuntimeException,此时变成了运行时期异常

2.提供构造方法,方便我们设置异常信息

9.打印异常信息的三个方法

Throwable中的方法:
    public String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误信息)
    public String toString():获取异常的类型和异常描述信息(不用)
    public void printStackTrace():打印异常的跟踪栈信息并输出到控制台上(最详细的异常信息)
public class Demo12Exception {
    public static void main(String[] args) {
        String s = "abc.txt1";
        try {
            method(s);
        } catch (FileNotFoundException e) {
            //System.out.println(e.getMessage());
            //System.out.println(e.toString());
            e.printStackTrace();
        }
    }
    public static void method(String s)throws FileNotFoundException{
        if (!s.endsWith(".txt")){
            throw new FileNotFoundException("文件找不到异常");
        }
    }
}

第三章.Object类

1.Object的介绍

1.概述:
  所有类的父类,根类,所有的类都会直接或者间接去继承Object2.注意:
  a.一个类如果没有明确写出extends xxx,那么此类默认的亲爹就是Object

2.Object类中的toString方法

小技巧:

1.按住ctrl不放,鼠标点击被调用的方法或者变量,可以快速跳到对应的方法以及变量的位置

2.ctrl+n 查询类

3.alt+7 查看当前类中的成员

1.Object中的toString方法  -> 返回对象的字符串表示形式
  public String toString() {
      return getClass().getName() + "@" + Integer.toHexString(hashCode());
  }

2.结论:
  a.如果一个类没有重写toString方法,直接输出对象名会默认调用Object中的toString方法,此时会输出地址值     这个地址值的组成形式就是Object中toString方法拼接成的形式
      
  b.如果一个类重写了Object中的toString方法,再返回地址值就没有意义了,所以我们重写toString之后,我们应该返回对象的内容    
public class Person{
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //重写toString

    @Override
    public String toString() {
        return name+","+age;
    }
}
public class Test01 {
    public static void main(String[] args) {
        Person p1 = new Person("柳岩",36);
        Person p2 = new Person("涛哥",18);
        System.out.println(p2);
        System.out.println(p1.toString());//com.atguigu.b_object.Person@135fbaa4
        System.out.println(p2.toString());//com.atguigu.b_object.Person@45ee12a7

        ArrayList<String> list = new ArrayList<>();
        list.add("abc");
        list.add("def");
        System.out.println(list);// [abc, def]
    }
}

结论:

1.如果直接输出对象名,不让其输出地址值,就在此对象中重写toString方法,让toString返回内容

2.怎么重写:

​ alt+insert->toString->ok

3.Object类中的equals方法

1.Object中的equals方法:
  public boolean equals(Object obj) {
      return (this == obj);
  }

2.注意:
  ==:
   a.针对于基本类型,比较的值
   b.针对于引用类型,比较的是地址值    
3.结论:
  a.如果没有重写Object中的equals方法,那么会调用Object中的equals方法,针对引用类型比较地址值
  b.如果重写Object中的equals方法,再比较地址值就没意义了,所以重写之后,我们应该比较对象的内容    
public class Person{
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //重写toString

   /* @Override
    public String toString() {
        return name+","+age;
    }*/

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }


    /**
     *
     * @param obj
     * @return
     *
     * 问题1:为啥用obj调用name和age报错? 因为此时obj为Object类型接收了Person类型的p2
     *      此处为多态,name和age是Person中的特有属性,多态前提下,不能直接调用子类特有成员,所以报错
     * 解决问题1:
     *      向下转型
     *
     * 问题2:如果传递的不是Person类型,会出现类型转换异常
     * 解决问题2:加个类型判断,如果传递过来的数据属于Person类型,在强转成Person类型
     *
     * 问题3:如果equals方法接收的是null,我们就没有必要判断类型了
     * 解决问题3:直接做非空判断,提高点效率
     *
     * 问题4:如果equals方法接收的是自己,就会出现自己和自己比较,自己跟自己比肯定为true,就没有必要
     *      判断类型,向下转型,比较了
     * 解决问题4:加判断,如果地址值一样,直接返回true
     *
     */
    /*public boolean equals(Object obj){
        if (this==obj){
            return true;
        }

        if (obj==null){
            return false;
        }

        if (obj instanceof Person){
            Person p2 = (Person)obj;
            return this.name.equals(p2.name) && this.age == p2.age;
        }

        return false;

    }*/

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

}

public class Test02 {
    public static void main(String[] args) {
        Person p1 = new Person("柳岩",36);
        Person p2 = new Person("柳岩",36);
        //System.out.println(p1.equals(p2));

        //ArrayList<String> list = new ArrayList<>();
        //System.out.println(p1.equals(list));
        //System.out.println(p1.equals(null));
        System.out.println(p1.equals(p1));

        System.out.println("=========================");

        String s1 = new String("abc");
        String s2 = new String("abc");
        System.out.println(s1.equals(s2));//true
        System.out.println(s1==s2);//false
    }
}

在这里插入图片描述

结论:

1.如果比较两个对象,想比较对象的内容,就重写equals方法

2.怎么重写:alt+insert -> equals and hashCode -> 一路下一步->ok

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值