菜鸟之路Day14一一异常与File
作者:blue
时间:2025.2.2
1.异常
1.1异常体系
Error:代表的系统级别错误(属于严重问题)系统一旦出现问题,sun公司会把这些错误封装成Error对象。Error是给sun公司自己用的,不是给我们程序员用的。因此我们开发人员不用管它。
Exception:叫做异常,代表程序可能出现的问题。我们通常会用Exception以及它的子类来封装程序出现的问题
运行时异常:RuntimeException及其子类,编译阶段不会出现异常提醒。运行时出现的异常(如:数组索引越界异常)
编译时异常:直接继承于Excpetion,编译阶段就会出现异常提醒。(如:日期解析异常)
1.2异常的作用
作用一:异常时用来查询bug的关键参考信息
作用二:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
1.3异常的处理方式
①JVM默认的处理方式
把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
程序停止执行,下面的代码不会再执行了
②自己处理(捕获异常)
try {
可能出现异常的代码;
} catch(异常类名 变量名) {
异常的处理代码;
}
目的:当代码出现异常的时候,可以让程序继续往下执行
public class Demo1 {
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){
//如果出现了ArrayIndexOutOfBoundsException异常,我该如何处理
System.out.println("索引越界了");
}
System.out.println("看看我执行了吗?");
}
}
有关捕获异常的四个问题
一.如果try中没有遇到问题,怎么执行?
public class Demo1 {
public static void main(String[] args) {
int[] arr = {
1,2,3,4,5,6};
try{
//正常的代码
System.out.println(arr[0]);
}catch(ArrayIndexOutOfBoundsException e){
//如果出现了ArrayIndexOutOfBoundsException异常,我该如何处理
System.out.println("索引越界了");
}
System.out.println("看看我执行了吗?");
}
}
答:会把try里面的所有代码全部执行完毕,不会执行catch里面的代码,只有当出现了异常才会执行catch里面的代码
二.如果try中可能遇到多个问题,怎么执行?
public class Demo2 {
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);
}catch(ArrayIndexOutOfBoundsException e){
//如果出现了ArrayIndexOutOfBoundsException异常,我该如何处理
System.out.println("索引越界了");
}catch (ArithmeticException e){
System.out.println("不能做除0操作");
}
System.out.println("看看我执行了吗?");
}
}
答:我们会写多个catch与之对应,如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面,在JDK7之后,我们可以在catch中同时捕获多个异常,中间用|进行隔开,表示如果出现了A异常或者B异常,采取同一种处理方案。
三.如果try中遇到问题没有被捕获,怎么执行?
答:相当于try....catch的代码白写了,
四.如果try中遇到了问题,那么try下面的其他代码还会执行吗?
答:下面的代码不会执行了,直接跳转到对应的catch当中,执行catch里面的语句体,但是如果没有对应catch与之匹配,那么还是会交给虚拟机进行处理
③抛出异常
1.关于抛出异常的一些常用方法(Throwable的成员方法)
public class Demo3 {
public static void main(String[] args) {
/*
* public String getMessage() 返回此throwable的详细消息字符串
* public String toString() 返回此可抛出的简短描述
* public void printStackTrace() 把异常的错误信息输出在控制台
* 细节:仅仅是打印信息,不会停止程序运行
* */
int[] arr = {
1,2,3,4,5,6};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e){
/*String message = e.getMessage();
System.out.println(message); Index 10 out of bounds for length 6 */
/*String str = e.toString();
System.out.println(str); java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 6*/
e.printStackTrace();
}
System.out.println("看看我执行了吗?");
}
}
2.抛出处理
①throws:写在方法定义处,表明声明一个异常,告诉调用者,使用本方法可能会有哪些异常
编译时异常:必须要写
运行时异常:可以不写
public void 方法()throws 异常类名1,异常类名2...{
...
}
②throw:写在方法内,结束方法
手动抛出异常对象,交给调用者
方法中下面的代码不再执行了
public void 方法(){
throw new NullPointerException();
}
实例:
public class Demo4 {
public static void main(String[] args) {
int[] arr = null;
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){
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(arr[i]>max) max = arr[i];
}
return max;
}
}
练习:
需求:
键盘录入自己心仪的女朋友姓名和年龄。
姓名的长度在3~10之间
年龄的范围为18-40岁
超出这个范围是异常数据不能赋值,需要重新录入,一直录到正确为止。
提示
需要考虑用户在键盘录入时的所有情况。
比如:录入年龄时超出范围,录入年龄时录入了abc等情况
public class Demo5 {
public static void main(String[] args) {
GirlFriend gf = new GirlFriend();
Scanner sc = new Scanner(System.in);
while (true) {
try {
System.out.println("请输入你心仪女朋友的姓名");
String name = sc.nextLine();
gf.setName(name);//有可能出现错误
System.out.println("请输入女朋友的年龄");
String age = sc.nextLine();
int Age = Integer.parseInt(age);//有可能出现错误
gf.setAge(Age);//有可能出现错误
break;
} catch (NumberFormatException e) {
System.out.println("年龄的格式有误,请输入数字");
} catch (RuntimeException e) {
System.out.println("姓名或年龄超出范围");
}
}
System.out.println(gf);
}
}
在GirlFriend类中,对set方法的数据做限定,如果不是正确数据,就抛出一个RuntimeException对象
public class GirlFriend {
private String name;
private int age;
public GirlFriend() {
}
public GirlFriend(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
if(name.length()<3||name.length()>10){
throw new RuntimeException();
}
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<18||age>40){
throw new RuntimeException();
}
this.age = age;
}
@Override
public String toString() {
return "GirlFriend{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
1.4自定义异常
在刚刚的练习代码中,我们针对名字和年龄的异常都是抛出一个RuntimeException,但不够具体,不够见名知意,这时我们就可以自定义异常。
①定义异常类
②写继承关系
③空参构造
④带参构造
意义:让控制台的报错信息更加见名知意
现在的idea建类的时候都有Exception选项
public class NameFormatException extends RuntimeException {
public NameFormatException() {
}
public NameFormatException(String message) {
super(message);
}
}
然后我们修改对应的抛出错误的方法
public void setName(String name) {
if(name.length()<3||name.length()>10){
throw new NameFormatException(name+"姓名的长度在3~10之间");
}
this.name = name;
}
然后我们修改对应的catch异常的对象,调用方法把异常的错误信息输出在控制台即可
catch (NameFormatException e) {
e.printStackTrace();
}
2.File
2.1构造方法
File对象就表示一个路径,可以是文件的路径,也可以是文件夹的路径
这个路径可以是存在的,也允许是不存在的
构造方法演示:
public class Demo1 {
public static void main(String[] args) {
/*
* public File(String pathname) 把字符串表示的路径变成File对象
* public File(String parent,String child) 把父级路径和子级路径进行拼接
* public File(File parent,String child) 把父级路径和子级路径进行拼接
* windows: "\"
* java:"\"->转义字符,所以得有两个\\
* Linux:"/"
* */
String str = "C:\\Users\\zhangtenlan\\Desktop\\test.txt";
//1.public File(String pathname) 把字符串表示的路径变成File对象
File f1 = new File(str);
System.out.println(f1);//C:\Users\zhangtenlan\Desktop\test.txt
//2.public File(String parent,String child) 把父级路径和子级路径进行拼接
//父级路径:C:\Users\zhangtenlan\Desktop
//子级路径:test.txt
String parent = "C:\\Users\\zhangtenlan\\Desktop";
String child = "test.txt";
File f2 = new File(parent,child);
System.out.println(f2);//C:\Users\zhangtenlan\Desktop\test.txt
//3.public File(File parent,String child) 把父级路径和子级路径进行拼接
File fparent = new File(parent);
File f3 = new File(fparent,child);
System.out.println(f3);//C:\Users\zhangtenlan\Desktop\test.txt
}
}
2.2File的成员方法(判断,获取)
判断方法演示:
public class Demo2 {
public static void main(String[] args) {
//public boolean isDirectory() 判断此路径名表示的File是否为文件夹
//public boolean isFile() 判断此路径名表示的File是否为文件
//public boolean exists() 判断此路径名表示的File是否存在
//1.对一个存在的文件做判断
File f1 = new File("C:\\Users\\zhangtenlan\\Desktop\\test.txt");
System.out.println(f1.isDirectory());//false
System.out.println(f1.isFile());//true
System.out.println(f1.exists());//true
System.out.println("----------------------------------------------------");
//2.对一个存在的文件夹做判断
File f2 = new File("C:\\Users\\zhangtenlan\\Desktop\\TEST");
System.out.println(f2.isDirectory());//true
System.out.println(f2.isFile());//false
System.out.println(f2.exists());//true
System.out.println("----------------------------------------------------");
//3.对一个不存在的文件做判断
File f3 = new File("C:\\Users\\zhangtenlan\\Desktop\\aaa");
System.out.println(f3.isDirectory());//false
System.out.println(f3.isFile());//false
System.out.println(f3.exists());//false
}
}
获取方法演示:
public class Demo3 {
public static void main(String[] args) {
//1.public long length() 返回文件的大小(字节数量Byte)
File f1 = new File("C:\\Users\\zhangtenlan\\Desktop\\test.txt");
System.out.println(f1.length());//注意只能获取文件的大小,文件夹却不行
System.out.println("=================================================");
//2.public String getAbsolutePath() 返回文件的绝对路径
File f2 = new File("src/File");//用相对路径创建一个File对象
System.out.println(f2.getAbsoluteFile());//D:\some_test_project_of_my_own\Day14\src\File
System.out.println("=================================================");
//3.public String getPath() 返回定义文件时使用的路径
System.out.println(f2.getPath());//src\File
System.out.println("=================================================");
//4.public String getName() 返回文件名称,带后缀
System.out.println(f1.getName());//test.txt
System.out.println("=================================================");
//5.public long lastModified() 返回文件的最后修改时间(时间毫秒值)
System.out.println(f1.lastModified());//1738810278724
}
}
2.3File的成员方法(创建,删除)
public class Demo4 {
public static void main(String[] args) throws IOException {
//1.public boolean createNewFile() 创建一个新的空的文件
//如果当前路径表示的文件是不存在的,则创建成功,方法返回true
//如果当前路径表示的文件是存在的,则创建失败,方法返回false
//如果父级路径是不存在的,那么方法会有异常IOException
//该方法创建的一定是文件,如果路径中不包含后缀名,则创建一个没有后缀的文件
File f1 = new File("C:\\Users\\zhangtenlan\\Desktop\\test.txt");
System.out.println(f1.createNewFile());
//2.public boolean mkdir() 创建单级文件夹,没什么用,因为它mkdirs既能创建多级又能创建单级
//3.public boolean mkdirs() 创建多级文件夹
File f2 = new File("C:\\Users\\zhangtenlan\\Desktop\\aaa\\bbb\\ccc");
System.out.println(f2.mkdirs());
//4.public boolean delete() 删除文件,空文件夹
//如果删除的是文件,则直接删除,不走回收站
//如果删除的是空文件夹,则直接删除,不走回收站
//如果删除的是有内容的文件夹,则删除失败
System.out.println(f1.delete());
}
}
2.4File的成员方法(获取并遍历)
public class Demo5 {
public static void main(String[] args) {
/*
* public File[] listFiles() 获取当前该路径下所有内容
* 当调用者File表示的路径不存在时,返回null
* 当调用者File表示的路径是文件时,返回null
* 当调用者File表示的路径是一个空文件夹时,返回一个长度为0的数组
* 当调用者File表示的路径是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
* 当调用者File表示的路径是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
* 当调用者File表示的路径是需要权限才能访问的文件夹时,返回null
* */
File f1 = new File("C:\\Users\\zhangtenlan\\Desktop\\aaa");
File[] arr = f1.listFiles();
for(File f : arr){
System.out.println(f);
}
}
}
内容学习至黑马程序员BV1yW4y1Y7Ms