异常和File
- 一、异常
- 1.1异常的分类
- 1.2 异常的作用
- 1.3 异常的处理方式
- 1.3.1 JVM默认的处理方式
- 1.3.2 自己处理(捕获异常)
- 1.3.3 自己处理(灵魂四问)
- 1.4 异常中的常见方法
- 1.5 抛出异常
- 综合练习(键盘录入数据)
- 1.6 自定义异常
- 二、File
- 2.1 路径
- 2.2 File的常见成员方法(判断、获取)
- 2.3 File的常见成员方法(创建、删除)
- 2.4 File的常见成员方法(获取并遍历)
- 三、综合练习
- 练习一:(创建文件)
- 练习二:(单个文件夹查找文件)
- 练习三:(遍历硬盘查找文件)
- 练习四:(删除文件夹)
- 练习五:(统计文件夹大小)
- 练习六:(统计各种文件数量)
一、异常
异常:异常就是代表程序出现的问题
1.1异常的分类
Error:代表的系统级别错误(属于严重问题)
- 系统一旦出现问题,sun公司会把这些错误封装成Error对象。
- Error是给sun公司自己用的,不是给我们程序员用的。
- 因此我们开发人员不用管它。
Exception:叫做异常,代表程序可能出现问题。
我们通常会用Exception以及他的子类来封装程序出现的问题。
运行时异常:RuntimeException及其子类,编译阶段不会出现异常提醒。
运行时出现的异常(如:数组索引越界异常)
编译时异常:编译阶段就会出现异常提醒的。(如:日期解析异常)
编译时异常:在编译阶段,必须要手动处理,否则代码报错
运行时异常:在编译阶段是不需要处理的,是代码运行时出现的异常
1.2 异常的作用
作用一:异常时用来查询bug的关键参考信息
作用二:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
public static void main(String[] args) {
Student s = new Student();
//年龄在20-40之间
s.setAge(50);
}
Student类中setAge方法
/**
* 设置
*
* @param age
*/
public void setAge(int age) {
if (age < 20 || age > 40){
throw new RuntimeException("年龄在20-40岁之间");//运行时异常
}else {
this.age = age;
}
}
Exception in thread "main" java.lang.RuntimeException: 年龄在20-40岁之间
at myException.Student.setAge(Student.java:49)
at myException.ExceptionDemo1.main(ExceptionDemo1.java:7)
1.3 异常的处理方式
1.3.1 JVM默认的处理方式
- 把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
- 程序停止执行,下面的代码不会再执行了
1.3.2 自己处理(捕获异常)
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6};
try {
System.out.println(arr[10]);//此处出现了异常,程序就会在这里创建一个ArrayIndexOutOfBoundsException对象
//new ArrayIndexOutOfBoundsException();
//拿着这个对象到catch的小括号中对比,看括号中的变量是否可以接收这个对象
//如果能被接收,就表示该异常就被捕获(抓住),执行catch里面对应的代码
//当catch 里面所有的代码执行完毕,继续执行try...catch体系下面的其他代码
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("索引越界了");
}
System.out.println("看看我执行了吗");
}
好处:可以让程序继续往下执行,不会停止。
1.3.3 自己处理(灵魂四问)
- 灵魂一问:如果try中没有遇到问题,怎么执行?
- 会把try里面所有的代码全部执行完毕,不会执行catch里面的代码
- 注意:
- 只有当出现了异常才会执行catch里面的代码
- 灵魂二问:如果try中可能会遇到多个问题,怎么执行?
- 会写多个catch与之对应
- 细节:
- 如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面。
- 如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面。
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6};
try {
System.out.println(arr[10]);
System.out.println(2 / 0);
String s = null;
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("索引越界了");
} catch (ArithmeticException e) {
System.out.println("除数不能为零!");
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (Exception e) {
System.out.println("Exception");
}
System.out.println("看看我执行了吗");
}
了解性:
- 在JDK7之后,我们可以在catch中同时捕获多个异常,中间用 | 进行隔开
- 表示如果出现了A异常或者B异常的话,采取同一种处理方案
-
灵魂三问:如果try中遇到的问题没有被捕获,怎么执行?
相当于try…catch的代码白写了,最终还是会交给虚拟机进行处理。 -
灵魂四问:如果try中遇到了问题,那么try下面的其他代码还会执行吗?
- 下面的代码就不会执行了,直接跳转到对应的catch当中,执行catch里面的语句体
- 但是如果没有对应catch与之匹配,那么还是会交给虚拟机进行处理。
1.4 异常中的常见方法
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
//0.返回此 throwable 的详细消息字符串
/*String message = e.getMessage();
System.out.println(message);*/ //Index 10 out of bounds for length 6
//1.返回此可抛出的简短描述
/*String string = e.toString();
System.out.println(string);*/ //java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 6
//2.把异常的错误信息输出在控制台
e.printStackTrace();//仅仅是打印信息,不会停止程序运行
}
System.out.println("看看我执行了吗");
}
拓展内容:
//正常的输出语句
System.out.println(123);
//错误的输出语句
System.err.println(456); //字体颜色是红色
public void printStackTrace()
- 在底层时利用 System.err.println 进行输出
- 把异常的错误信息以红色字体输出在控制台
- 细节
- 仅仅是打印信息,不会停止程序运行
1.5 抛出异常
public static void main(String[] args) {
//定义一个方法求数组的最大值
// int[] arr = {1,2,3,4,5};
int[] arr = null;
// int[] arr = {};
int max = 0;
try {
max = getMax(arr);
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (ArrayIndexOutOfBoundsException e){
System.out.println("索引越界异常");
}
System.out.println(max);
}
public static int getMax(int[] arr) /*throws NullPointerException, ArrayIndexOutOfBoundsException*/ {
if (arr == null) {
//手动创建一个异常对象,并把这个异常交给方法的调用者处理
//此时方法就会结束,下面的代码就不会执行了
throw new NullPointerException();
}
if (arr.length == 0) {
throw new ArrayIndexOutOfBoundsException();
}
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
return max;
}
综合练习(键盘录入数据)
需求:
- 键盘录入自己心仪的女朋友姓名和年龄,
- 姓名的长度在3~10之间
- 年龄的范围为18-40岁
- 超出这个范围是异常数据不能赋值,需要重新录入,一直录到正确为止。
提示: - 需要考虑用户在键盘录入时的所有情况。
- 比如:录入年龄时超出范围,录入年龄时录入了abc等情况
女朋友类:
package myException;
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) {
//姓名的长度在3~10之间
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) {
//年龄的范围为18-40岁
if (age < 18 || age > 40) {
throw new RuntimeException();
}
this.age = age;
}
public String toString() {
return "GirlFriend{name = " + name + ", age = " + age + "}";
}
}
public static void main(String[] args) {
/*需求:
键盘录入自己心仪的女朋友姓名和年龄,
姓名的长度在3~10之间
年龄的范围为18-40岁
超出这个范围是异常数据不能赋值,需要重新录入,一直录到正确为止。
提示:
需要考虑用户在键盘录入时的所有情况。
比如:录入年龄时超出范围,录入年龄时录入了abc等情况*/
//键盘录入自己心仪的女朋友姓名和年龄
Scanner sc = new Scanner(System.in);
//创建女朋友对象
GirlFriend gf = new GirlFriend();
while (true) {
try {
//接收女朋友的姓名
System.out.println("请输入你女朋友的姓名");
String name = sc.nextLine();
gf.setName(name);
//接收女朋友的年龄
System.out.println("请输入你女朋友的年龄");
String ageStr = sc.nextLine();
int age = Integer.parseInt(ageStr);
gf.setAge(age);
break;
} catch (NumberFormatException e) {
System.out.println("年龄格式错误,年龄格式必须是数字");
} catch (RuntimeException e) {
System.out.println("姓名的长度或者年龄的范围有误");
}
}
//打印
System.out.println(gf);
}
1.6 自定义异常
技巧:
NameFormat:当前异常的名字,表示姓名格式化问题
Exception: 表示当前类是一个异常类
运行时:RunTimeException 核心 就表示由于参数错误而导致的问题
编译时:Exception 核心 提醒程序员检查本地信息
姓名格式化异常:
package myException.Test2;
public class NameFormatException extends RuntimeException{
//技巧:
// NameFormat:当前异常的名字,表示姓名格式化问题
// Exception: 表示当前类是一个异常类
//运行时:RunTimeException 核心 就表示由于参数错误而导致的问题
//编译时:Exception 核心 提醒程序员检查本地信息
public NameFormatException() {
}
public NameFormatException(String message) {
super(message);
}
}
年龄越界异常:
package myException.Test2;
public class AgeOutOfBoundsException extends RuntimeException{
public AgeOutOfBoundsException() {
}
public AgeOutOfBoundsException(String message) {
super(message);
}
}
public static void main(String[] args) {
/*需求:
键盘录入自己心仪的女朋友姓名和年龄,
姓名的长度在3~10之间
年龄的范围为18-40岁
超出这个范围是异常数据不能赋值,需要重新录入,一直录到正确为止。
提示:
需要考虑用户在键盘录入时的所有情况。
比如:录入年龄时超出范围,录入年龄时录入了abc等情况*/
//键盘录入自己心仪的女朋友姓名和年龄
Scanner sc = new Scanner(System.in);
//创建女朋友对象
myException.Test1.GirlFriend gf = new GirlFriend();
while (true) {
try {
//接收女朋友的姓名
System.out.println("请输入你女朋友的姓名");
String name = sc.nextLine();
gf.setName(name);
//接收女朋友的年龄
System.out.println("请输入你女朋友的年龄");
String ageStr = sc.nextLine();
int age = Integer.parseInt(ageStr);
gf.setAge(age);
break;
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (NameFormatException e) {
e.printStackTrace();
} catch (AgeOutOfBoundsException e) {
e.printStackTrace();
}
}
//打印
System.out.println(gf);
}
二、File
2.1 路径
- File对象就表示一个路径,可以是文件的路径、也可以是文件夹的路径
- 这个路径可以是存在的,也允许是不存在的
public static void main(String[] args) {
//0.根据文件路径创建文件对象
// 根据字符串表示的路径,变成File对象
String str = "G:\\code\\Java\\basic_code\\day27_code\\src\\myFile\\a.txt";
File f1 = new File(str);
System.out.println(f1);
//1.根据路径名字字符串和子路径名字字符串创建文件对象
//父级路径:G:\code\Java\basic_code\day27_code\src\myFile
//子级路径:a.txt
String parent = "G:\\code\\Java\\basic_code\\day27_code\\src\\myFile";
String child = "a.txt";
File f2 = new File(parent, child);
System.out.println(f2);
File f3 = new File(parent + "//" + child);
System.out.println(f3);
//2.根据父路径对应文件对象和子路径名字字符串创建文件对象
//把一个File表示的路径和String表示路径进行拼接
File parent2 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile");
String str2 = "a.txt";
File f4 = new File(parent2, str2);
System.out.println(f4);
}
2.2 File的常见成员方法(判断、获取)
- 判断
public static void main(String[] args) {
//0.对一个文件的路径进行判断
File f1 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile\\a.txt");
System.out.println(f1.isDirectory()); //false
System.out.println(f1.isFile()); // true
System.out.println(f1.exists()); // true
System.out.println("======================");
//1.对一个文件夹的路径进行判断
File f2 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile");
System.out.println(f2.isDirectory()); //true
System.out.println(f2.isFile()); // false
System.out.println(f2.exists()); // true
}
- 获取
public static void main(String[] args) {
//0.返回文件的大小,字节数量
//细节1:这个方法只能获取文件的大小,单位是字节
//如果单位我们要是M,G,可以不断的除以1024
//细节2:这个方法无法获取文件夹的大小
//如果我们要获取一个文件夹的大小,需要把这个文件夹里面所有的文件大小都累加在一起
File f1 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile\\a.txt");
long len = f1.length();
System.out.println(len);
System.out.println("---------------------");
//1.返回文件的绝对路径
File f2 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile\\a.txt");
File path1 = f2.getAbsoluteFile();
System.out.println(path1);
File f3 = new File("day27_code//src//myFile//a.txt");
File path2 = f3.getAbsoluteFile();
System.out.println(path2);
System.out.println("---------------------------------");
//2.返回定义文件时使用的路径
File f4 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile\\a.txt");
String path3 = f4.getPath();
System.out.println(path3);
File f5 = new File("day27_code//src//myFile//a.txt");
String path4 = f5.getPath();
System.out.println(path4);
System.out.println("------------------------------");
//3.获取文件的名字
/*细节1:
* 返回文件的文件名 后缀名、扩展名
*
* 细节2:
* 文件夹:返回的就是文件夹的名字*/
File f6 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile\\a.txt");
String name = f6.getName();
System.out.println(name);
File f7 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile");
String name2 = f7.getName();
System.out.println(name2);
//4.返回文件的最后修改时间
File f8 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile");
long time = f8.lastModified();
System.out.println(time); //获取的是毫秒值
}
2.3 File的常见成员方法(创建、删除)
public static void main(String[] args) throws IOException {
//0.创建一个新的空的文件
/*细节1:如果当前路径表示的文件是不存在的,则创建成功,方法返回false
* 如果当前路径表示的文件是存在的,则回创建失败,方法返回false
* 细节2:如果父级路径是不存在的,那么方法会有异常IOException
* 细节3:createNewFile方法创建的一定是文件,如果路径中不包含后缀名,则创建一个没有后缀的文件*/
File f1 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile\\b.txt");
boolean b = f1.createNewFile();
System.out.println(b);
//1.创建单级文件夹
/*细节1:Windows当中路径是唯一的,如果当前路径已经存在,则创建失败,返回false
* 细节2:mkdir方法只能创建单级文件夹,无法创建多级文件夹*/
File f2 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile\\aaa");
boolean b2 = f2.mkdir();
System.out.println(b2);
//2.创建多级文件夹
//细节:既可以创建单级的,又可以创建多级的文件夹
File f3 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile\\aaa\\bbb\\ccc");
boolean b3 = f3.mkdirs();
System.out.println(b3);
//3.删除
/*细节:
* 如果删除的是文件,则直接删除,不走回收站。
* 如果删除的是空文件夹,则直接删除,不走回收站
* 如果删除的是有内容的文件夹,则删除失败*/
File f4 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile\\a.txt");
boolean b4 = f4.delete();
System.out.println(b4);
}
2.4 File的常见成员方法(获取并遍历)
public static void main(String[] args) {
File f = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile");
//获取当前该路径下所有内容
File[] files = f.listFiles();
for (File file : files) {
System.out.println(file);
}
}
public static void main(String[] args) {
//0.获取系统中所有的盘符
File[] arr = File.listRoots();
System.out.println(Arrays.toString(arr));
//1.获取当前该路径下所有内容(仅仅能获取名字)
File f1 = new File("G:\\code\\Java\\basic_code\\day27_code\\src\\myFile");
String[] arr2 = f1.list();
System.out.println(Arrays.toString(arr2));
//2.利用文件名过滤器获取当前该路径下所有内容
//需求:获取文件夹里面所有的.txt文件
//方法一:
String[] arr3 = f1.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
File src = new File(dir, name);
return src.isFile() && name.endsWith(".txt");
}
});
System.out.println(Arrays.toString(arr3));
//方法二:
File[] arr5 = f1.listFiles();
for (File file : arr5) {
if (file.isFile() && file.getName().endsWith(".txt")) {
System.out.println(file);
}
}
//利用文件名过滤器获取当前该路径下所有内容
File[] arr6 = f1.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isFile() && pathname.getName().endsWith(".txt");
}
});
System.out.println(Arrays.toString(arr6));
File[] arr7 = f1.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
File file = new File(dir, name);
return file.isFile() && file.getName().endsWith(".txt");
}
});
System.out.println(Arrays.toString(arr7));
}
三、综合练习
练习一:(创建文件)
需求:
在当前模块下的aaa文件夹中创建一个a.txt文件
public static void main(String[] args) throws IOException {
//需求:
// 在当前模块下的aaa文件夹中创建一个a.txt文件
//0.创建aaa文件夹
File f1 = new File("day27_code\\aaa");
boolean b = f1.mkdirs();
System.out.println(b);
//1.创建a.txt文件
File f2 = new File(f1,"a.txt");
boolean b2 = f2.createNewFile();
System.out.println(b2);
}
练习二:(单个文件夹查找文件)
需求:
定义一个方法找某一个文件夹中,是否有以avi结尾的电影。
(暂时不需要考虑字文件夹)
public static void main(String[] args) {
//需求:
// 定义一个方法找某一个文件夹中,是否有以avi结尾的电影。
// (暂时不需要考虑字文件夹)
File f = new File("day27_code/aaa");
boolean b = haveAvi(f);
System.out.println(b);
}
/*作用:找某一个文件夹中是否有以avi结尾的电影
* 形参:要查找的文件
* 返回值:查找的结果 存在 true 不存在 false*/
private static boolean haveAvi(File file) {
File[] files = file.listFiles();
for (File f : files) {
if (f.isFile() && f.getName().endsWith(".avi")){
return true;
}
}
return false;
}
练习三:(遍历硬盘查找文件)
需求:
找到电脑中所有以avi结尾的电影(需要考虑子文件夹)
套路:
1. 进入文件夹
2. 遍历数组
3. 判断
4. 判断
public static void main(String[] args) {
/*需求:
找到电脑中所有以avi结尾的电影(需要考虑子文件夹)
*/
// File f = new File("C:/");
findAvi();
}
private static void findAvi(){
File[] files = File.listRoots();
for (File file : files) {
findAvi(file);
}
}
private static void findAvi(File src) {
//进入文件夹src
File[] files = src.listFiles();
if (files != null){
//遍历数组,依次得到文件夹中的每一个文件或文件夹
for (File file : files) {
if (file.isFile()) {
//判断-是否是文件
String name = file.getName();
if (name.endsWith(".avi")) {
System.out.println(file);
}
} else {
//判断-是否是文件夹
//递归
findAvi(file);
}
}
}
}
练习四:(删除文件夹)
需求:
删除一个多级文件夹
如果我们要删除一个有内容的文件夹
1. 先删除文件夹里面所有的内容
2. 再删除自己
public static void main(String[] args) {
/*删除一个多级文件夹*/
File f = new File("day27_code/aaa");
delete(f);
}
private static void delete(File src) {
//1. 先删除文件夹里面所有的内容
//进入文件夹
File[] files = src.listFiles();
//遍历
for (File file : files) {
//判断是否是文件
if (file.isFile()) {
file.delete();
} else {
//判断是否是文件夹
delete(file);
}
}
//2. 再删除自己
src.delete();
}
练习五:(统计文件夹大小)
需求:
统计一个文件夹的总大小
public static void main(String[] args) {
/* 需求:
统计一个文件夹的总大小*/
File f = new File("G:\\code\\Java\\basic_code\\day27_code\\src");
long len = getLen(f);
System.out.println(len);
}
private static long getLen(File src) {
long len = 0;
//进入文件夹
File[] files = src.listFiles();
for (File file : files) {
if (file.isFile()) {
len += file.length();
} else {
len += getLen(file);
}
}
return len;
}
练习六:(统计各种文件数量)
需求:统计一个文件夹中每种文件的个数并打印(考虑子文件夹)
1. 打印格式如下:
2. txt:3个
3. doc:4个
4. jpg:6个
public static void main(String[] args) {
/*需求:统计一个文件夹中每种文件的个数并打印(考虑子文件夹)
1. 打印格式如下:
2. txt:3个
3. doc:4个
4. jpg:6个*/
File f = new File("day27_code/aaa");
HashMap<String, Integer> count = getCount(f);
System.out.println(count);
}
/*
* 作用:
* 统计文件夹中文件的个数
* 参数
* 要统计的那个文件夹
* 返回值
* Map(后缀名:次数)*/
private static HashMap<String, Integer> getCount(File src) {
//0.创建集合
HashMap<String, Integer> hm = new HashMap<>();
//1.进入文件夹
File[] files = src.listFiles();
//2.遍历
for (File file : files) {
if (file.isFile()) {
//3.判断是文件
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 {
//4.判断是文件夹
HashMap<String, Integer> sonMap = getCount(file);
//遍历sonMap把里面的值累加到hm当中
Set<Map.Entry<String, Integer>> entries = sonMap.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();
Integer 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;
}