day27-异常、File

1. 异常

1.1 异常概念

异常,就是不正常的意思。在生活中:医生说,你的身体某个部位有异常,该部位和正常相比有点不同,该部位的功能将受影响.在程序中的意思就是:

  • 异常 :指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。

在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理。

异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行.

1.2 异常体系

在这里插入图片描述

异常机制其实是帮助我们找到程序中的问题,异常的根类是java.lang.Throwable,其下有两个子类:java.lang.Errorjava.lang.Exception,平常所说的异常指java.lang.Exception

Throwable体系:

  • Error:严重错误Error,代表的系统级别的错误,无法通过处理的错误,只能事先避免,好比绝症。
  • Exception:表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的。好比感冒、阑尾炎。

1.3 异常分类

在这里插入图片描述

public class Main {
    public static void main(String[] args) throws ParseException {

        //编译时异常(在编译阶段必须要手动处理,否则代码报错)
        String time = "2024年4月16日";
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
        Date parse = simpleDateFormat.parse(time);
        System.out.println(parse);

        //运行时异常(编译阶段不需要处理,是代码运行时出现的异常)
        int[] arr= {1,2,3};
        System.out.println(arr[3]);
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.4 异常的作用

在这里插入图片描述
比如作用一:越界异常,就知道哪里错了,或者初始化对象数组,但是没有赋值,操作数组就会出现空指针异常。
比如作用二:如果对某个对象的age赋值,但是假如超过40岁,则告诉调用者,那么就用异常,即如果age>40则,抛异常

1.5 异常的处理方式

在这里插入图片描述

1.5.1 JVM默认处理方式

在这里插入图片描述
在这里插入图片描述

1.5.2 自己处理(捕获异常)

在这里插入图片描述
在这里插入图片描述

1.6 灵魂4问

  • 如果try中没有遇到问题,怎么执行?

    • 会把try里面所有的代码全部执行完毕,不会执行catch里面的代码
      注意: 只有当出现了异常才会执行catch里面的代码
      在这里插入图片描述
  • 如果try中可能会遇到多个问题,怎么执行?

    • 会写多个catch与之对应
      细节: 如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面
      在这里插入图片描述
    • 在JDK7之后,我们可以在catch中同时捕获多个异常,中间用|进行隔开,表示如果出现了A异常或者B异常的话,采取同一种处理方案。
      在这里插入图片描述
  • 如果try中遇到的问题没有捕获,怎么执行呢?

    • 相当于try…catch的代码白写了,最终还是交给虚拟机进行处理。
      在这里插入图片描述
      执行过程就是,数组越界后,会new一个ArrayIndexOutofBoundsException对象,然后拿着这个对象和下面的catch对比,发现没有可以接受的,就把这个异常对象交给jvm处理,jvm就会输出异常并停止程序。
  • 如果try中遇到了问题,那么try下面的其他代码还会执行吗?

    • 下面的代码就不会执行了,直接跳转到对应的catch当中,执行catch里面的语句体,但是如果没有对应catch与之匹配,那么还是会交给虚拟机进行处理
      在这里插入图片描述
      哪怕后面再出现一个异常,那么也不会被捕获到。
      在这里插入图片描述
      在这里插入图片描述

1.7 异常中的常见方法

在这里插入图片描述
细节:printStackTrace最常用,因为包含了上面两个所有信息,而且仅仅是打印信息,不会停止程序运行,底层使用了System.err.println输出信息在这里插入图片描述
小扩展:
在这里插入图片描述

1.8 抛出异常throw

在这里插入图片描述
需求:定义一个方法找到数组中最大的值

public class Main {
    public static void main(String[] args){
        int[] arr=null;
        int max=0;
        try {
            max = getMax(arr);
        } catch (NullPointerException e) {
            System.out.println("空指针异常");
        }catch (IndexOutOfBoundsException e) {
            System.out.println("索引越界异常");
        }
        System.out.println(max);
    }
    public static int getMax(int[] arr)/*throws NullPointerException,IndexOutOfBoundsException*/{
        //手动创建一个异常独享,病把这个异常交给方法的调用者处理
        //此时方法就会结束,下面的代码不会再执行了
        if(arr==null){
            throw new NullPointerException();
        }
        if(arr.length==0){
            throw new IndexOutOfBoundsException();
        }
        int max_value = arr[0];
        for (int i = 0; i < arr.length; i++) {
            if(arr[i]>max_value){
                max_value=arr[i];
            }
        }
        return max_value;
    }
}

输出:
空指针异常
0
在这里插入图片描述

1.9 练习:

在这里插入图片描述

public class GirlFriend {
    private String name;
    private int age;

    public GirlFriend() {
    }


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

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        if(name.length()<3||name.length()>10){
            throw new RuntimeException();
        }
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        if(age<18||age>40){
            throw new RuntimeException();
        }
        this.age = age;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        GirlFriend girlFriend = new GirlFriend();

        while (true) {
            try {
                System.out.println("请输入女朋友姓名:");
                String name = scanner.next();
                girlFriend.setName(name);
                System.out.println("请输入女朋友年龄:");
                String agestr = scanner.next();
                int age = Integer.parseInt(agestr);
                girlFriend.setAge(age);
                break;
            } catch (NumberFormatException e) {
                System.out.println("年龄格式输入错误,请输入数字!");
            }
            catch (RuntimeException e){
                System.out.println("姓名长度或年龄范围有误!");
            }
        }
        System.out.println(girlFriend);
    }
}

1.10 自定义异常

由于上一步的练习使用了运行时异常,不太符合具体情况,因此需要自定义异常:
在这里插入图片描述
在这里插入图片描述

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

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

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

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

public class GirlFriend {
    private String name;
    private int age;

