一、异常
在学习IO流之前,我们需要先了解异常和File文件类。File表示的是IO流将来要进行操作的文件,常见的操作是上传和下载,操作过程中可以会出现一些问题,需要处理问题,所以需要学习异常
1.1 异常的概述以及分类
异常:指的是程序在执行过程中,出现的非正常情况,最终会导致JVM的非正常停止
在Java这种面向对象的编程语言中,异常本身就是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式为终端处理
1.2 异常体系
异常机制其实是帮助我们找到程序中存在的问题,异常的根类是Throwable,下面有两个子类:Error和Exception。
Error:严重错误,无法处理的错误也不予处理,只能事先避免。
Exception:表示异常,异常产生后可以通过代码的方式纠正,使得程序继续运行。
1.3 JVM默认处理异常
main方式收到这个问题时,有两种处理方式
1.main方法自己处理该问题,然后继续运行
2.自己没有处理方式,交给调用main方法的JVM进行处理。JVM默认的处理将异常的名称、信息、出现的位置打印在了控制台,并且同时停止程序的运行。
1.4 Throwable的常用方法
public void printStackTrace() ://打印异常的详细信息。
包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。
public String getMessage() ://获取发生异常的原因。
提示给用户的时候,就提示错误原因。
public String toString() ://获取异常的类型和异常描述信息(不用)。
1.5 异常的分类
- 编译时期异常:checked异常。在编译时期,就会检查。如果没有处理异常,则编译失败(日期格式化异常)
- 运行时期异常:runtime异常。在运行时期,检查异常。在编译时期,运行异常不会编译器检测(不报错)(数学异常)
public class Test01 {
public static void main(String[] args) throws ParseException {
//编译器异常:日期格式化异常
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
//编译器异常,必须处理,抛出异常 处理:main方法抛出ParseException
Date parse = simpleDateFormat.parse("2012-12-22");
System.out.println(parse);
//运行期异常 数学异常 打印ArithmeticException: / by zero 除数为0异常
int a=1;
int b=0;
System.out.println(a/b);
}
}
public class Test02 {
public static void main(String[] args) {
int[] arr={10,20,30};
int element = getElement(arr, 4);
System.out.println(element);
}
private static int getElement(int[] arr,int index) {
return arr[index];
}
}
对Test02程序的执行过程进行分析
在getElement方法中,由于没有找到参数的索引,导致程序运行时发生了异常,这个异常JVM认识。Java中对于这种异常有具体的描述,其内容包括:异常的名称、内容以及产生的位置。Java将这些信息直接封装到ArrayIndexOutOfBoundsException异常的一个对象中。
JVM将异常抛出给方法的调用者main方法中。main方法接受这个异常对象,由于main方法没有处理这个异常,main方法就会将这个异常抛出给调用者JVM,当JVM收到异常是,就会将异常的内容打印在控制台,同时停止程序的运行。
1.6 异常的处理
如果异常出现的话,会终止程序的运行,所以必须处理异常
1.6.1 捕获异常
捕获异常:Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理
(1) try…catch
try…catch的方式就是捕获异常。
try{
编写可能会出现异常的代码
}catch(异常类型 e){
处理异常的代码
}
注意:
- try和catch都不能单独使用,必须一起使用
- try中的代码越少越好
- catch中要做处理,哪怕是一条输出语句也可以.(不能将异常信息隐藏)
使用演示:
public class Test03 {
public static void main(String[] args) {
int a=1;
int b=0;
try {
//可能出现问题的代码
System.out.println(a/b);
}catch (ArithmeticException e ){//异常名和对象
//处理语句
System.out.println("除数为0");
}
}
}
这样捕获到异常之后,程序会执行catch中的代码,不会在控制台打印异常信息
(2) finally代码块
finally:有一些特定的代码无论异常是否发生,都需要执行。另外,因为有些异常会引发程序发生跳转,导致有一些语句不能被执行到。而finally就是解决这个问题,finally中存放的代码都是一定会执行的。一般用于释放资源
注意:在执行finally之前,如果JVM退出则finally语句执行不到(System.exit(0))
public class FinallyDemo {
public static void main(String[] args) {
List<Integer> list=new ArrayList();
list.add(1);
list.add(2);
list.add(3);
try {
Integer integer = list.get(3);
System.out.println(integer);
}catch (IndexOutOfBoundsException e){
System.out.println("出现异常情况");
}finally {
System.out.println("finally代码执行了");
}
//finally代码不执行
try {
int[] arr={1,2,3};
System.out.println(arr[3]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("出现异常情况2");
//停止JVM finally代码执行不能够执行
System.exit(0);
}finally {
System.out.println("finally代码执行了");
}
}
}
运行结果
1.6.2 抛出异常throw
在编写程序时,必须要考虑程序出现问题的情况。比如,在定义方法时,方法需要接受参数。那么,当调用方
法使用接受到的参数时,需要先对参数数据进行合法的判断,数据若不合法,就应该告诉调用者,传递合法的
数据进来。这时需要使用抛出异常的方式来告诉调用者。
Java中就提供了throw关键字,用来抛出一个指定的异常对象,封装一些提示信息
使用格式:throw new 异常类名(参数);
代码演示:
public class ThrowDemo {
public static void main(String[] args) {
/* int[] arr2={1,2,3,4,5};
int element1 = getElement(arr2, 10);
//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 传递的索引越界
System.out.println(element1);*/
int[] arr=null;
int element = getElement(arr, 2);
//Exception in thread "main" java.lang.NullPointerException: 传递的数组为空数组
System.out.println(element);
}
public static int getElement (int[] arr,int index){
//运行期异常
if (arr==null){
throw new NullPointerException("传递的数组为空数组");
}
if (index<0||index>arr.length-1){
//判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续进行,就会结束当前方法,将异常告知调用者。
throw new ArrayIndexOutOfBoundsException("传递的索引越界");
}
int i = arr[index];
return i;
}
}
对于调用者来说处理异常有两种方式,一种是进行捕获处理,另一种就是继续讲异常声明处理,使用throws声明处理
1.6.3 声明异常throws
声明异常:将问题标识出来,告知调用者,如果方法内通过throw抛出了编译时异常,而没有进行捕获处理,那么必须通过throws进行声明,让调用者进行处理
关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
格式:修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }
代码:
public class ThrowDemo {
public static void main(String[] args)throws NullPointerException,ArrayIndexOutOfBoundsException {
/* int[] arr2={1,2,3,4,5};
int element1 = getElement(arr2, 10);
//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 传递的索引越界
System.out.println(element1);*/
int[] arr=null;
int element = getElement(arr, 2);
//Exception in thread "main" java.lang.NullPointerException: 传递的数组为空数组
System.out.println(element);
}
public static int getElement (int[] arr,int index)throws NullPointerException{
//运行期异常
if (arr==null){
throw new NullPointerException("传递的数组为空数组");
}
if (index<0||index>arr.length-1){
throw new ArrayIndexOutOfBoundsException("传递的索引越界");
}
int i = arr[index];
return i;
}
}
main声明的异常由于没有进行处理,将异常抛给调用者JVM,JVM使用默认的处理异常方式进行处理
throws用于进行异常类的声明,若方法可能会 出现多个异常,那么throws后面可以写多个异常类,用,隔开
1.6.4 抛出异常throw与声明异常throws的区别
throw:用在方法体内,跟的是异常类的一个对象(只能抛出一个对象名)
异常可以为编译期,也可以为运行期
表示抛出异常,由方法体内的语句处理
throw是抛出了异常,执行throw则一定抛出了某种异常
throws:用在方法声明的后面,跟的是异常类名
可以跟多个异常类名,中间使用逗号隔开
表示声明异常,有方法的调用者来处理
throws表示出现异常的可能性,并不一定会发生该异常
1.7 自定义异常
在开发过程中根据自己的需求来定义一个异常类,可以定义编译期异常,也可以是运行期异常。
自定义编译期异常,继承Exception。
自定义运行期异常,继承RuntimeException
自定义一个异常类RegisterException,用来进行用户的注册
RegisterException类:
public class RegisterException extends Exception {
public RegisterException(){
super();
}
//添加一个带异常信息的构造方法
public RegisterException(String s){
super(s);
}
}
测试类,用来测试用户名是否被注册
public class RegisterExceptionDemo2 {
static String[] usernames={"张三","李四","王五"};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("输入注册的用户名信息:");
String username = scanner.nextLine();
cheakUserName(username);
}
public static void cheakUserName(String username) {
for (String name : usernames) {
if (name.equals(username)){
try {
//throw抛出一个自定义异常
throw new RegisterException("该用户已经被注册");
} catch (RegisterException e) {
e.printStackTrace();
return;//结束方法
}
}
}
System.out.println("恭喜注册成功");
}
}
测试结果
(1)用户已被注册
(2)用户注册成功
1.8 异常的注意事项
a:子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类,或者子类不抛出异常也是可以的。
b:如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常,或者子类不抛出异常也是可以的。
c:如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws
class Fu{
public static void show01()throws NullPointerException,ClassCastException{};
public static void show02()throws IndexOutOfBoundsException{};
public static void show03()throws NullPointerException,ClassCastException{};
public static void show04(){};
}
class Zi extends Fu{
//子类重写父类方法。抛出父类相同的异常
public static void show01()throws NullPointerException,ClassCastException{};
//子类重写父类方法,抛出父类异常的子类
public static void show02()throws ArrayIndexOutOfBoundsException{};
//子类重写父类方法,不抛出异常
public static void show03(){};
//父类不抛出异常,子类重写也不抛出异常
//有异常发生,只能try,不能throws
public static void show04(){
try {
throw new Exception("子类异常");
} catch (Exception e) {
e.printStackTrace();
}
};
}
二、File文件类
Java把电脑中的文件和文件夹(目录)封装为一个File类,使用File类对于文件和文件夹进行操作(创建 删除 获取 判断 遍历文件夹 文件的大小)File类是文件和目录路径名的抽象表示,主要用于文件和目录的创建
2.1 构造方法
public File(String pathname) :通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
public File(String parent, String child) :从父路径名字符串和子路径名字符串创建新的 File实例。
public File(File parent, String child) :从父抽象路径名和子路径名字符串创建新的 File实例。
public class FileMethod01 {
public static void main(String[] args) {
// public File(String pathname) :通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
File file = new File("a.txt");
System.out.println(file);//a.txt
/*public File(String parent, String child) :从父路径名字符串和子路径名字符串创建新的 File实例。
路径分为父路径和子路径*/
String parent="D:\\IDEAlei\\File";
String child="c.txt";
File file1 = new File(parent, child);
System.out.println(file1);//D:\IDEAlei\File\c.txt
/*public File(File parent, String child) :从父抽象路径名和子路径名字符串创建新的 File实例。
File:父路径 String:子路径*/
File file3=new File("C:\\IDEAlei\\File");
File file4=new File(file3,"d.txt");//File:父路径 String:子路径
System.out.println(file4);//
}
}
2.2 常用方法
2.2.1 获取功能的方法
public String getAbsolutePath() :返回此File的绝对路径名字符串。
public String getPath() :将此File转换为路径名字符串。
public String getName() :返回由此File表示的文件或目录的名称。
public long length() :返回由此File表示的文件的长度。
public class Method01 {
public static void main(String[] args) {
File file1=new File("D:\\IDEAlei\\File\\a.txt");
System.out.println("绝对路径"+file1.getAbsolutePath());//绝对路径D:\IDEAlei\File\a.txt
System.out.println("相对路径"+file1.getPath());//相对路径D:\IDEAlei\File\a.txt
System.out.println("文件名称"+file1.getName());//文件名称a.txt
System.out.println("文件长度:"+file1.length()+"字节");//文件长度:0字节//File表示的文件的长度。
//toString()相当于getPath()
System.out.println(file1.toString());//D:\IDEAlei\File\a.txt
File file2=new File("b.txt");
System.out.println("绝对路径"+file2.getAbsolutePath());//绝对路径C:\Users\asus\IdeaProjects\MyTest\b.txt
System.out.println("相对路径"+file2.getPath());//相对路径b.txt
System.out.println("文件名称"+file2.getName());//文件名称b.txt
System.out.println("文件长度:"+file2.length()+"字节");//文件长度:3字节
File file=new File("D:\\james\\james.png");
System.out.println(file.length());//292098
File file3=new File("D:\\james");
//文件夹是没有大小的,当文件不存在时也同样返回0
System.out.println(file3.length());//0
File file4=new File("D:\\sdes");
System.out.println(file4.length());//0
}
}
绝对路径:从盘符开始的路径,是一个完整的路径、比如:D:\james\james.png
相对路径:相对于项目目录的路径,这是一个便捷的路径
**注意:**在创建文件或者文件夹时忘记写盘符路径,那么默认路径为项目目录的路径
2.2.2 判断功能的方法
public boolean exists() :此File表示的文件或目录是否实际存在。
public boolean isDirectory() :此File表示的是否为目录。
public boolean isFile() :此File表示的是否为文件。
public class FileMethod02 {
public static void main(String[] args) {
/*
public boolean exists() :此File表示的文件或目录是否实际存在。
public boolean isDirectory() :此File表示的是否为目录。
public boolean isFile() :此File表示的是否为文件。
电脑中只存在文件夹(目录)和文件
两个方法的前提是路径存在,如果不存在,返回false
*/
//存在的一个目录
File file=new File("D:\\IDEAlei\\File");
System.out.println(file.exists());//true
System.out.println(file.isDirectory());//true
System.out.println(file.isFile());//false
//不存在的一个目录
File file1=new File("C:\\IDEAlei\\File");
System.out.println(file1.exists());//false
System.out.println(file1.isDirectory());//false
System.out.println(file1.isFile());//false
//存在的一个文件
File file4=new File("D:\\IDEAlei\\File\\a.txt");
System.out.println(file4.isDirectory());//false
System.out.println(file4.isFile());//true
}
}
2.2.3 删除功能的方法
public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
public boolean delete() :删除由此File表示的文件或目录。
public boolean mkdir() :创建由此File表示的目录。
public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。
public class FileMethod03 {
public static void main(String[] args) throws IOException {
/*
public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
文件存在,返回false 文件不存在:返回true 创建一个空的文件
只能创建文件,不能创建文件夹
创建文件时路径必须存在,否则抛出异常
createNewFile()抛出IOException throws或者try...catch
*/
File file=new File("D:\\IDEAlei\\File\\c.txt");
boolean newFile = file.createNewFile();
System.out.println(newFile);
/*
public boolean mkdir() :创建由此File表示的目录。 创建单级文件夹
public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。 创建单级文件夹 多级文件夹同文件
*/
File file2=new File("D:\\IDEAlei\\File\\aaa");
boolean mkdir = file2.mkdir();//单级文件夹
System.out.println(mkdir);
File file3=new File("D:\\IDEAlei\\File\\111\\222\\333");
boolean mkdirs = file3.mkdirs();多级文件夹
System.out.println(mkdirs);
File file4=new File("D:\\IDEAlei\\File\\abc.txt");//创建的是一个名称为abc.txt的文件夹
boolean mkdir1 = file4.mkdir();
System.out.println(mkdir1);
/*
public boolean delete() :删除由此File表示的文件或目录。
true :删除成功 false:文件夹内有内容,不会删除返回false 或者构造方法中的路径不存在
注意: delete方法直接在硬盘中删除文件或者文件夹 不走回收站
*/
boolean b = file2.delete();
System.out.println(b);
boolean b1 = file4.delete();
System.out.println(b1);
}
}
2.2.4 重命名的方法
public boolean renameTo(File dest):把文件重命名为指定的文件路径
public class FileDemo02 {
public static void main(String[] args) {
File file = new File("aaa.txt");
File file1 = new File("bbb.txt");
boolean b = file.renameTo(file1);
if (b) {
System.out.println("重命名成功");
}else {
System.out.println("重命名失败");
}
}
}
注意:当调用方法的文件路径和传入的参数的文件的路径名相同,则为重命名。否则为剪切+重命名
2.2.5 目录的遍历
public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。
public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。
练习:删除多级文件夹
public class MyTest0101 {
public static void main(String[] args) {
File file = new File("C:\\Users\\asus\\Desktop\\aaa");
file.mkdirs();
deleteFile1(file);
}
private static void deleteFile1(File file) {
//遍历得到文件目录下的所有文件 listFiles() 方法
File[] files = file.listFiles();
for (File file1 : files) {
//判断是否是目录,如果是,则递归
if (file1.isDirectory()){
deleteFile1(file1);
}else {
file1.delete();
}
}
file.delete();
}
}
练习:修改多级文件夹的后缀名
public class Test02 {
public static void main(String[] args) {
/*
练习:将文件名后缀修改为.PNG
*/
//绑定一个文件夹
File file = new File("C:\\Users\\asus\\Desktop\\music");
//构造一个修改的方法updataFileName
updataFileName(file);
}
private static void updataFileName(File file) {
//遍历得到文件目录下的所有文件
File[] files = file.listFiles();
for (File file1 : files) {
//对遍历的文件进行判断,是文件则进行修改操作
if (file1.isFile()){
//获取文件的绝对路径
String name = file1.getAbsolutePath();
//修改文件的绝对路径名
String newName=name.substring(0,name.lastIndexOf("."))+".PNG";
//使用新的文件名构造一个文件
File endFile = new File(newName);
//对文件进行重命名
file1.renameTo(endFile);
}else {
//是文件夹的话,对文件夹调用updataFileName
updataFileName(file1);
}
}
}
}