异常
- A:异常的概述
- 异常就是Java程序在运行过程中出现的错误。
- B:异常的分类
- 通过API查看Throwable
- Error
- 服务器宕机,数据库崩溃等
- Exception
- C:异常的继承体系
- Throwable
- Error
- Exception
- RuntimeException
- Throwable
- 异常注意事项
- a:子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)
- b:如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
- c:如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws
如何使用异常处理
- 原则:如果该功能内部可以将问题处理,用try,如果处理不了,交由调用者处理,这是用throws
区别:
- 后续程序需要继续运行就try
- 后续程序不需要继续运行就throws
如果JDK没有提供对应的异常,需要自定义异常。
- JVM默认是如何处理异常的
- main函数收到这个问题时,有两种处理方式:
- a:自己将该问题处理,然后继续运行
- b:自己没有针对的处理方式,只有交给调用main的jvm来处理
- jvm有一个默认的异常处理机制,就将该异常进行处理.
- 并将该异常的名称,异常的信息.异常出现的位置打印在了控制台上,同时将程序停止运行
- 异常处理的两种方式
- a:try…catch…finally
- try catch
- try catch finally
- try finally
- b:throws
- a:try…catch…finally
编译期异常和运行期异常的区别
- Java中的异常被分为两大类:编译时异常和运行时异常。
所有的RuntimeException类及其子类的实例被称为运行时异常,其他的异常就是编译时异常
编译时异常
- Java程序必须显示处理,否则程序就会发生错误,无法通过编译
- 运行时异常
- 无需显示处理,也可以和编译时异常一样处理
- Throwable的几个常见方法
- a:getMessage()
- 获取异常信息,返回字符串。
- b:toString()
- 获取异常类名和异常信息,返回字符串。
- c:printStackTrace()
- 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
- a:getMessage()
- throws和throw的区别
- a:throws
- 用在方法声明后面,跟的是异常类名
- 可以跟多个异常类名,用逗号隔开
- 表示抛出异常,由该方法的调用者来处理
- b:throw
- 用在方法体内,跟的是异常对象名
- 只能抛出一个异常对象名
- 表示抛出异常,由方法体内的语句处理
- a:throws
- Finally
- A:finally的特点
- 被finally控制的语句体一定会执行
- 特殊情况:在执行到finally之前jvm退出了(比如System.exit(0))
- B:finally的作用
- 用于释放资源,在IO流操作和数据库操作中会见到
- 如果try/catch里面有return语句,finally还会执行,return执行->finally执行->return返回
- A:finally的特点
- 自定义异常
- 继承自Exception
- 继承自RuntimeException
File
- File类
- File更应该叫做一个路径
- 文件路径或者文件夹路径
- 路径分为绝对路径和相对路径
- 绝对路径是一个固定的路径,从盘符开始
- 相对路径相对于某个位置,在eclipse下是指当前项目下,在dos下
- 查看API指的是当前路径
- 文件和目录路径名的抽象表示形式
- File更应该叫做一个路径
- 构造方法
- File(String pathname):根据一个路径得到File对象
- File(String parent, String child):根据一个目录和一个子文件/目录得到File对象
- File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象
- 创建功能
- public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了
- public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了
- public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来
- 重命名和删除
- 重命名和删除功能
- public boolean renameTo(File dest):把文件重命名为指定的文件路径
- public boolean delete():删除文件或者文件夹
- 重命名注意事项
- 如果路径名相同,就是改名。
- 如果路径名不同,就是改名并剪切。
- 删除注意事项:
- Java中的删除不走回收站。
- 要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹
- 重命名和删除功能
- 判断功能
- public boolean isDirectory():判断是否是目录
- public boolean isFile():判断是否是文件
- public boolean exists():判断是否存在
- public boolean canRead():判断是否可读
- public boolean canWrite():判断是否可写
- public boolean isHidden():判断是否隐藏
- 获取功能
- public String getAbsolutePath():获取绝对路径
- public String getPath():获取路径
- public String getName():获取名称
- public long length():获取长度。字节数
- public long lastModified():获取最后一次的修改时间,毫秒值
- public String[] list():获取指定目录下的所有文件或者文件夹的名称数组
- public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组
- 文件名称过滤器的概述
- public String[] list(FilenameFilter filter)
- public File[] listFiles(FileFilter filter)
IO流
- 概念
- IO流用来处理设备之间的数据传输
- Java对数据的操作是通过流的方式
- Java用于操作流的类都在IO包中
- 流按流向分为两种:输入流,输出流。
- 流按操作类型分为两种:
- 字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
- 字符流 : 字符流只能操作纯字符数据,比较方便。
- IO流常用父类
- 字节流的抽象父类:
- InputStream
- OutputStream
- 字符流的抽象父类:
- Reader
- Writer
- 字节流的抽象父类:
- IO程序书写
- 使用前,导入IO包中的类
- 使用时,进行IO异常处理
- 使用后,释放资源
- read()一次读取一个字节
FileInputStream fis = new FileInputStream("aaa.txt"); //创建一个文件输入流对象,并关联aaa.txt int b; //定义变量,记录每次读到的字节 while((b = fis.read()) != -1) { //将每次读到的字节赋值给b并判断是否是-1 System.out.println(b); //打印每一个字节 } fis.close();
- read()方法读取的是一个字节,为什么返回是int,而不是byte
-
因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111,那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上.24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型 - write()一次写出一个字节
FileOutputStream fos = new FileOutputStream("bbb.txt"); //如果没有bbb.txt,会创建出一个
//fos.write(97); //虽然写出的是一个int数,但是在写出的时候会将前面的24个0去掉,所以写出的一个byte
fos.write(98);
fos.write(99);
fos.close();
- FileOutputStream的构造方法写出数据如何实现数据的追加写入
FileOutputStream fos = new FileOutputStream("bbb.txt",true); //如果没有bbb.txt,会创建出一个
//fos.write(97); //虽然写出的是一个int数,但是在写出的时候会将前面的24个0去掉,所以写出的一个byte
fos.write(98);
fos.write(99);
fos.close();
- FileInputStream读取
FileOutputStream写出
FileInputStream fis = new FileInputStream("致青春.mp3"); //创建输入流对象,关联致青春.mp3 FileOutputStream fos = new FileOutputStream("copy.mp3");//创建输出流对象,关联copy.mp3 int b; while((b = fis.read()) != -1) { fos.write(b); } fis.close(); fos.close();
- 字节数组拷贝之available()方法
- int read(byte[] b):一次读取一个字节数组
- write(byte[] b):一次写出一个字节数组
- available()获取读的文件所有的字节个数
弊端:有可能会内存溢出
FileInputStream fis = new FileInputStream("致青春.mp3"); FileOutputStream fos = new FileOutputStream("copy.mp3"); byte[] arr = new byte[fis.available()]; //根据文件大小做一个字节数组 fis.read(arr); //将文件上的所有字节读取到数组中 fos.write(arr); //将数组中的所有字节一次写到了文件上 fis.close(); fos.close();
- 定义小数组
- write(byte[] b)
- write(byte[] b, int off, int len)写出有效的字节个数
- 字节流一次读写一个字节数组复制图片和视频
FileInputStream fis = new FileInputStream("致青春.mp3");
FileOutputStream fos = new FileOutputStream("copy.mp3");
int len;
byte[] arr = new byte[1024 * 8]; //自定义字节数组
while((len = fis.read(arr)) != -1) {
//fos.write(arr);
fos.write(arr, 0, len); //写出字节数组写出有效个字节个数
}
fis.close();
fos.close();
BufferedInputStream和BufferOutputStream拷贝
- 缓冲思想
- 字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,
- 这是加入了数组这样的缓冲区效果,java本身在设计的时候,
- 也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区
- BufferedInputStream
- BufferedInputStream内置了一个缓冲区(数组)
- 从BufferedInputStream中读取一个字节时
- BufferedInputStream会一次性从文件中读取8192个, 存在缓冲区中, 返回给程序一个
- 程序再次读取时, 就不用找文件了, 直接从缓冲区中获取
- 直到缓冲区中所有的都被使用过, 才重新从文件中读取8192个
- BufferedOutputStream
- BufferedOutputStream也内置了一个缓冲区(数组)
- 程序向流中写出字节时, 不会直接写到文件, 先写到缓冲区中
- 直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里
FileInputStream fis = new FileInputStream("致青春.mp3"); //创建文件输入流对象,关联致青春.mp3 BufferedInputStream bis = new BufferedInputStream(fis); //创建缓冲区对fis装饰 FileOutputStream fos = new FileOutputStream("copy.mp3"); //创建输出流对象,关联copy.mp3 BufferedOutputStream bos = new BufferedOutputStream(fos); //创建缓冲区对fos装饰 int b; while((b = bis.read()) != -1) { bos.write(b); } bis.close(); //只关装饰后的对象即可 bos.close();
- 内存比硬盘运算效率高 只要降低到硬盘的读写次数降低就会提高效率
- 小数组的读写和带Buffered的读取哪个更快?
- 定义小数组如果是8192个字节大小和Buffered比较的话,定义小数组会略胜一筹,因为读和写操作的是同一个数组,而Buffered操作的是两个数组[8192]大小
- 缓冲思想
- flush()方法
- 用来刷新缓冲区的,刷新后可以再次写出
- close()方法
- 用来关闭流释放资源的的,如果是带缓冲区的流对象的close()方法,不但会关闭流,还会再关闭流之前刷新缓冲区,关闭后不能再写出
try close
try( FileInputStream fis = new FileInputStream("aaa.txt"); FileOutputStream fos = new FileOutputStream("bbb.txt"); MyClose mc = new MyClose(); //try括号内需要创建实现了自动关闭的流 即 Class MyClose implements AutoCloseable 在大括号内容执行后自动关闭 ){ int b; while((b = fis.read()) != -1) { fos.write(b); } }