    public GirlFriend() {
    }


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

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        if(name.length()<3||name.length()>10){
            throw new NameFormatException(name+"超出范围!");
        }
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        if(age<18||age>40){
            throw new AgeOutOfBoundsException(age+"超出范围!");
        }
        this.age = age;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

import java.text.ParseException;
import java.text.SimpleDateFormat;

import java.util.Date;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        GirlFriend girlFriend = new GirlFriend();
        while (true) {
            try {
                System.out.println("请输入女朋友姓名:");
                String name = scanner.next();
                girlFriend.setName(name);
                System.out.println("请输入女朋友年龄:");
                String agestr = scanner.next();
                int age = Integer.parseInt(agestr);
                girlFriend.setAge(age);
                break;
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
            catch (AgeOutOfBoundsException e){
                e.printStackTrace();
            }
            catch (NameFormatException e){
                e.printStackTrace();
            }
        }
        System.out.println(girlFriend);
    }
}

1.11 Finally

在这里插入图片描述
除非虚拟机停止,比如在try里面,写了一个System.eixt(0),那么finally里面的代码就不会执行了

2. File类

2.1 概述

java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。

2.2 构造方法

在这里插入图片描述

  • 构造举例,代码如下:
// 文件路径名
String pathname = "D:\\aaa.txt";
File file1 = new File(pathname); 

// 文件路径名
String pathname2 = "D:\\aaa\\bbb.txt";
File file2 = new File(pathname2); 

// 通过父路径和子路径字符串
 String parent = "d:\\aaa";
 String child = "bbb.txt";
 File file3 = new File(parent, child);

// 通过父级File对象和子路径字符串
File parentDir = new File("d:\\aaa");
String child = "bbb.txt";
File file4 = new File(parentDir, child);

小贴士:

  1. 一个File对象代表硬盘中实际存在的一个文件或者目录。
  2. 无论该路径下是否存在文件或者目录,都不影响File对象的创建。
    在这里插入图片描述

2.3 常用方法

判断功能的方法

  • public boolean exists() :此File表示的文件或目录是否实际存在。
  • public boolean isDirectory() :此File表示的是否为目录。
  • public boolean isFile() :此File表示的是否为文件。

方法演示,代码如下:

//1.对一个文件进行判断
File file1 = new File("C:\\Users\\gao\\Desktop\\JavaLearn\\src\\Main.java");
System.out.println(file1.exists());//true
System.out.println(file1.isDirectory());//false
System.out.println(file1.isFile());//true

//2.对一个文件夹进行判断
File file2 = new File("C:\\Users\\gao\\Desktop\\JavaLearn\\src");
System.out.println(file2.exists());//true
System.out.println(file2.isDirectory());//true
System.out.println(file2.isFile());//false

//3.对一个不存在的路径进行判断
File file3 = new File("C:\\Users\\gao\\Desktop\\JavaLearn\\aaa");
System.out.println(file3.exists());//false
System.out.println(file3.isDirectory());//false
System.out.println(file3.isFile());//false

注意:如果一个文件夹或文件不存在,那么输出是否是文件或文件夹都会输出false,因为他不存在

获取功能的方法

