数据来源:拉勾教育Java就业急训营
核心类库(下)
- 一. 异常机制和File类
- 二. IO流
-
- 1. IO流的概念
- 2. 基本分类
- 3. 体系结构
- 4. 相关流的详解
-
- 4.1 FileWriter类(重点)
- 4.2 FileReader类(重点)
- 4.3 FileOutputStream类(重点)
- 4.4 FileInputStream类(重点)
- 4.5 BufferedOutputStream类(重点)
- 4.6 BufferedInputStream类(重点)
- 4.7 BufferedWriter类(重点)
- 4.8 BufferedReader类(重点)
- 4.9 PrintStream类
- 4.10 PrintWriter类
- 4.11 OutputStreamWriter类
- 4.12 InputStreamReader类
- 4.13 字符编码
- 4.14 DataOutputStream类(了解)
- 4.15 DataInputStream类(了解)
- 4.16 ObjectOutputStream类(重点)
- 4.17 ObjectInputStream类(重点)
- 4.18 RandomAccessFile类
- 三. 多线程
- 四. 网络编程
- 五. 反射机制
一. 异常机制和File类
1. 异常机制(重点)
1.1 概念
● 异常就是"不正常"的含义,在Java语言中主要指程序执行中发生的不正常情况。
● java.lang.Throwable类是Java语言中错误(Error)和异常(Exception)的超类。
● 其中Error类主要用于描述Java虚拟机无法解决的严重错误,通常无法编码解决,如:JVM挂掉了等。
● 其中Exception类主要用于描述因编程错误或偶然外在因素导致的轻微错误,通常可以编码解决,如:0作为除数等。
1.2 异常的分类
● java.lang.Exception类是所有异常的超类,主要分为以下两种:
RuntimeException - 运行时异常,也叫作非检测性异常
IOException和其它异常 - 其它异常,也叫作检测性异常,所谓检测性异常就是指在编译阶段都能被编译器检测出来的异常。
● 其中RuntimeException类的主要子类:
ArithmeticException类 - 算术异常
ArrayIndexOutOfBoundsException类 - 数组下标越界异常
NullPointerException - 空指针异常
ClassCastException - 类型转换异常
NumberFormatException - 数字格式异常
● 注意:
当程序执行过程中发生异常但又没有手动处理时,则由Java虚拟机采用默认方式处理异常,而默认处理方式就是:打印异常的名称、异常发生的原因、异常发生的位置以及终止程序。
1.3 异常的避免
public class ExceptionPreventTest {
public static void main(String[] args) {
// 会发生算术异常
int ia = 10;
int ib = 0;
if (0 != ib) {
System.out.println(ia / ib);
}
// 数组下标越界异常
int[] arr = new int[5];
int pos = 5;
if (pos >= 0 && pos < 5) {
System.out.println(arr[pos]);
}
// 发生空指针异常
String str = null;
if (null != str) {
System.out.println(str.length());
}
// 类型转换异常
Exception ex = new Exception();
if (ex instanceof IOException) {
IOException ie = (IOException) ex;
}
// 数字格式异常(用正则表达式判断)
String str2 = "123a";
if (str2.matches("\\d+")) {
System.out.println(Integer.parseInt(str2));
}
System.out.println("程序总算正常结束了!");
}
}
● 在以后的开发中尽量使用if条件判断来避免异常的发生。
● 但是过多的if条件判断会导致程序的代码加长、臃肿,可读性差。
1.4 异常的捕获
语法格式
try {
编写可能发生异常的代码;
}
catch(异常类型 引用变量名) {
编写针对该类异常的处理代码;
}
...
finally {
编写无论是否发生异常都要执行的代码;
}
注意事项
a.当需要编写多个catch分支时,切记小类型应该放在大类型的前面;
b.懒人的写法:用多态的方式捕获所有小异常的父类Exception
catch(Exception e) {
}
c.finally通常用于进行善后处理,如:关闭已经打开的文件等
执行流程
try {
a;
b; - 可能发生异常的语句
c;
}catch(Exception ex) {
d;
}finally {
e;
}
当没有发生异常时的执行流程:a b c e;
当发生异常时的执行流程:a b d e;
案例:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionCatchTest {
public static void main(String[] args) {
// 创建一个FileInputStream类型的对象与d:/a.txt文件关联,打开文件
FileInputStream fis = null;
try {
System.out.println("1");
// 当程序执行过程中发生了异常后直奔catch分支进行处理
fis = new FileInputStream("d:/a.txt");
System.out.println("2");
} catch (FileNotFoundException e) {
System.out.println("3");
e.printStackTrace();
System.out.println("4");
}
// 关闭文件
try {
System.out.println("5");
fis.close();
System.out.println("6");
} /*catch (Exception e) {
e.printStackTrace();
}*/ catch (IOException e) {
System.out.println("7");
e.printStackTrace();
System.out.println("8");
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("世界上最真情的相依就是你在try我在catch,无论你发神马脾气我都默默承受并静静的处理,到那时再来期待我们的finally!");
// 当程序执行过程中没有发生异常时的执行流程:1 2 5 6 世界上...
// 当程序执行过程中发生异常又没有手动处理空指针异常时的执行流程:1 3 4 5 空指针异常导致程序终止
// 当程序执行过程中发生异常并且手动处理空指针异常时的执行流程: 1 3 4 5 世界上...
// 手动处理异常和没有处理的区别:代码是否可以继续向下执行
}
}
手动处理异常和没有处理的区别:代码是否可以继续向下执行
笔试考点
public class ExceptionFinallyTest {
// 笔试考点
public static int test() {
try {
int[] arr = new int[5];
System.out.println(arr[5]);
return 0;
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
return 1;
} finally {
return 2; // 提交结束方法并返回数据
}
}
public static void main(String[] args) {
int test = test();
System.out.println("test = " + test); // 2
}
}
解析:test方法中发生数组下标越界异常,进入catch语句,在执行return 1;语句时,本应返回1并结束方法体,但下面有finally语句必,因此finally语句会在catch语句结束之前强行执行,finally语句中return 2;返回2并结束方法体,即抢先结束方法体,因此最后test = 2
1.5 异常的抛出(甩锅)
基本概念
在某些特殊情况下有些异常不能处理或者不便于处理时,就可以将该异常转移给该方法的调用者,这种方法就叫异常的抛出。当方法执行时出现异常,则底层生成一个异常类对象抛出,此时异常代码后续的代码就不再执行。
语法格式
// 访问权限 返回值类型 方法名称(形参列表) throws 异常类型1,异常类型2,...{ 方法体; }
public void show() throws IOException{
}
方法重写的原则
a.要求方法名相同、参数列表相同以及返回值类型相同,从jdk1.5开始支持返回子类类型;
b.要求方法的访问权限不能变小,可以相同或者变大;
c.要求方法不能抛出更大的异常;
注意
子类重写的方法不能抛出更大的异常、不能抛出平级不一样的异常,但可以抛出一样的异常、更小的异常以及不抛出异常。
经验分享
若父类中被重写的方法没有抛出异常时,则子类中重写的方法只能进行异常的捕获处理。
若一个方法内部又以递进方式分别调用了好几个其它方法,则建议这些方法内可以使用抛出的方法处理到最后一层进行捕获方式处理。
1.6 自定义异常
基本概念
当需要在程序中表达年龄不合理的情况时,而Java官方又没有提供这种针对性的异常,此时就需要程序员自定义异常加以描述。
实现流程
a.自定义xxxException异常类继承Exception类或者其子类。
b.提供两个版本的构造方法,一个是无参构造方法,另外一个是字符串作为参数的构造方法。
public class AgeException extends Exception {
static final long serialVersionUID = 7818375828146090155L; // 序列化的版本号 与序列化操作有关系
public AgeException() {
}
public AgeException(String message) {
super(message);
}
}
person类:
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) throws AgeException {
setName(name);
setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) throws AgeException {
if (age > 0 && age < 150) {
this.age = age;
} else {
//System.out.println("年龄不合理哦!!!");
throw new AgeException("年龄不合理哦!!!");
}
}
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类:
public class PersonTest {
public static void main(String[] args) {
Person p1 = null;
try {
p1 = new Person("zhangfei", -30);
} catch (AgeException e) {
e.printStackTrace();
}
System.out.println("p1 = " + p1); // p1 = null
}
}
分析:
Person类中setAge方法抛出异常,谁调用就抛给谁,构造方法调用,继续抛出异常,接着测试类中main方法调用,new对象时发生异常,因为不建议面main方法抛出异常,所以进行异常的手动处理,即try/catch语句,最后并没有new出对象,故p1 = null
若就地处理,即在setAge方法时,不抛出异常,而是直接进行手动处理,那么后续的构造方法和main方法也不用抛出异常,可正常执行,那么是可以new对象的,不过年龄是默认值0,p1 = Person{name=‘zhangfei’, age=0}
异常的产生
// 格式:throw new 异常类型(实参);
throw new AgeException("年龄不合理!!!");
Java采用的异常处理机制是将异常处理的程序代码集中在一起,与正常的程序代码分开,使得程序简洁、优雅,并易于维护。
异常小结:
2. File类(重点)
2.1 概念
java.io.File类主要用于描述文件或目录路径的抽象表示信息,可以获取文件或目录的特征信息,如:大小等。
2.2 常用的方法
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
public class FileTest {
// 自定义成员方法实现指定目录以及子目录中所有内容的打印
public static void show(File file) {
// 获取目录f3下的所有内容并记录到一维数组中
File[] filesArray = file.listFiles();
// 遍历数组
for (File tf: filesArray) {
String name = tf.getName();
// 判断是否为文件,若是则直接打印文件名称
if (tf.isFile()) {
System.out.println(name);
}
// 若是目录,则使用[]将目录名称括起来,递归打印
if (tf.isDirectory()) {
System.out.println("[" + name + "]");
show(tf);
}
}
}
public static void main(String[] args) throws IOException {
// 1.构造File类型的对象与d:/a.txt文件关联
File f1 = new File("d:/a.txt");
// 2.若文件存在则获取文件的相关特征信息并打印后删除文件
if (f1.exists()) {
System.out.println("文件的名称是:" + f1.getName());
System.out.println("文件的大小是:" + f1.length());
Date d1 = new Date(f1.lastModified());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("文件的最后一次修改时间:" + sdf.format(d1));
// 绝对路径: 主要指以根目录开始的路径信息,如:c:/ d:/ /..
// 相对路径: 主要指以当前目录所在位置开始的路径信息,如:./ ../ 相对路径
System.out.println("文件的绝对路径信息是:" + f1.getAbsolutePath());
System.out.println(f1.delete()? "文件删除成功": "文件删除失败");
} else {
// 3.若文件不存在则创建新的空文件
System.out.println(f1.createNewFile()? "文件创建成功": "文件创建失败!");
}
System.out.println("---------------------------------------------------------");
// 4.实现目录的删除和创建
File f2 = new File("d:/捣乱/猜猜我是谁/你猜我猜不猜/死鬼");
if (f2.exists()) {
System.out.println("目录名称是:" + f2.getName());
System.out.println(f2.delete()? "目录删除成功": "目录删除失败");
} else {
//System.out.println(f2.mkdir()? "目录创建成功": "目录创建失败"); // 创建单层目录
System.out.println(f2.mkdirs()? "目录创建成功": "目录创建失败"); // 创建多层目录
}
System.out.println("---------------------------------------------------------");
// 5.实现将指定目录中的所有内容打印出来
File f3 = new File("d:/捣乱");
// 获取目录f3下的所有内容并记录到一维数组中
File[] filesArray = f3.listFiles();
// 遍历数组
for (File tf: filesArray) {
String name = tf.getName();
// 判断是否为文件,若是则直接打印文件名称
if (tf.isFile()) {
System.out.println(name);
}
// 若是目录,则使用[]将目录名称括起来
if (tf.isDirectory()) {
System.out.println("[" + name + "]");
}
}
System.out.println("---------------------------------------------------------");
// 6.实现目录中所有内容获取的同时进行过滤
// 匿名内部类的语法格式:接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };
/*FileFilter fileFilter = new FileFilter() {
@Override
public boolean accept(File pathname) {
// 若文件名是以.avi为结尾,则返回true表示保留 否则返回false就是表示丢弃
return pathname.getName().endsWith(".avi");
}
};*/
// Lambda表达式的格式:(参数列表) -> {方法体}
FileFilter fileFilter = (File pathname) -> {
return pathname.getName().endsWith(".avi");};
File[] filesArray2 = f3.listFiles(fileFilter);
for (File tf : filesArray2) {
System.out.println(tf);
}
System.out.println("---------------------------------------------------------");
// 7.使用递归的思想获取目录以及子目录中的内容
show(new File("d:/捣乱"));
}
}
二. IO流
1. IO流的概念
● IO就是Input和Output的简写,也就是输入和输出的含义。
● IO流就是指读写数据时像流水一样从一端流到另外一端,因此得名为“流"。
2. 基本分类
● 按照读写数据的基本单位不同,分为 字节流 和 字符流。
其中字节流主要指以字节为单位进行数据读写的流,可以读写任意类型的文件。
其中字符流主要指以字符(2个字节)为单位进行数据读写的流,只能读写文本文件。
● 按照读写数据的方向不同,分为 输入流 和 输出流(站在程序的角度)。
其中输入流主要指从文件中读取数据内容输入到程序中,也就是读文件。
其中输出流主要指将程序中的数据内容输出到文件中,也就是写文件。
● 按照流的角色不同分为节点流和处理流。
其中节点流主要指直接和输入输出源对接的流。
其中处理流主要指需要建立在节点流的基础之上的流。
3. 体系结构
重点掌握:
4. 相关流的详解
4.1 FileWriter类(重点)
基本概念
java.io.FileWriter类主要用于将文本内容写入到文本文件
常用的方法
FileWriter fw = new FileWriter(“d:/a.txt”);
新建一个输出流对象,相当于向指定目录文件搭建一个管道,通过管道向文件输入数据
void flush() 方法,用于清除管道残留,刷新管道
void close() 方法,关闭流对象,相当于撤走管道,同时有刷新管道的功能
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterTest {
public static void main(String[] args) {
// 选中代码后可以使用 ctrl+alt+t 来生成异常的捕获代码等
FileWriter fw = null;
try {
// 1.构造FileWrite类型的对象与d:/a.txt文件关联
// 若文件不存在,该流会自动创建新的空文件
// 若文件存在,该流会清空文件中的原有内容
fw = new FileWriter("d:/a.txt");
// 以追加的方式创建对象去关联文件
// 若文件不存在则自动创建新的空文件,若文件存在则保留原有数据内容
// fw = new FileWriter("d:/a.txt", true);
// 2.通过流对象写入数据内容 每当写入一个字符后则文件中的读写位置向后移动一位
fw.write('a');
// 准备一个字符数组
char[] cArr = new char[]{
'h', 'e', 'l', 'l', 'o'};
// 将字符数组中的一部分内容写入进去
fw.write(cArr, 1, 3); // ell
// 将整个字符数组写进去
fw.write(cArr); // hello
// 刷新流
fw.flush();
System.out.println("写入数据成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3.关闭流对象并释放有关的资源
if (null != fw) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4.2 FileReader类(重点)
基本概念
java.io.FileReader类主要用于从文本文件读取文本数据内容
常用的方法
import java.io.FileReader;
import java.io.IOException;
public class FileReaderTest {
public static void main(String[] args) {
FileReader fr = null;
try {
// 1.构造FileReader类型的对象与d:/a.txt文件关联
//fr = new FileReader("d:/a.txt");
fr = new FileReader("d:/b.txt");
// 2.读取数据内容并打印
/*
int res = fr.read();
System.out.println("读取到的单个字符是:" + (char)res); // 'a'
*/
int res = 0;
while ((res = fr.read()) != -1) {
System.out.println("读取到的单个字符是:" + (char)res + ",对应的编号是:" + res);
}
// 准备一个字符数组来保存读取到的数据内容
// char[] cArr = new char[5];
// 期望读满字符数组中的一部分空间,也就是读取3个字符放入数组cArr中下标从1开始的位置上
/*int res = fr.read(cArr, 1, 3);
System.out.println("实际读取到的字符个数是:" + res); // 3
for (char cv : cArr) {
System.out.println("读取到的单个字符是:" + (char)cv); // 啥也没有 a e l 啥也没有
}*/
// 期望读满整个字符数组
/*int res = fr.read(cArr);
System.out.println("实际读取到的字符个数是:" + res); // 5
for (char cv : cArr) {
System.out.println("读取到的单个字符是:" + (char)cv); // a e l l h
}*/
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3.关闭流对象并释放有关的资源
if (null != fr) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
字符流实现文件拷贝:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileCharCopyTest {
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try {
// 1.创建FileReader类型的对象与d:/a.txt文件关联
fr = new FileReader("d:/a.txt");
//fr = new FileReader("d:/03 IO流的框架图.png");
// 2.创建FileWriter类型的对象与d:/b.txt文件关联
fw = new FileWriter("d:/b.txt");
//fw = new FileWriter("d:/IO流的框架图.png"); 拷贝图片文件失败!!!
// 3.不断地从输入流中读取数据内容并写入到输出流中
System.out.println("正在玩命地拷贝...");
int res = 0;
while ((res = fr.read()) != -1) {
fw.write(res);
}
System.out.println("拷贝文件成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.关闭流对象并释放有关的资源
if (null != fw) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != fr) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4.3 FileOutputStream类(重点)
基本概念
java.io.FileOutputStream类主要用于将图像数据之类的原始字节流写入到输出流中
常用的方法
4.4 FileInputStream类(重点)
基本概念
java.io.FileInputStream类主要用于从输入流中以字节流的方式读取图像数据等
常用的方法
字节流实现文件的拷贝
三种方式进行拷贝:
方式一:以单个字节为单位进行拷贝,也就是每次读取一个字节后再写入一个字节
缺点:文件稍大时,拷贝的效率很低
方式二:准备一个和文件大小一样的缓冲区,一次性将文件中的所有内容取出到缓冲区然后一次性写入进去
缺点:若文件过大时,无法申请和文件大小一样的缓冲区,真实物理内存不足
方式三:准备一个相对适当的缓冲区,分多次将文件拷贝完成
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileByteCopyTest {
public static void main(String[] args) {
// 获取当前系统时间距离1970年1月1日0时0分0秒的毫秒数
long g1 = System.currentTimeMillis();
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 1.创建FileInputStream类型的对象与d:/03 IO流的框架图.png文件关联
//fis = new FileInputStream("d:/03 IO流的框架图.png");
fis = new FileInputStream("d:/02_IO流的框架结构.mp4");
// 2.创建FileOutputStream类型的对象与d:/IO流的框架图.png文件关联
//fos = new FileOutputStream("d:/IO流的框架图.png");
fos = new FileOutputStream("d:/IO流的框架结构.mp4");
// 3.不断地从输入流中读取数据内容并写入到输出流中
System.out.println("正在玩命地拷贝...");
// 方式一:以单个字节为单位进行拷贝,也就是每次读取一个字节后再写入一个字节
// 缺点:文件稍大时,拷贝的效率很低
/*int res = 0;
while ((res = fis.read()) != -1) {
fos.write(res);
}*/
// 方式二:准备一个和文件大小一样的缓冲区,一次性将文件中的所有内容取出到缓冲区然后一次性写入进去
// 缺点:若文件过大时,无法申请和文件大小一样的缓冲区,真实物理内存不足
/*int len = fis.available();
System.o