5 进阶
约 5544 字大约 18 分钟
2025-04-05
结合了Lambda表达式,简化集合、数组的操作 利用Stream流中的API进行各种操作
分为中间方法和终结方法
- 中间方法 : 方法调用完毕之后,还可以调用其他方法
- 终结方法 : 最后一步,调用完毕之后,不能调用其他方法
获取stream流
获取方式 | 方法名 | 说明 |
---|---|---|
单列集合 | default Stream<E> stream() | Collection中的默认方法 |
双列集合 | 无 | 无法直接使用stream流 |
数组 | public static <T> Stream<T> stream(T[ ] array)Arrays | 工具类中的静态方法 |
一堆零散数据 | public static<T> Stream<T> of(T... values) | Stream接口中的静态方法 |
双列集合若想要使用stream流需要使用keySet()或entrySet()获取单列集合再获取stream流 |
Stream<String> stream1=list.stream();
list.stream().forEach(s ->System.out.println(s));
中间方法
名称 | 说明 |
---|---|
Stream<T> filter(Predicate<? super T> predicate) | 过滤 |
Stream<T> limit(long maxSize) | 获取前几个元素 |
Stream<T> skip(long n) | 跳过前几个元素 |
Stream<T> distinct() | 元素去重,依赖(hashcode和equals方法) |
static <T> Stream<T> concat(Stream a, Stream b) | 合并a和b两个流为一个流 |
Stream<R> map(Function<T , R> mapper) | 转换流中的数据类型,或者对数据流进行处理返回新的数据 |
中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程 修改stream流中的数据,不会影响原来集合或者数组中的数据
终结方法
名称 | 说明 |
---|---|
void forEach(Consumer action) | 遍历 |
long count() | 统计 |
toArray() | 收集流中的数据,放到数组中 |
collect(Collector collector) | 收集流中的数据,放到集合中 |
方法引用
:: 方法引用符
public class FunctionDemo1{
public static int subtraction(int num1,int num2){
return num2-num1;
}
public static void main(){
Arrays.sort(arr,FunctionDemo1::subtraction);
}
}
引用静态方法
类名::静态方法
引用成员方法
格式:对象::成员方法
- 其他类:
其他类对象::方法名
- 本类:
this::方法名
- 父类:
super::方法名
引用构造方法
格式:类名::new
示例:
Student::new
引用数组的构造方法
格式:数据类型[]::new
示例:
int[]::new
异常
- Error:代表的系统级别错误(属于严重问题)系统一旦出现问题,sun公司会把这些错误封装成Error对象。Error是给sun公司自己用的,不是给我们程序员用的。因此我们开发人员不用管它。
- Exception:叫做异常,代表程序可能出现的问题。我们通常会用Exception以及他的子类来封装程序出现的问题。
- 运行时异常:RuntimeException本身和子类编译阶段没有错误提示,运行时出现的(如:数组索引越界异常)
- 编译时异常:没有继承RuntimeExcpetion的异常,直接继承于Excpetion。编译阶段就会错误提示
异常是用来查询bug的关键参考信息 异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
JVM默认的处理方式 把异常的名称,异常原因及异常出现的位置等信息输出在了控制台 程序停止执行,下面的代码不会再执行了
自己处理异常 捕获异常
try{
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}finally{
无论有没有异常都会执行的代码;
}
抛出异常
throws 写在方法定义处,表示声明一个异常告诉调用者,使用本方法可能会有哪些异常 编译时异常:必须要写 运行时异常:可以不写
public void 方法()throws 异常类名1,异常类名2...{
...
}
throw 写在方法内,结束方法 手动抛出异常对象,交给调用者 方法中下面的代码不再执行了
public void 方法(){
throw new NullPointerException();
}
异常中常用方法
Throwable中的成员方法
方法名称 | 说明 |
---|---|
public String getMessage() | 返回此 throwable 的详细消息字符串 |
public String tostring() | 返回此可抛出的简短描述 |
public voidprintstackTrace() | 把异常的错误信息输出在控制台(和jvm默认处理的一样但不会停止运行) |
自定义异常
自定义异常时要根据实际情况选择继承哪个异常 如果是运行时异常需要继承RuntimeException 如果是编译时异常需要继承Exception
public class NameFormatException extends RuntimeException{
public NameFormatException() {}
public NameFormatException(String message){
super(message);
}
}
文件操作
函数 | 作用 |
---|---|
public File(String pathname) | 把字符串表示的路径变成File对象 |
public File(String parent, String child) | 把父级路径和子级路径进行拼接 |
public File(Fileparent, String child) | 把父级路径和子级路径进行拼接 |
判断和获取
方法名称 | 说明 |
---|---|
public boolean isDirectory() | 判断此路径名表示的File是否为文件夹 |
public boolean isFile() | 判断此路径名表示的File是否为文件 |
public boolean exists() | 判断此路径名表示的File是否存在 |
public long length() | 返回文件的大小 (字节数量) |
public String getAbsolutePath() | 返回文件的绝对路径 |
public String getPath() | 返回定义文件时使用的路径 |
public String getName() | 返回文件的名称,带后缀 |
public long lastModified() | 返回文件的最后修改时间 (时间毫秒值) |
创建和删除
方法名称 | 说明 |
---|---|
public boolean createNewFile() | 创建一个新的空的文件如果存在则返回false,不存在则创建后返回true,如果没有给后缀名则创建无后缀名的文件 |
public boolean mkdir() | 创建单级文件夹 |
public boolean mkdirs() | 创建多级文件夹 |
public boolean delete() | 删除文件、空文件夹 |
获取并遍历
方法名称 | 说明 |
---|---|
public File[] listFiles() | 获取当前该路径下所有内容存储到数组中 |
public static File[] listRoots() | 列出可用的文件系统根如果时windows获取的就是盘符 |
public String[] list() | 获取当前该路径下所有内容 |
public String[] list(FilenameFilter filter) | 利用文件名过滤器获取当前该路径下所有内容 |
public File[] listFiles(FileFilter filter) | 利用文件名过滤器获取当前该路径下所有内容 |
public File[] listFiles(FilenameFilter filter) | 利用文件名过滤器获取当前该路径下所有内容 |
- 当调用者File表示的路径不存在时,返回null
- 当调用者File表示的路径是文件时,返回null
- 当调用者File表示的路径是一个空文件夹时,返回一个长度为0的数组
- 当调用者File表示的路径是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
- 当调用者File表示的路径是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
- 当调用者File表示的路径是需要权限才能访问的文件夹时,返回null
IO流
存储和读取数据的解决方案 用于读写文件中的数据(可以读写文件,或网络中的数据...)
按流的方向分分为输入流和输出流 按操作文件类型分分为字节流和字符流,字节流可以操控所有类型的文件,字符流只能操控纯文本文件
基本流
字节流
操作本地文件的字节输出流,可以把程序中的数据写到本地文件中。
当使用完io流对象后都需要手动关闭链接
f.close();
FileOutputStream
创建写入流对象
FileOutputStream fos =new FileoutputStream(name:"myio//a.txt")
直接指定对应路径的文件是使用写入方式打开的
参数是字符串表示的路径或者File对象都是可以的 如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的。 如果文件已经存在,则会清空文件
FileOutputStream fos =new FileoutputStream(name:"myio//a.txt",true)
在重载的构造函数中将第二个参数append的值设为true表示使用追加方式打开,这样打开文件的时候就不会清空文件,文件指针也放在文件末尾,当写入的时候从末尾添加
方法名 | 说明 |
---|---|
void write(int b) | 一次写一个字节数据 |
void write(byte[] b) | 一次写一个字节数组数据 |
void write(byte[] b, int off, int len) | 一次写一个字节数组的部分数据,指明开始和写入长度 |
写入的内容是ascii码,如果要写入纯数字需要写该数字对应的ascii码 |
要写入字符内容可以使用getBytes()转换为ascii再写入
String str="abc123";
byte[] bytes=str.getBytes());
fos.write(bytes);
如果要换行需要手写出来换行符
- windows : \r\n
- Linux : \n
- Mac : \r 在windows操作系统当中,java对回车换行进行了优化虽然完整的是\r\n,但是我们写其中一个\r或者\n,java也可以实现换行,因为java在底层会补全。
FileInputStream
当创建流对象时如果文件不存在,就直接报错
方法 | 说明 |
---|---|
int read() | 一次读取一字节数据,如果没有数据返回-1,每次读取数据都会使文件指针向后移1,返回的是ascii码,想要查看字符串类型需要强转 |
public int read(byte[] buffer) | 一次读一个字节数组数据,返回读取的字节数 |
如果文件打开了不释放会出现问题,所以在打开文件的时候通常会捕获异常,当操作出现异常的时候就释放文件描述符,但这样也会很麻烦
java7的时候添加了一个AutoCloseable的接口,实现了这个接口的类都可以在try的小括号里面创建对象,当try...catch语句执行完毕后会自动判断对象是否需要释放,如果需要释放就会自动释放
try (FileInputStream fis =new FileInputStream(name:"D:\\itheima\\movie.mp4");
FileOutputStream fos = new FileOutputStream( name: "myiollcopy.mp4")) {
//2.拷贝
int len;
byte[] bytes = new byte[1024 * 1024 * 5];
while ((len = fis.read(bytes)) != -1){
fos.write(bytes,off:0, len);
}catch(IoException e){
e.printStackTrace();
}
编码
String类中的方法 | 说明 |
---|---|
public byte[] getBytes() | 使用默认方式进行编码 |
public byte[] getBytes(String charsetName) | 使用指定方式进行编码 |
byte[]bytes2 = str.getBytes(charsetName:"GBK");//使用gbk进行编码
System.out.println(Arrays.toString(bytes2));
解码
String类中的方法 | 说明 |
---|---|
String(byte[] bytes) | 使用默认方式进行解码 |
String(byte[] bytes, String charsetName) | 使用指定方式进行解码 |
字符流
出现乱码的两种情况:
- 当读取数据时未读完整个汉字
- 编码和解码时的方式不统一
对于第二个问题我们可以编码和解码的方式统一,所以解决乱码问题最主要的问题是第一个问题
字符流的底层其实就是字节流携带了字符集 字符流就可以在读取英文时只读取一个字节,读取中文时根据不同的字符集读取对应的字节数,这样就解决了第一个问题
输入流:一次读一个字节,遇到中文时,一次读多个字节 输出流:底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中
FileReader
创建字符输入流对象
构造方法 | 说明 |
---|---|
public FileReader(File file) | 创建字符输入流关联本地文件 |
public FileReader(String pathname) | 创建字符输入流关联本地文件 |
读取数据
成员方法 | 说明 |
---|---|
public int read() | 读取数据,读到末尾返回-1 |
public int read(char[] buffer) | 读取多个数据,读到末尾返回-1 |
空参的方法读取后返回的还是十进制的编码,需要强转才能显示出内容 | |
有参的方法读取后自动进行转码,所以是char数组 |
释放资源
成员 | 说明 |
---|---|
public int close()方法 | 释放资源/关流 |
FileWriter
构造方法 | 说明 |
---|---|
public Filewriter(File file) | 创建字符输出流关联本地文件 |
public FileWriter(String pathname) | 创建字符输出流关联本地文件 |
public FileWriter(File file, boolean append) | 创建字符输出流关联本地文件,续写 |
public FileWriter(String pathname, boolean append) | 创建字符输出流关联本地文件,续写 |
成员方法 | 说明 |
---|---|
void write(int c) | 写出一个字符,如果是中文也是编码,如25105则写入一个"我" |
void write(String str) | 写出一个字符串 |
void write(String str, int off, int len) | 写出一个字符串的一部分 |
void write(char[] cbuf) | 写出一个字符数组 |
void write(char[] cbuf, int off, int len) | 写出字符数组的一部分 |
自带了一个8196字节的缓冲区 | |
无论写入还是写出底层都有一个缓冲区 | |
可以使用成员方法手动刷新缓冲区 |
成员方法 | 说明 |
---|---|
public void flush() | 将缓冲区中的数据,刷新到本地文件中 |
public void close() | 释放资源/关流 |
flush刷新:刷新之后,还可以继续往文件中写出数据 | |
close关流:断开通道,无法再往文件中写出数据 |
高级流
高级流都不用手动关闭,在生命周期结束它会自动关闭
缓冲流
高级流的一种
字节缓冲输入流 字节缓冲输出流 字符缓冲输入流 字符缓冲输出流
缓冲流在原本的基本流上封装了一个缓冲区,这对性能有很大提升,但字符流本身就有缓冲区所以提示不是很明显
字节缓冲流
方法名称 | 说明 |
---|---|
public BufferedInputStream(InputStream is) | 把基本流包装成高级流,提高读取数据的性能 |
public BufferedOutputStream(OutputStream os) | 把基本流包装成高级流,提高写出数据的性能 |
BufferedInputStream bis =new BufferedInputStream(new FileInputStream(name:"myio\la.txt"));
BufferedoutputStream bos =new BufferedoutputStream(new FileOutputStream(name:"myio\lcopy.txt"));
字符缓冲流
方法名称 | 说明 |
---|---|
public BufferedReader(Reade r) | 把基本流变成高级流 |
public Bufferedwriter(Writer r) | 把基本流变成高级流 |
字符缓冲输流特有方法
- public String. readLine() : 读取一行数据但不会读入换行符,如果没有数据可读了,会返回null
字符缓冲输出流特有方法
- public void newLine() : 写入一个跨平台的换行
转换流
转换流也是高级流的一种是字符流和字节流之间的桥梁
转换输入流InputStreamReader 转换输出流OutputStreamWriter 将字节流转换为字符流,在读取的时候转换为字符流读入,在写出的时候再转换为字节流写出,这样就能以字节流读写(都是以二进制形式),读入后使用转换的字符流也不会出现乱码问题
转换后字节流也可以使用字符流的方法了
//转换输入流
InputStreamReader isr = new InputStreamReader(new FileInputStream("myio\\gbkfile.txt"), "GBK");
//jdk11推出的方案,更简洁
//FileReader fr = new FileReader("myiol\b.txt", Charset.forName("GBK"));
//转换输出流
OutputStreamwriter osw = new OutputstreaamWriter(new FileoutputStream("myio\\b.txt"),"GBK");
//jdk11推出的方案更简洁
FileWriter fw= new FileWriter("myiollc.txt", Charset.forName("GBK"));
序列化流与反序列化流
序列化流ObjectlnputStream
可以把Java中的对象写到本地文件中
构造方法 | 说明 |
---|---|
public Objectoutputstream(outputStream out) | 把基本流包装成高级流 |
成员方法 | 说明 |
---|---|
public final void writeobject(object obj) | 把对象序列化(写出)到文件中去 |
如果想要序列化写入一个类还需要让该类实现一个Serializable接口\
Serializable接口里面是没有抽象方法,也就无需实现 这样的接口被称为标记型接口一旦实现了这个接口,那么就表示当前的Student类可以被序列化
反序列化流ObjectOutputStream
可以把序列化到本地文件中的对象,读取到程序中来
构造方法 | 说明 |
---|---|
public ObjectInputstream(Inputstream out) | 把基本流变成高级流 |
成员方法 | 说明 |
---|---|
public object readobject() | 把序列化到本地文件中的对象,读取到程序中来 |
读出的类型还需要强转后才能还原真实的数据 |
如果在序列化一个类后再对这个类进行更改,那么反序列化取出这个类时就会报错,这是因为在序列化时会自动记录一个版本号用以标识,更改了类中的成员它的版本号也会改变,而序列化取出的类版本号还是原来的就会不匹配
可以手动指出版本号,这样更改类中成员后版本号依旧没变
public class Student implements Serializable{
private static final long serialversionuID = 1L;
}
需要在类中手动声明private static final long serialversionuID
成员变量,修饰符等都不能更改
如果修改的类增加了新的成员变量,那么旧版本中的该成员变量默认值就为null 如果修改的类删除了成员变量,那么旧版本中的类就忽略该变量
如果有的成员需要不序列化到本地文件中可以给这个成员添加transient
关键字 transient : 瞬态关键字 作用:该关键字标记的成员变量不参与序列化过程
打印流
PrintStream字节打印流 PrintWriter字符打印流
打印流只操作文件目的地,不操作数据源(只能写不能读) 特有的写出方法可以实现,数据原样写出
特有的写出方法,可以实现自动刷新,自动换行
字节打印流
构造方法 | 说明 |
---|---|
public PrintStream(OutputStream/File/String) | 关联字节输出流/文件/文件路径 |
public PrintStream(String fileName, Charset charset) | 指定字符编码 |
public PrintStream(OutputStream out, boolean autoFush) | 自动刷新 |
public PrintStream(OutputStream out, boolean autoFlush, String encoding) | 指定字符编码且自动刷新 |
字节流底层没有缓冲区,因此指定不指定自动刷新都是一样的 |
打印都是原样打印,不会进行转换
成员方法 | 说明 |
---|---|
public voidwrite(int b) | 常规方法:规则跟之前一样,将指定的字节写出 |
public void println(Xxx xx) | 特有方法:打印任意数据,自动刷新,自动换行 |
public void print(Xxx xx) | 特有方法:打印任意数据,不换行 |
public void printf(String format, Object... args) | 特有方法:带有占位符的打印语句,不换行(格式化输出) |
字符打印流
方法和字节打印流一样
构造方法 | 说明 |
---|---|
public PrintWriter(Write/File/String) | 关联字节输出流/文件/文件路径 |
public PrintWriter(String fileName, Charset charset) | 指定字符编码 |
public PrintWriter(Write w, boolean autoFlush) | 自动刷新 |
public PrintWriter(OutputStream out, boolean autoFlush, Charset charset) | 指定字符编码且自动刷新 |
成员方法 | 说明 |
---|---|
public void write(...) | 常规方法:规则跟之前一样,写出字节或者字符串 |
public void println(Xxx xx) | 特有方法:打印任意类型的数据并且换行 |
public void print(Xxx xx) | 特有方法:打印任意类型的数据,不换行 |
public void printf(String format, Object... args) | 特有方法:带有占位符的打印语句 |
压缩流与解压缩流
解压的本质:把压缩包里面的每一个文件或者文件夹读取出来,按照层级拷贝到目的地当中
解压
//1.创建一个File表示要解压的压缩包
File src = new File(pathname::"D:\\aaa.zip");
//2.创建一个File表示解压的目的地
File dest = new File( pathname:"D:\\");
//创建一个解压缩流用来读取压缩包中的数据
ZipInputStream zip = new ZipInputStream(new FileInputStream(src));
//要先获取到压缩包里面的每一个zipentry对象
//表示当前在压缩包中获取到的文件或者文件夹
ZipEntry entry;
while((entry = zip.getNextEntry()) != null){
System.out.println(entry);
if(entry.isDirectory()){
//文件夹:需要在目的地dest处创建一个同样的文件夹
File file = new File(dest,entry.toString());
file.mkdirs();
else{
//文件:需要读取到压缩包中的文件,并把他存放到目的地dest文件夹中(按照层级目录进行存放)
FileOutputStream fos = new FileOutputStream(new File(dest,entry.toString()));
int b;
while((b = zip.read()) != -1){
//写到目的地
fos.write(b);
}
fos.close();
//表示在压缩包中的一个文件处理完毕了。
zip.closeEntry();
}
zip.close();
isDirectory()判断entry对象是否是一个文件夹 getNextEntry()获取下一个压缩包内的对象,以深搜的方式
压缩
//1.创建File对象表示要压缩的文件
File src =new File(pathname:"D:\\a.txt");
//2.创建File对象表示压缩包的位置
File dest = new File(pathname::"D:\\");
7/1.创建压缩流关联压缩包
ZipOutputStream zos = new ZipoutputStream(new FileoutputStream(new File(dest, child: "a.zip")));
//2.创建zipEntry对象,表示压缩包里面的每一个文件和文件夹
ZipEntry entry = new ZipEntry( name: "a.txt");|
//3.把zipEntry对象放到压缩包当中
zos.putNextEntry(entry);
//4.把src文件中的数据写到压缩包当中
FileInputStream fis = new FileInputStream(src);
int b;
while((b = fis.read()) != -1){
zos.write(b);
}
zos.closeEntry();
zos.close();
Commons-io
Commons-io是apache开源基金组织提供的一组有关lO操作的开源工具包。 作用:提高IO流的开发效率。
FileUtils类(文件/文件夹相关) | 说明 |
---|---|
static void copyFile(File srcFile, File destFile) | 复制文件 |
static void copyDirectory(File srcDir, File destDir) | 复制文件夹 |
static void copyDirectoryToDirectory(File srcDir, File destDir) | 复制文件夹 |
static void deleteDirectory(File directory) | 删除文件夹 |
static void cleanDirectory(File directory) | 清空文件夹 |
static String readFileToString(File file, Charset encoding) | 读取文件中的数据变成成字符串 |
static void write(File file, CharSequence data, String encoding) | 写出数据 |
IOUtils类(流相关相关) | 说明 |
---|---|
public static int copy(InputStream input, OutputStream output) | 复制文件 |
public static int copyLarge(Reader input, Writer output) | 复制大文件 |
public static String readLines(Reader input) | 读取数据 |
public static void write(String data, OutputStream output) | 写出数据 |
Hutool
相关类 | 说明 |
---|---|
IoUtil | 流操作工具类 |
FileUtil | 文件读写和操作的工具类 |
FileTypeUtil | 文件类型判断工具类 |
WatchMonitor | 目录、文件监听 |
ClassPathResource | 针对ClassPath中资源的访问封装 |
FileReader | 封装文件读取 |
FileWriter | 封装文件写入 |
FileReader和FileWriter与官方的类名重了所以在导包时要注意 |
贡献者
版权所有
版权归属:PinkDopeyBug