  • public long length() :返回由此File表示的文件的长度。

    • 细节1:这个方法只能获取文件的大小,单位是字节
    • 细节2:这个方法无法获取文件夹的大小,如果需要获取文件夹大小,需要把这个文件夹的所有文件大小累加在一起。
  • public String getAbsolutePath() :返回此File的绝对路径。

  • public String getPath() :返回定义文件时的路径。

  • public String getName() :返回由此File表示的文件或目录的名称。

    • 细节1:定义的是文件,则返回的文件名+扩展名,如a.txt
    • 细节2:定义的是文件及,则返回的是文件夹的名字
  • public long lastModified : 返回文件的最后修改时间(时间毫秒值)

    方法演示,代码如下:

    //1.返回文件的大小
    File file = new File("C:\\Users\\gao\\Desktop\\JavaLearn\\src\\Main.java");
    System.out.println(file.length());//276
    
    //2.返回文件的绝对路径
    System.out.println(file.getAbsoluteFile());//C:\Users\gao\Desktop\JavaLearn\src\Main.java
    File file1 = new File("src//Main.java");
    System.out.println(file1.getAbsoluteFile());//C:\Users\gao\Desktop\JavaLearn\src\Main.java
    
    //3.返回文件定义时的路径
    System.out.println(file.getPath());//C:\Users\gao\Desktop\JavaLearn\src\Main.java
    System.out.println(file1.getPath());//src\Main.java
    
    //4.获取文件名字
    System.out.println(file.getName());
    System.out.println(file1.getName());
    
    //5.获取文件最后修改时间
    System.out.println(file.lastModified());//1713927862885
    Date date = new Date(file.lastModified());
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
    System.out.println(sdf.format(date));//2024年04月24日11时04分22秒
    

API中说明:length(),表示文件的长度。但是File对象表示目录,则返回值未指定。

创建删除功能的方法

  • public boolean createNewFile() :创建一个新的空文件。
    • 细节1:如果创建的文件不存在,则创建成功,返回true,如果创建的文件已经存在,则创建失败,返回false
    • 细节2:如果父级路径是不存在的,则会报错,IOException
    • 细节3:createNewFile一定创建的是一个文件,如果路径中不包含后缀名,则创建一个没有后缀的文件
  • public boolean mkdir() :创建单级文件夹。
    • 细节1:windows当中的路径是唯一的,如果当前路径已经存在,则创建失败,返回false
    • 细节2:mkdir只能创建单级文件夹,无法创建多级文件夹
  • public boolean mkdirs() :创建多级文件夹。
    • 细节:既可以创建单级文件夹,也可以创建多级文件夹
  • public boolean delete() :删除文件、文件夹。
    • 细节:默认只能删除文件和空文件夹,直接删除,不走回车站。如果删除有内容的文件夹,则删除失败

方法演示,代码如下:

//1.创建空文件
boolean newFile = new File("./a.txt").createNewFile();
System.out.println(newFile);

//2.创建文件夹
boolean mkdir = new File("./aaa").mkdir();
System.out.println(mkdir);

//3.创建多级文件夹
boolean newFile1 = new File("./bbb/ccc").mkdirs();
System.out.println(newFile1);

API中说明:delete方法,如果此File表示目录,则目录必须为空才能删除。

2.4 目录的遍历

