IO流和Lambda 表达式
目录
IO流和Lambda 表达式
1. IO 分类
完成数据在文件和文件直接的传递过程。对于计算机而言,所有的内容都是文件!!!所有的内容,设备,数据都看作是文件内容,通过读写操作对文件数据进行提取和写入操作。计算机之父【冯·诺依曼】设计的基础原理。
按照处理数据单位:
字节流
数据每一次读取和写入操作基础单位为字节
使用场景很多 视频,音频,图片,文本文件...
字符流
数据每一次读取和写入操作基础单位为字符,字符需要根据当前所处计算机环境对应的默认字符集进行数据二次解
析。
字符流 ==> 字节 + 解码(根据当前计算机对应字符集进行解码)
有且只能处理通过【记事本】打开的非乱码的可读文本文件。
按照处理流向分析:
参照物 【内存】
输入流:
数据流向内存方向,为输入流
输出流:
数据从内存流出,为输出流
例如:
保存数据到硬盘上的一个 .doc 文件。输出流
从硬盘读取游戏必要运行资源到内存。 输入流
我通过内网通发送群消息给大家。输出
大家看到群消息。 输入
IO流操作基础类:
字节输入流 InputStream
字节输出流 OutputStream
字符输入流 Reader
字符输出流 Writer
2. 文件相关字节流操作
2.1 文件字节输入流
class FileInputStream extends InputStream
构造方法:
FileInputStream(String fileName);
根据文件路径创建对应的 FileInputStream 字节输入流对象
FileInputStream(File file);
根据文件对应的 File 对象,创建 FileInputStream 字节输入流对象
成员方法:
int read();
从文件中读取一个字节数据到当前 Java 程序,返回值为 int 类型,实际有效数据为 byte 类型。
int read(byte[] buf);
从文件中读取数据到 byte 类型的缓冲数组,返回值类型是读取到的文件内容字节个数
int read(byte[] buf, int off, int len);
从文件中读取数据到 byte 类型的缓冲数组,要求从数组 off 下标开始记录数据,同时要求最大长度为 len,返
回值类型是读取到的文件内容字节个数
【注意】
以上方法如果返回值为 -1 表示读取数据到文件末尾 EOF End of Filex
package com.qfedu.a_byteStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
class FileInputStream extends InputStream
构造方法:
FileInputStream(String fileName);
根据文件路径创建对应的 FileInputStream 字节输入流对象
FileInputStream(File file);
根据文件对应的 File 对象,创建 FileInputStream 字节输入流对象
成员方法:
int read();
从文件中读取一个字节数据到当前 Java 程序,返回值为 int 类型,实际有效数据为 byte 类型。
int read(byte[] buf);
从文件中读取数据到 byte 类型的缓冲数组,返回值类型是读取到的文件内容字节个数
int read(byte[] buf, int off, int len);
从文件中读取数据到 byte 类型的缓冲数组,要求从数组 off 下标开始记录数据,同时要求最大长度为 len,返
回值类型是读取到的文件内容字节个数
【注意】
以上方法如果返回值为 -1 表示读取数据到文件末尾 EOF End of Filex
文件读取操作流程:
1. 明确文件路径
2. 打开 FileInputStream 输入流管道
3. 利用 read 方法读取文件数据
4. 关闭资源。close
*/
public class Demo1 {
public static void main(String[] args) throws IOException {
}
// 有缓冲
private static void read2() throws FileNotFoundException, IOException {
// 1. 明确文件路径
String filePath = "G:/aaa/1.txt";
// 2. 打开 FileInputStream 输入流管道
FileInputStream fis = new FileInputStream(filePath);
// 3. 利用 read 方法读取文件数据
// 准备一个缓冲字节数组 缓冲数组一般选择 4KB 8KB 16KB
// 特殊说明 macOS 1000 4000 8000
byte[] buf = new byte[1024 * 4];
int length = -1;
while ((length = fis.read(buf)) != -1) {
/*
* String(char[] arr, int off, int length);
* String(byte[] arr, int off, int length);
*/
System.out.println(new String(buf, 0, length));
}
// 4. 关闭资源。close
fis.close();
}
// 无缓冲
private static void read1() throws FileNotFoundException, IOException {
// 1. 明确文件路径
String filePath = "G:/aaa/1.txt";
// 2. 打开 FileInputStream 输入流管道
FileInputStream fis = new FileInputStream(filePath);
// 3. 利用 read 方法读取文件数据
// int content = fis.read();
// System.out.println((char) content);
// 可以利用循环将整个文件读取完毕
int content = -1;
/*
* 第一步:
* content = fis.read() 从文件中读取数据到 content 变量存储
* 第二步:
* content != -1
*/
while ((content = fis.read()) != -1) {
System.out.println((char) content);
}
// 4. 关闭资源。close
fis.close();
}
}
2.2 文件字节输出流
class FileOutputStream extends OutputStream
构造方法:
FileOutputStream(String fileName);
根据用户指定的文件路径,打开对应文件的字节输出流
FileOutputStream(File file);
根据用户指定的文件对应 File 对象,打开对应文件的字节输出流
FileOutputStream(String fileName, boolean append);
根据用户指定的文件路径,打开对应文件的字节输出流
append 追加写标记为 true,当前文件内容保留,后期添加从文件末尾添加数据
FileOutputStream(File file, boolean append);
根据用户指定的文件对应 File 对象,打开对应文件的字节输出流
append 追加写标记为 true,当前文件内容保留,后期添加从文件末尾添加数据
注意:
1. FileOutputStream 如果对应文件不存在,同时文件对应路径有效合法,并且有可写入数据权限,
FileOutputStream 可以创建对应文件。
2. FileOutputStream 默认数据写入到文件的方式是【删除写】,如果需要追加写,需要在构造方法中添加追加
写标记
成员方法:
void write(int b);
在对应文件中写入一个字节(byte)数据
void write(byte[] buf);
在对应文件中,写入整个byte 类型数组数据
void write(byte[] buf, int off, int len);
在对应文件中,写入 byte 类型数组中,从下标 off 位置开始,到 len 计数个数对应的数据内容。
2.3 文件字符输入流
class FileReader extends Reader
构造方法:
FileReader(String fileName);
根据文件路径创建对应的 FileReader 字符输入流对象
FileReader(File file);
根据文件对应的 File 对象,创建 FileReader 字符输入流对象
成员方法:
int read();
从文件中读取一个字符数据到当前 Java 程序,返回值为 int 类型,实际有效数据为 char 类型。
int read(char[] buf);
从文件中读取数据到 char 类型的缓冲数组,返回值类型是读取到的文件内容字符个数
int read(char[] buf, int off, int len);
从文件中读取数据到 char 类型的缓冲数组,要求从数组 off 下标开始记录数据,同时要求最大长度为 len,返
回值类型是读取到的文件内容字符个数
【注意】
以上方法如果返回值为 -1 表示读取数据到文件末尾 EOF End of Filex
package com.qfedu.b_charStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/*
字符输入流
class FileReader extends Reader
构造方法:
FileReader(String fileName);
根据文件路径创建对应的 FileReader 字符输入流对象
FileReader(File file);
根据文件对应的 File 对象,创建 FileReader 字符输入流对象
成员方法:
int read();
从文件中读取一个字符数据到当前 Java 程序,返回值为 int 类型,实际有效数据为 char 类型。
int read(char[] buf);
从文件中读取数据到 char 类型的缓冲数组,返回值类型是读取到的文件内容字符个数
int read(char[] buf, int off, int len);
从文件中读取数据到 char 类型的缓冲数组,要求从数组 off 下标开始记录数据,同时要求最大长度为 len,返
回值类型是读取到的文件内容字符个数
【注意】
以上方法如果返回值为 -1 表示读取数据到文件末尾 EOF End of File
流程
1. 明确文件位置
2. 打开 FileReader 管道
3. 读取数据
4. 关闭资源
*/
public class Demo1 {
public static void main(String[] args) throws IOException {
}
private static void read2() throws FileNotFoundException, IOException {
// 1. 明确文件位置
String filePath = "G:/aaa/1.txt";
// 2. 打开 FileReader 管道
FileReader fr = new FileReader(filePath);
// 3. 读取数据 8KB 缓冲字符数组, char 类型占 2 个字节
char[] buf = new char[1024 * 4];
int length = -1;
while ((length = fr.read(buf)) != -1) {
System.out.println(new String(buf, 0, length));
}
// 4. 关闭资源
fr.close();
}
private static void read1() throws FileNotFoundException, IOException {
// 1. 明确文件位置
String filePath = "G:/aaa/1.txt";
// 2. 打开 FileReader 管道
FileReader fr = new FileReader(filePath);
// 3. 读取数据
int content = -1;
while ((content = fr.read()) != -1) {
System.out.println((char) content);
}
// 4. 关闭资源
fr.close();
}
}
2.4 文件字符输出流
class FileWriter extends Writer
构造方法:
FileWriter(String fileName);
根据用户指定的文件路径,打开对应文件的字符输出流
FileWriter(File file);
根据用户指定的文件对应 File 对象,打开对应文件的字符输出流
FileWriter(String fileName, boolean append);
根据用户指定的文件路径,打开对应文件的字符输出流
append 追加写标记为 true,当前文件内容保留,后期添加从文件末尾添加数据
FileWriter(File file, boolean append);
根据用户指定的文件对应 File 对象,打开对应文件的字符输出流
append 追加写标记为 true,当前文件内容保留,后期添加从文件末尾添加数据
注意:
1. FileWriter 如果对应文件不存在,同时文件对应路径有效合法,并且有可写入数据权限,
FileWriter 可以创建对应文件。
2. FileWriter 默认数据写入到文件的方式是【删除写】,如果需要追加写,需要在构造方法中添加追加
写标记
成员方法:
void writer(String str);
void write(int ch);
在对应文件中写入一个字符(char)数据
void write(char[] buf);
在对应文件中,写入整个 char 类型数组数据
void write(char[] buf, int off, int len);
在对应文件中,写入 char 类型数组中,从下标 off 位置开始,到 len 计数个数对应的数据内容。
void writer(String str);
在对应文件中,写入 String 类型字符串
void writer(String str, int off, int len);
在对应文件中,写入 String 类型字符串,从下标 off 位置开始,到 len 计数个数对应的数据内容。
2. Lambda 表达式
2.1 无参数无返回 Lambda
需要定义一个接口,并且接口中有且只有一个未完成的方法!!!就一个函数式接口,最好使用 @FunctionalInterface 开启检查
@FunctionalInterface
interface A {
void test();
}
准备一个方法,方法参数是接口 A 类型
public static void testLambda(A a) {
a.test();
}
package com.qfedu.c_lambda;
/*
* 1. 完成 接口 A 实现类 通过该 实例化对象作为方法参数调用执行 testLambda
* 2. 直接使用 接口 A 的匿名内部类的匿名对象作为 testLambda 方法参数
* 3. Lambda 表达式操作
*/
@FunctionalInterface
interface A {
void test();
}
class TypeA implements A {
@Override
public void test() {
System.out.println("实现类 TypeA 实现完成 test 方法");
}
}
public class Demo1 {
/*
* JVM 执行 main 方法
*/
public static void main(String[] args) {
// 方式一
testLambda(new TypeA());
// 方式二 JDK 1.8 之前
testLambda(new A() {
@Override
public void test() {
System.out.println("匿名内部类的匿名对象,直接作为方法的参数");
}
});
/*
* 【重点】方式三 Lambda表达式
* () 对应当前 接口 A 中的 test 方法没有参数
* -> Java Lambda 表达式语法规则
* {} 表示需要完成的方法体内容
* 当前 接口A 中的方法 void test() 没有返回值,所以在 Lambda 表达式对应
* 大括号中无需return关键字返回数据
*/
testLambda(() -> {
System.out.println("Lambda表达式直接作为方法的参数");
});
// Lambda 表达式有且只有一行代码,可以省略大括号
testLambda(() -> System.out.println("如果Lambda表达式只有一行,可以省略大括号"));
}
public static void testLambda(A a) {
a.test();
}
}
2.2 有参数无返回 Lambda
需要定义一个接口,并且接口中有且只有一个未完成的方法!!!就一个函数式接口,最好使用
@FunctionalInterface 开启检查
/*
当前接口是一个函数式接口,有且只有一个未完成的方法,同时方法参数为 String 类型,返回值为 void
有参数无返回
*/
@FunctionalInterface
interface Consumer {
void accept(String str);
}
package com.qfedu.c_lambda;import javax.activation.CommandInfo;
/*
当前接口是一个函数式接口,有且只有一个未完成的方法,同时方法参数为 String 类型,返回值为 void
有参数无返回
Consumer 接口目前来看,是一个针对于 String 类型的处理器
*/
@FunctionalInterface
interface Consumer {
/**
* Consumer 接口中规定了处理了 String 类型的方法
*
* @param str String 类型字符串
*/
void accept(String str);
}
public class Demo1 {
public static void main(String[] args) {
// 匿名内部类方式完成方法调用操作
testLambda("北平在不在???", new Consumer() {
@Override
public void accept(String str) {
System.out.println(str);
}
});
/*
* Lambda 表达式如果有参数,参数名称是一个自定义临时变量,随便你!!! 小括号定义的变量可以在Lambda表达式中使用
*/
testLambda("有问题就问!!!不会就问!!!截图问,语音问,不行电话问!!!", (s) -> {
System.out.println(s);
});
/*
* 1. 方法体一句话,可以省略大括号
* 2. 参数就一个,小括号也可以不要
*/
testLambda("Lambda简化!!!", s -> System.out.println(s));
/*
* 目标执行方法是 System.out.println 直接点!!!方法引用
*/
testLambda("方法引用!!!", System.out::println);
testLambda("方法引用!!!", Demo1::parseString);
}
/**
* 测试方法,参数是字符串类型数据和处理字符串 Consumer 处理器
*
* @param str String 字符串
* @param consumer Consumer 接口,其中规定了一个处理 String 类型数据的方法
*/
public static void testLambda(String str, Consumer consumer) {
consumer.accept(str);
}
public static void parseString(String str) {
System.out.println(str.length());
}
}
2.3 无参数有返回 Lambda
/*
供应商,供应者 生产者
*/
@FunctionalInterface
interface Supplier {
int get();
}
package com.qfedu.c_lambda;
/*
供应商,供应者 生产者
*/
@FunctionalInterface
interface Supplier {
int get();
}
public class Demo2 {
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 19, 2, 4, 6, 8, 10};
/*
* 找出数组最大值下标位置
*
* Lambda 表达式中可以利用在对应方法大括号中,Lambda 表达式之前的方法内部局部变量
*/
int maxIndex = testLambda(() -> {
int index = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[index] < arr[i]) {
index = i;
}
}
// 当前 Lambda 表达式对应方法有返回值,必须要对应当前返回值类型给予对应数据
return index;
});
System.out.println(maxIndex);
}
/**
* 测试方法
*
* @param supplier Supplier 生产者接口
* @return int 类型
*/
public static int testLambda(Supplier supplier) {
return supplier.get();
}
}
2.4 有参数有返回 Lambda ☆
@FunctionalInterface
interface Predicate {
boolean test(String str);
}
package com.qfedu.c_lambda;
@FunctionalInterface
interface Predicate {
/**
* 判断器/过滤器 规定的方法,所需参数为 字符串类型,返回值为 int 类型
*
* @param str String 字符串
* @return 根据实现结果和条件要求返回 boolean
*/
boolean test(String str);
}
public class Demo3 {
public static void main(String[] args) {
String str = "噶周董腰子两个用于校区建设";
// boolean test(String str);
boolean ret = testLambda(str, (s) -> {
return s.length() > 20;
});
System.out.println(ret);
/*
* 1. 一个参数可以把小括号省略
* 2. 一行代码,可以省大括号
* 3. 一行代码,一个return return 不要了
*/
ret = testLambda(str, s -> s.length() > 10);
System.out.println(ret);
}
/**
* 判断字符串,是否满足条件 Lambda 演示方法
*
* @param str String 字符串
* @param predicate 判断器/过滤器 接口规范
* @return 判断/过滤结果返回
*/
public static boolean testLambda(String str, Predicate predicate) {
return predicate.test(str);
}
}
2.5 Lambda + 泛型案例
package com.qfedu.c_lambda;
import java.util.Arrays;
import java.util.Comparator;
interface HandlerNumber {
int sum(int n1, int n2, int n3);
}
public class Demo4 {
public static void main(String[] args) {
/*
* Person 类型数组
*/
Person[] arr = {
new Person(1, "周董", 56),
new Person(2, "北平", 76),
new Person(3, "王老师", 16),
new Person(4, "王乾", 26),
new Person(5, "刘某", 15),
new Person(6, "智广", 66)
};
/*
* public static <T> void parallelSort(T[] a, Comparator<T> cmp)
*
* 第一个参数是泛型约束的数组,传入的实际参数为数组类型,同时数组存储数据内容,约束泛型对应具体数据类型
*
* Comparator 比较器接口 java.util.Comparator<T>,当前数组明确数据类型,
* 需要提供对应数组类型的 Comparator 比较器对象
* int compare(T o1, T o2);
*/
Arrays.sort(arr, (p1, p2) -> p1.getAge() - p2.getAge());
for (Person person : arr) {
System.out.println(person);
}
int testLambda = testLambda(10, 20, 30, (n1, n2, n3) -> n1 + n2 + n3);
System.out.println(testLambda);
}
public static int testLambda(int num1, int num2, int num3, HandlerNumber hn) {
return hn.sum(num1, num2, num3);
}
}