本章目录
异常
1、异常机制概述
异常机制是指当程序出现错误时,程序处理错误的做法。
异常机制提供了程序发生异常时的安全退出通道,当程序发生异常时,程序的执行流程改变,程序将控制权转交给异常处理器,由异常处理器对异常进行安全处理。
2、异常的结构
在 Java 中,异常的顶级父类为 Throwable 类,它有两个子类实例 Error 和 Exception,通常用于指示发生了异常情况。
Error:错误,程序运行中发生的较严重的问题,程序无法处理,大多数与编程人员无关,而是计算机能力方面的问题。例如:内存溢出。这些错误不可察,因为它们在程序的控制和处理能力之外,绝大多数的程序运行时不允许出现这些情况。对于设计合理的程序来说,即使发生了 Error,本质上也不应该去处理由它引起的状况。
Exception:异常,指程序本身可以处理的异常,通常情况下,编程人员就可以使用某些手段对这类异常进行修改或避免这类异常的发生。它又分为编译期异常和运行期异常。
编译期异常:是从语法角度上讲必须要处理的异常,如果不处理,编译就无法通过。
运行期异常:译为 RuntimeException,这些异常一般是逻辑不当引发的异常,Java 编译器无法检查出来,即使不对其进行处理,编译也会通过。
3、异常结构图解
4、异常处理
抛出异常:当某处代码发生异常时,抛给代码所属的方法,由系统负责处理异常代码。
注意:
- 父类的方法没有抛出异常,子类重写父类该方法时,也不能抛出异常。
- 父类方法抛出异常,子类重写该方法时,可以不抛出异常。
- 子类重写父类方法时,不能抛出父类没有抛出的异常。
- 子类抛出的异常类型不能比父类大,只能比父类小或与父类相同。
格式:
public void method() throws 异常名{
//方法体
}
捕捉异常:当某处代码发生异常时,编程人员对异常进行处理,程序运行至异常代码处时,执行编程人员写好的异常处理规则,不再由系统对异常进行处理。
捕捉异常需要使用 try-catch 或 try-catch-finally 语句块。当 try 中语句发生异常时,转而执行 catch 中的代码。finally 中的语句在异常处理的最后执行,通常用来释放资源。
格式 1:
try{
//可能出现异常的代码
}catch(异常类型 对象名){
//异常处理语句
}
格式 2:
try{
//可能出现异常的代码
}catch(异常类型1 对象名){
//异常处理语句
}catch(异常类型2 对象名){
//异常处理语句
}catch(异常类型3 对象名){
//异常处理语句
}
...
格式 3:
try{
//可能出现异常的代码
}catch(异常类型1 | 异常类型2 | ... 对象名 ){
//异常处理语句
}
格式 4:
try{
//可能出现异常的代码
}catch(异常类型 对象名){
//异常处理语句
}finally{
//释放资源
}
对于错误、编译期异常、运行期异常,一般在 Java 中的处理方式不同。
- 错误:对于程序运行时可能出现的 Error,一般不做任何处理,因为大多数的 Error 超出了程序处理的能力。
- 编译期异常:对于所有编译期的异常,必须捕捉,或抛出方法之外。
- 运行时异常:运行时异常将由程序运行时自动抛出。
5、异常案例
5.1、编译期异常
编译期发生异常时,我们既可以抛出异常给 JVM 处理,也可以手动捕获处理。
抛出异常:
public class Exception01 {
public static void main(String[] args) throws ParseException {
String s = "2020年12月15日";
Date date = new SimpleDateFormat("yyyy-MM-dd").parse(s);
System.out.println(date);
}
}
捕捉异常:
public class Exception01 {
public static void main(String[] args){
String s = "2020年12月15日";
Date date = null;
try {
date = new SimpleDateFormat("yyyy-MM-dd").parse(s);
} catch (ParseException e) {
System.out.println("日期格式有误,参照格式:yyyy-MM-dd");
}
System.out.println(date);
}
}
5.2、运行期异常
运行时发生的异常,可以交由 JVM 处理,我们不做处理,但 JVM 处理的方式并不友好,它的处理方式为,终止运行程序,在控制台打印异常信息。
public class Exception02 {
public static void main(String[] args) {
int a = 10;
int b = 0;
//除数为 0,JVM 的处理方式为停止程序,打印异常的堆栈信息
System.out.println(a / b);
}
}
既然 JVM 的处理方式不友好,那么我们通常对运行时异常进行手动捕获处理。
public class Exception02 {
public static void main(String[] args) {
int a = 10;
int b = 0;
try {
int c = a / b;
System.out.println(c);
}catch (ArithmeticException e){
System.out.println("除数为 0 了");
}
}
}
捕获异常时,尽量明确异常的类型,当异常是平级关系时,catch 的先后无所谓。如果异常之间有继承关系,父类异常在最后的 catch 语句中。当捕捉到一处异常后,try 中异常后的语句不再执行。
public class Exception03 {
public static void main(String[] args) {
int a = 10;
int b = 0;
int[] arr = {1,20};
try {
System.out.println(arr[6]); //数组角标越界
System.out.println(a / b); //不再捕捉此处异常
}catch (ArithmeticException e){
System.out.println("除数为 0 异常");
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("数组角标越界异常");
}catch (NullPointerException e){
System.out.println("空指针异常");
}catch (Exception e){
System.out.println("其他异常");
}
}
}
public class Exception04 {
public static void main(String[] args) {
int a = 10;
int b = 0;
int[] arr = {1,20};
try {
System.out.println(arr[6]);
}catch (ArithmeticException | ArrayIndexOutOfBoundsException e){
if (e instanceof ArithmeticException){
System.out.println("除数为 0 异常");
}else if(e instanceof ArrayIndexOutOfBoundsException){
System.out.println("数组角标越界异常");
}else if (e instanceof NullPointerException){
System.out.println("空指针异常");
}
}
}
}
try-catch-finally 格式的使用:
public class Exception05 {
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入整数:");
int i = scanner.nextInt();
System.out.println("你输入的整数是:" + i);
} catch (InputMismatchException e) {
System.out.println("输入数据类型错误!");
} finally {
scanner.close();
}
}
}
判断输入类型正确后再录入数据:
public class Exception06 {
public static void main(String[] args) {
while (true){
Scanner scanner = new Scanner(System.in);
System.out.println("请输入整数:");
try {
int i = scanner.nextInt();
System.out.println(i);
break;
}catch (InputMismatchException e){
System.out.print("输入类型有误,");
}
}
}
}
5.3、throws 与 throw
throws:用在方法声明上,可以抛出一个或多个异常类型,多个异常中间用逗号隔开,它只表示发生某异常的可能性,在程序运行中并不一定会发生此异常。
throw:用在方法的内部,只能抛出一个异常,并且抛出的是一个具体的异常对象,一旦抛出,就说明程序一定发生了此异常。
public class Exception07 {
public static void main(String[] args) {
int a = 10;
int b = 0;
if (b == 0){
throw new ArithmeticException();
}else {
System.out.println(a / b);
}
}
}
5.4、自定义异常
Java 中给出的异常种类很多,但有时并不能准确描述一个异常,所以 Java 给我们提供了自定义异常,让编程人员在开发中可以更准确的描述现实中发生的异常。
案例:考试成绩为:0 ~ 100,判断录入成绩是否合理。
在 Java 中不存在成绩不合理异常,所以我们需要自定义这个异常,自定义的方法很简单,编写一个类,让这个类继承 Exception 或 RuntimeException 即可。
自定义异常类:
public class IsRight extends RuntimeException{
public IsRight(String message) {
super(message);
}
}
测试类:
public class Exception08 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请数入你的成绩(0~100):");
int i = scanner.nextInt();
if (i >= 0 & i <= 100 ){
System.out.println("你的成绩为:"+i);
}else {
throw new IsRight("输入的成绩不合理。");
}
}
}
File 类
1、File 类概述
Java 中的 File 类是 java.io 包中唯一代表磁盘文件的对象,通过 File 类,可以实现对文件和目录的有关操作。
File 类中定义了一些获取和处理文件信息的方法,例如:新建、删除、重命名文件和目录等,但 File 类不具有操作文件内容的方法,例如:读取文件信息和向文件写入信息。
所以,File 类仅仅描述文件本身的属性。
2、文件存储路径
在计算机中,每一个文件都有存储的位置,称为存储路径。只有在正确的路径下,才能访问到需要的文件。
文件的存储路径分为:绝对路径、相对路径。
绝对路径:完整描述文件位置的路径,例如:E:/BaiduNetdiskDownload/a.txt
相对路径:相对于某文件位置的路径,例如:/a.txt
,表示当前目录下的 a.txt 文件。
另外,使用../
来表示上一级目录,../../
表示上上级目录,以此类推。
3、File 类常用方法
3.1、构造方法
//根据指定路径名字符串来创建一个 File 实例。
File(String pathname)
//根据 parent 文件路径和 child 文件名创建一个 File 实例。
File(File parent, String child)
//根据 parent 路径名和 child 文件名创建一个 File 实例。
File(String parent, String child)
3.2、封装功能
封装功能就是将一个路径封装成一个 File 文件,通常使用构造方法对路径进行封装。
public class File01 {
public static void main(String[] args) {
//绝对路径封装文件 File(String pathname)
File file = new File("E:\\BaiduNetdiskDownload\\a.txt");
//相对路径封装文件,表示该目录下的 test.txt 文件
File file1 = new File("test.txt");
//父路径名和子文件名封装文件 File(String parent, String child)
File file2 = new File("E:\\BaiduNetdiskDownload\\", "a.txt");
//根据父文件路径和子文件名封装文件 File(File parent, String child)
File file3 = new File("E:\\BaiduNetdiskDownload");
File file4 = new File(file3, "a.txt");
}
}
3.3、创建功能
方法 | 作用 |
---|---|
createNewFile() | 当不存在此路径名指定的文件时,创建一个新的空文件 |
mkdir() | 创建此路径名指定的单级目录 |
mkdirs() | 创建此路径名指定的所有目录 |
public class File02 {
public static void main(String[] args) {
//如果该文件不存在,创建该文件,返回 true
//如果文件已存在,不重复创建,返回 false
File file = new File("E:\\BaiduNetdiskDownload\\b.txt");
try {
boolean newFile = file.createNewFile();
System.out.println(newFile);
} catch (IOException e) {
e.printStackTrace();
}
//创建单级目录
File file1 = new File("E:\\BaiduNetdiskDownload\\testDir1");
boolean mkdir = file1.mkdir();
System.out.println(mkdir);
//创建多级目录
File file2 = new File("E:\\BaiduNetdiskDownload\\testDir1\\testDir1-1\\testDir1-1-1");
boolean mkdirs = file2.mkdirs();
System.out.println(mkdirs);
}
}
3.4、删除/重命名或剪切重命名
方法 | 作用 |
---|---|
delete() | 删除路径表示的文件或目录 |
renameTo(File dest) | 重命名文件或剪切后再重命名文件 |
delete() 方法删除文件时,为永久删除,返回值表示是否删除成功,被删除的文件无法在回收站找到,同时,它只能删除单级目录,不能删除多级目录,要想删除多级目录,需要使用递归。
public class File03 {
public static void main(String[] args) {
//永久删除文件
File file = new File("E:\\BaiduNetdiskDownload\\a.txt");
boolean delete = file.delete();
System.out.println(delete);
//删除单机目录
File file1 = new File("E:\\BaiduNetdiskDownload\\testDir2");
try {
boolean newFile = file1.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
boolean delete1 = file1.delete();
System.out.println(delete1);
//删除多级目录,testDir1下有testDir1-1,testDir1-1下有testDir1-1-1
File file2 = new File("E:\\BaiduNetdiskDownload\\testDir1");
boolean delete2 = file2.delete();
System.out.println(delete2);
}
}
renameTo(File dest) 方法有两个作用:重命名、剪切重命名。
重命名:当传入的新文件路径和旧文件的路径一致,只是文件名不同,就会将文件重命名。
剪切:如果传入的新文件路径和旧文件路径不一致,并且文件名不同,就会剪切旧文件至新文件路径并重命名。
public class File04 {
public static void main(String[] args) {
//重命名
File file = new File("E:\\BaiduNetdiskDownload\\b.txt");
File file1 = new File("E:\\BaiduNetdiskDownload\\c.txt");
boolean b = file.renameTo(file1);
System.out.println(b);
//剪切并重命名
File file2 = new File("E:\\BaiduNetdiskDownload\\c.txt");
File file3 = new File("E:\\BaiduNetdiskDownload\\testDir1\\d.txt");
boolean b1 = file2.renameTo(file3);
System.out.println(b1);
}
}
3.5、判断功能
方法 | 作用 |
---|---|
isFile() | 判断路径名表示的是否为一个文件 |
isDirectory() | 判断路径名表示的文件是否为一个目录 |
isHidden() | 判断路径名表示的是否为一个隐藏文件 |
isAbsolute() | 判断路径名是否是绝对路径 |
canRead() | 判断路径表示的文件是否可读 |
canWrite() | 判断路径表示的文件是否可写 |
canExecute() | 判断路径表示的文件是否可执行 |
exists() | 判断路径表示的文件是否存在 |
public class File05 {
public static void main(String[] args) {
File file = new File("E:\\BaiduNetdiskDownload\\testDir1\\d.txt");
//判断路径名表示的是否为一个文件
boolean b = file.isFile();
System.out.println(b);
//判断路径名表示的文件是否为一个目录
boolean b1 = file.isDirectory();
System.out.println(b1);
//判断路径名表示的是否为一个隐藏文件
boolean b2 = file.isHidden();
System.out.println(b2);
//判断路径名是否是绝对路径
boolean b3 = file.isAbsolute();
System.out.println(b3);
//判断路径表示的文件是否可读
boolean b4 = file.canRead();
System.out.println(b4);
//判断路径表示的文件是否可写
boolean b5 = file.canWrite();
System.out.println(b5);
//判断路径表示的文件是否可执行
boolean b6 = file.canExecute();
System.out.println(b6);
//判断路径表示的文件是否存在
boolean b7 = file.exists();
System.out.println(b7);
}
}
3.6、获取功能
方法 | 作用 |
---|---|
long length() | 获取文件的字节数 |
String getName() | 获取文件名称 |
String getParent() | 以字符串形式获取文件的父路径 |
File getParentFile() | 获取当前文件的父文件 |
String getAbsolutePath() | 以字符串形式获取文件的绝对路径 |
File getAbsoluteFile() | 获取绝对路径并封装成文件 |
String getPath() | 以字符串形式获取文件的相对路径 |
long getTotalSpace() | 获取磁盘总大小,单位为:字节 |
long getFreeSpace() | 获取磁盘剩余大小,单位为:字节 |
long lastModified() | 获取文件最后一次的修改时间,是一个毫秒值 |
String[] list() | 获取指定路径下所有文件和目录的名称 |
File[] listFiles() | 获取指定路径下所有文件和目录 |
public class File06 {
public static void main(String[] args) {
File file = new File("E:\\BaiduNetdiskDownload\\testDir1\\d.txt");
File file1 = new File("D:\\");
//获取文件的字节数
long length = file.length();
System.out.println(length);
//获取文件名称
String name = file.getName();
System.out.println(name);
//以字符串形式获取文件的父路径
String parent = file.getParent();
System.out.println(parent);
//获取当前文件的父文件
File parentFile = file.getParentFile();
System.out.println(parentFile.toString());
//以字符串形式获取文件的绝对路径
String absolutePath = file.getAbsolutePath();
System.out.println(absolutePath);
//获取绝对路径并封装成文件
File absoluteFile = file.getAbsoluteFile();
System.out.println(absoluteFile.toString());
//以字符串形式获取文件的相对路径
String path = file.getPath();
System.out.println(path);
//获取磁盘总大小,单位为:字节
long totalSpace = file1.getTotalSpace();
System.out.println(totalSpace);
//获取磁盘剩余大小,单位为:字节
long freeSpace = file1.getFreeSpace();
System.out.println(freeSpace);
//获取文件最后一次的修改时间,是一个毫秒值
long l = file.lastModified();
Date date = new Date(l);
String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
System.out.println(format);
//获取指定路径下所有文件和目录的名称
String[] list = file1.list();
System.out.println(Arrays.toString(list));
//获取指定路径下所有文件和目录
File[] files = file1.listFiles();
System.out.println(Arrays.toString(files));
}
}
3.7、过滤功能
过滤方法其实是获取指定路径下所有文件和目录方法的重载,参数需要传递一个过滤器,常常采用匿名类的方式传递参数,跟据过滤器的返回值来决定要不要将文件或目录加入返回的 file 数组。返回值为 true 将文件或目录添加进返回数组,false 则为不添加。
方法 | 功能 |
---|---|
File[] listFiles(FilenameFilter filter) | 使用名称过滤器过滤出需要返回的文件或目录 |
File[] listFiles(FileFilter filter) | 使用文件过滤器过滤出需要返回的文件或目录 |
public class File07 {
public static void main(String[] args) {
File file = new File("E:\\BaiduNetdiskDownload");
//使用名称过滤器过滤出想要的文件
File[] files = file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
//dir 是父文件,name 是子文件名
File file1 = new File(dir, name);
if (file1.isFile() & file1.getName().endsWith(".txt")) {
return true;
} else {
return false;
}
}
});
System.out.println(Arrays.toString(files));
//使用文件过滤器过滤出想要的文件
File[] files1 = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.isFile() & pathname.getName().endsWith(".txt")) {
return true;
} else {
return false;
}
}
});
System.out.println(Arrays.toString(files1));
}
}
3.8、递归删除指定类型文件
需求:删除指定目录中.txt
类型的所有文件。
public class File08 {
public static void main(String[] args) {
File file = new File("E:\\BaiduNetdiskDownload");
forDelete(file);
}
public static void forDelete(File file){
//获取出传递过来的所有文件
File[] files = file.listFiles();
//遍历文件
for (File file1 : files) {
//如果遍历出的是以 .txt 结尾的文件,直接删除
if (file1.isFile() & file1.getName().endsWith(".txt")){
file1.delete();
}else {
//遍历出的是目录,递归调用这个方法再去处理目录
forDelete(file1);
}
}
}
}
夜色太沉,我只用一个手势吧,就如同你曾轻轻地招手,我便押上了自己的一生.
各位看官,本章结束,我们下篇见 (∩_∩)~~
-Czx.