  • public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。 重点掌握
    在这里插入图片描述
//1.创建File
File file = new File("C:\\Users\\gao\\Desktop\\JavaLearn");
File[] files = file.listFiles();
for (File file1 : files) {
    System.out.println(file1);
}

C:\Users\gao\Desktop\JavaLearn\.gitignore
C:\Users\gao\Desktop\JavaLearn\.idea
C:\Users\gao\Desktop\JavaLearn\bbb
C:\Users\gao\Desktop\JavaLearn\JavaLearn.iml
C:\Users\gao\Desktop\JavaLearn\out
C:\Users\gao\Desktop\JavaLearn\src

小贴士:

调用listFiles方法的File对象,表示的必须是实际存在的目录,否则返回null,无法进行遍历。

其他获取并遍历方法,重点掌握listFiles就可以了,因为其他的都可以使用listFiles实现:

在这里插入图片描述

//1.listRoots
File[] files = File.listRoots();
for (File file : files) {
    System.out.println(file);
}
System.out.println("======================");

//2.list
File file = new File("C:\\Users\\gao\\Desktop\\JavaLearn");
String[] list = file.list();
for (String s : list) {
    System.out.println(s);
}
System.out.println("======================");

//需求,获取文件夹,且b开头的文件夹
//3.list(FilenameFilter filter)
String[] list1 = file.list(new FilenameFilter() {
    @Override
    //参数一:父级路径
    //参数二:子级路径
    public boolean accept(File dir, String name) {
        File file1 = new File(dir, name);
        return file1.isDirectory() && name.startsWith("b");
    }
});
for (String s : list1) {
    System.out.println(s);
}
System.out.println("======================");

//需求,获取文件夹,且b开头的文件夹
//4.listFiles(FileFilter filter)
File[] files1 = file.listFiles(new FileFilter() {
    @Override
    public boolean accept(File pathname) {
        return pathname.isDirectory() && pathname.getName().startsWith("b");
    }
});
for (File file1 : files1) {
    System.out.println(file1);
}
System.out.println("======================");

//5.listFiles(FilenameFilter filter)
File[] files2 = file.listFiles(new FilenameFilter() {
    @Override
    public boolean accept(File dir, String name) {
        File file1 = new File(dir, name);
        return file1.isDirectory() && name.startsWith("b");
    }
});
for (File file1 : files2) {
    System.out.println(file1);
}

2.5 综合练习

练习1:创建文件夹

​ 在当前模块下的aaa文件夹中创建一个a.txt文件

代码实现:

//1.创建a.txt的父级路径
File file = new File("./aaa");
//2.创建父级路径
//如果aaa是存在的,那么此时创建失败的。
//如果aaa是不存在的,那么此时创建成功的。
file.mkdirs();
//3.拼接父级路径和子级路径
File src = new File(file,"a.txt");
boolean b = src.createNewFile();
if(b){
    System.out.println("创建成功");
}else{
    System.out.println("创建失败");
}
练习2:查找文件(不考虑子文件夹)

​ 定义一个方法找某一个文件夹中,是否有以avi结尾的电影(暂时不需要考虑子文件夹)

代码示例:

public class Test2 {
    public static void main(String[] args) {
        /*需求:
             定义一个方法找某一个文件夹中,是否有以avi结尾的电影。
	        (暂时不需要考虑子文件夹)
        */

        File file = new File("D:\\aaa\\bbb");
        boolean b = haveAVI(file);
        System.out.println(b);
    }
    /*
    * 作用:用来找某一个文件夹中,是否有以avi结尾的电影
    * 形参:要查找的文件夹
    * 返回值:查找的结果  存在true  不存在false
    * */
    public static boolean haveAVI(File file){// D:\\aaa
        //1.进入aaa文件夹,而且要获取里面所有的内容
        File[] files = file.listFiles();
        //2.遍历数组获取里面的每一个元素
        for (File f : files) {
            //f:依次表示aaa文件夹里面每一个文件或者文件夹的路径
            if(f.isFile() && f.getName().endsWith(".avi")){
                return true;
            }
        }
        //3.如果循环结束之后还没有找到,直接返回false
        return false;
    }
}

练习3:(考虑子文件夹)

​ 找到电脑中所有以avi结尾的电影。(需要考虑子文件夹)

代码示例:

public class Test3 {
    public static void main(String[] args) {
        /* 需求:
        找到电脑中所有以avi结尾的电影。(需要考虑子文件夹)


        套路:
            1,进入文件夹
            2,遍历数组
            3,判断
            4,判断

        */

        findAVI();

    }

    public static void findAVI(){
        //获取本地所有的盘符
        File[] arr = File.listRoots();
        for (File f : arr) {
            findAVI(f);
        }
    }

    public static void findAVI(File src){//"C:\\
        //1.进入文件夹src
        File[] files = src.listFiles();
        //2.遍历数组,依次得到src里面每一个文件或者文件夹
        if(files != null){
            for (File file : files) {
                if(file.isFile()){
                    //3,判断,如果是文件,就可以执行题目的业务逻辑
                    String name = file.getName();
                    if(name.endsWith(".avi")){
                        System.out.println(file);
                    }
                }else{
                    //4,判断,如果是文件夹,就可以递归
                    //细节:再次调用本方法的时候,参数一定要是src的次一级路径
                    findAVI(file);
                }
            }
        }
    }
}

练习4:删除多级文件夹

需求: 如果我们要删除一个有内容的文件夹
1.先删除文件夹里面所有的内容
2.再删除自己

代码示例:

public class Test4 {
    public static void main(String[] args) {
        /*
           删除一个多级文件夹
           如果我们要删除一个有内容的文件夹
           1.先删除文件夹里面所有的内容
           2.再删除自己
        */

        File file = new File("D:\\aaa\\src");
        delete(file);

    }

    /*
    * 作用:删除src文件夹
    * 参数:要删除的文件夹
    * */
    public static void delete(File src){
        //1.先删除文件夹里面所有的内容
        //进入src
        File[] files = src.listFiles();
        //遍历
        for (File file : files) {
            //判断,如果是文件,删除
            if(file.isFile()){
                file.delete();
            }else {
                //判断,如果是文件夹,就递归
                delete(file);
            }
        }
        //2.再删除自己
        src.delete();
    }
}

练习5:统计大小

​ 需求:统计一个文件夹的总大小

代码示例:

public class Test5 {
    public static void main(String[] args) {
       /*需求:
            统计一个文件夹的总大小
      */


        File file = new File("D:\\aaa\\src");

        long len = getLen(file);
        System.out.println(len);//4919189
    }

    /*
    * 作用:
    *       统计一个文件夹的总大小
    * 参数:
    *       表示要统计的那个文件夹
    * 返回值:
    *       统计之后的结果
    *
    * 文件夹的总大小:
    *       说白了,文件夹里面所有文件的大小
    * */
    public static long getLen(File src){
        //1.定义变量进行累加
        long len = 0;
        //2.进入src文件夹
        File[] files = src.listFiles();
        //3.遍历数组
        for (File file : files) {
            //4.判断
            if(file.isFile()){
                //我们就把当前文件的大小累加到len当中
                len = len + file.length();
            }else{
                //判断,如果是文件夹就递归
                len = len + getLen(file);
            }
        }
        return len;
    }
}

练习6:统计文件个数

需求:统计一个文件夹中每种文件的个数并打印。(考虑子文件夹)
打印格式如下:
txt:3个
doc:4个
jpg:6个

代码示例:

public class Test6 {
    public static void main(String[] args) throws IOException {
        /*
            需求:统计一个文件夹中每种文件的个数并打印。(考虑子文件夹)
            打印格式如下:
            txt:3个
            doc:4个
            jpg:6个
        */
        File file = new File("D:\\aaa\\src");
        HashMap<String, Integer> hm = getCount(file);
        System.out.println(hm);
    }

    /*
    * 作用:
    *       统计一个文件夹中每种文件的个数
    * 参数:
    *       要统计的那个文件夹
    * 返回值:
    *       用来统计map集合
    *       键:后缀名 值:次数
    *
    *       a.txt
    *       a.a.txt
    *       aaa(不需要统计的)
    *
    *
    * */
    public static HashMap<String,Integer> getCount(File src){
        //1.定义集合用来统计
        HashMap<String,Integer> hm = new HashMap<>();
        //2.进入src文件夹
        File[] files = src.listFiles();
        //3.遍历数组
        for (File file : files) {
            //4.判断,如果是文件,统计
            if(file.isFile()){
                //a.txt
                String name = file.getName();
                String[] arr = name.split("\\.");
                if(arr.length >= 2){
                    String endName = arr[arr.length - 1];
                    if(hm.containsKey(endName)){
                        //存在
                        int count = hm.get(endName);
                        count++;
                        hm.put(endName,count);
                    }else{
                        //不存在
                        hm.put(endName,1);
                    }
                }
            }else{
                //5.判断,如果是文件夹,递归
                //sonMap里面是子文件中每一种文件的个数
                HashMap<String, Integer> sonMap = getCount(file);
                //hm:  txt=1  jpg=2  doc=3
                //sonMap: txt=3 jpg=1
                //遍历sonMap把里面的值累加到hm当中
                Set<Map.Entry<String, Integer>> entries = sonMap.entrySet();
                for (Map.Entry<String, Integer> entry : entries) {
                    String key = entry.getKey();
                    int value = entry.getValue();
                    if(hm.containsKey(key)){
                        //存在
                        int count = hm.get(key);
                        count = count + value;
                        hm.put(key,count);
                    }else{
                        //不存在
                        hm.put(key,value);
                    }
                }
            }
        }
        return hm;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值