文章目录
IO流和Lambda表达式
1. IO流
1.1 IO流概述
IO流
流 水流,电流,气流
IO Input 输入 Output 输出
输入输出是存在参照物,参照物是当前运行程序。
IO流在开发中的用途
1. 文件内容操作
2. 网络数据传输 TCP/IP UDP NIO Netty WebSocket
3. 数据库内容传递
IO分类
输入流
字节输入流
字符输入流
输出流
字节输出流
字符输出流
1.2 IO流操作涉及到的类
字节输入流
InputStream 字节输入流基类
--| FileInputStream 文件操作字节输入流
字节输出流
OutputStream 字节输出流基类
--| FileOutputStream 文件操作字节输出流
字符输入流
Reader 字符输入流基类
--| FileReader 文件操作字符输入流
字符输出流
Writer 字符输出流基类
--| FileWriter 文件操作字符输出流
学习的方法:
read
write
1.3 文件操作字节输入流
构造方法:
FileInputStream(String pathName);
FileInputStream(File file);
一个是根据用户给定的文件路径,一个是根据用户给定的File对象,创建对应的文
件操作字节输入流,存在异常抛出 FileNotFoundException 文件未找到异常
操作方法:
int read();
从文件中读取一个字节数据返回。
int read(byte[] buf);
从文件中读取数据到当前byte类型数组中,返回值类型是读取到byte类型数组中的
字节个数
int read(byte[] buf, int off, int len);
从文件中读取数据到当前byte类型数组中,要求从off偏移量位置开始,计数长度
为len,返回值类型是读取到的字节个数
【注意】
1.以上所有的read方法,如果读取到文件末尾,返回值为 -1 EOF End Of
File
2. 所有的read方法,都会抛出IOException
package com.qfedu.a_io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* 文件操作字节输入流
* FileInputStream
*
* 1. 确定文件
* 2. 开启FileInputStream通道
* 3. 使用read方法读取数据和数据处理
* 4. 关闭资源
*/
public class Demo1 {
public static void main(String[] args) throws IOException {
}
public static void readTest2() throws FileNotFoundException, IOException {
// 1. 确定文件
String filePath = "G:/aaa/你大爷的.txt";
// 2. 开启FileInputStream通道
FileInputStream fis = new FileInputStream(filePath);
// 3. 读取数据,需要准备一个byte类型数组 当前缓冲数组容量为8KB
byte[] buf = new byte[1024 * 8];
int length = -1;
while ((length = fis.read(buf)) != -1) {
// 将读取到的数据,转换成一个String字符串
System.out.println(new String(buf, 0, length));
}
// 4. 关闭资源
fis.close();
}
public static void readTtest1() throws FileNotFoundException, IOException {
// 1. 确定文件
String filePath = "G:/aaa/你大爷的.txt";
// 2. 开启FileInputStream通道
FileInputStream fis = new FileInputStream(filePath);
int content = -1;
// 3. 读取数据
while ((content = fis.read()) != -1) {
System.out.println((char) content);
}
// 4. 关闭资源
fis.close();
}
}
1.4 文件操作字节输出流
构造方法:
FileOutputStream(String filePath);
FileOutputStream(File file);
FileOutputStream(String filePath, boolean append);
FileOutputStream(File file, boolean append));
根据用户给定的文件路径或者File类对象,创建对应FileOutputStream对象。
【注意】
1. 在创建FileOutputStream流对象过程中,如果文件不存在,并且路径合
法!!!可以直接创建对应文件。
2. 在未约束FileOutputStream对象情况下,默认采用的写入数据模式是删除
写。如果想要追加写,在构造方法中添加一个参数 boolean append 赋值为
true
操作方法:
void write(int b);
写入一个字节数据到文件中,要求数据类型为int类型,但是实际写入数据是int类
型低8位 ==> byte类型数据
void write(byte[] buf);
写入一个字节数组到文件中
void write(byte[] buf, int off, int len);
写入一个字节数组到文件中,要求从off偏移位置开始,指定长度为len
package com.qfedu.a_io;
import java.io.FileOutputStream;
import java.io.IOException;
/*
* 文件操作字节输出流
*
* 1. 确定文件位置
* 2. 打开FileOutputStream流管道
* 3. 写入数据 write
* 4. 关闭资源
*/
public class Demo2 {
public static void main(String[] args) throws IOException {
// 1. 确定文件位置
String filePath = "G:/aaa/你二大爷的.txt";
// 2. 创建FileOutputStream流管道
FileOutputStream fos = new FileOutputStream(filePath);
// 3. 写入数据
fos.write(550);
fos.write("ABCDEFG".getBytes());
fos.write("ABCDEFG".getBytes(), 2, 5);
// 4. 关闭close
fos.close();
}
}
1.5 字节流拷贝文件
package com.qfedu.a_io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/*
* 字节流拷贝文件
*/
public class Demo3 {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
// 1. 开启FileInputStream对象
FileInputStream fis = new FileInputStream("G:/aaa/1.mp4");
// 2. 开启FileOutputStream对象
FileOutputStream fos = new FileOutputStream("G:/aaa/华哥の帅帅.mp4");
// 3. 准备缓冲数组
byte[] buf = new byte[1024 * 8];
int length = -1;
// 4. 读取数据,写入数据
while ((length = fis.read(buf)) != -1) {
fos.write(buf, 0, length);
}
// 5. 关闭资源,先开后关,后开先关
fos.close();
fis.close();
long end = System.currentTimeMillis();
System.out.println("Time : " + (end - start));
}
}
1.6 字符流操作限制
1. 操作对应的文件有且只能是记事本可以打开的可视化文本文件。
2. 要求操作过程中,文件对应的编码集和当前程序对应编码集一致。
1.7 文件操作字符输入流
构造方法:
FileReader(String pathName);
FileReader(File file);
一个是根据用户给定的文件路径,一个是根据用户给定的File对象,创建对应的文
件操作字节输入流,存在异常抛出 FileNotFoundException 文件未找到异常
操作方法:
int read();
从文件中读取一个字符数据返回。
int read(char[] buf);
从文件中读取数据到当前byte类型数组中,返回值类型是读取到char类型数组中的
字符个数
int read(char[] buf, int off, int len);
从文件中读取数据到当前char类型数组中,要求从off偏移量位置开始,计数长度
为len,返回值类型是读取到的字符个数
【注意】
1.以上所有的read方法,如果读取到文件末尾,返回值为 -1 EOF End Of
File
2. 所有的read方法,都会抛出IOException
1.8 文件操作字符输出流
构造方法:
FileWriter(String filePath);
FileWriter(File file);
FileWriter(String filePath, boolean append);
FileWriter(File file, boolean append));
根据用户给定的文件路径或者File类对象,创建对应FileWriter对象。
【注意】
1. 在创建FileWriter流对象过程中,如果文件不存在,并且路径合
法!!!可以直接创建对应文件。
2. 在未约束FileWriter对象情况下,默认采用的写入数据模式是删除
写。如果想要追加写,在构造方法中添加一个参数 boolean append 赋值为
true
操作方法:
void write(int b);
写入一个字符数据到文件中,要求数据类型为int类型,但是实际写入数据是int类
型低16位 ==> byte类型数据
void write(byte[] buf);
写入一个字节数组到文件中
void write(byte[] buf, int off, int len);
写入一个字节数组到文件中,要求从off偏移位置开始,指定长度为len
void write(String str);
void write(String str, int off, int len);
2. 缓冲流
2.1 缓冲的概念
CPU通过内存读取硬盘数据的小要求
1. 磁盘每一个扇区是4096字节
2. CPU每一次读取数据都需要首先从磁盘中读取4096字节
缓冲的使用
1. 提供程序操作文件的效率
2. 可以保护磁盘
2.2 缓冲流对应类
缓冲流没有任何的读写能力。只是一个仓库中转站。只是提供缓冲和临时存储功能。所有的读写能力都来自于对应输入流和输出流
BufferedInputStream
字节缓冲输入流
构造方法所需参数是InputStream对象。需要字节输入流来提供读取文件的
能力。
BufferedOutputStream
字节缓冲输出流
构造方法所需参数OutputStream对象,需要字节输出流提供写入数据到文件
的能力
BufferedReader
字符缓冲输入流
构造方法所需参数Reader对象,需要字符输出流提供读取数据到文件
的能力
String readLine(); 读取一行数据
BufferedWriter
字符缓冲输出流
构造方法所需参数Writer对象,需要字符输出流提供写入数据到文件
的能力
void newLine(); 在文件中换行
2.3 字节缓冲操作,输入输出
package com.qfedu.b_buffered;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
* 字节缓冲
*/
public class Demo1 {
public static void main(String[] args) throws IOException {
writeTest();
bufferedWrite();
}
public static void writeTest() throws FileNotFoundException, IOException {
long start = System.currentTimeMillis();
FileOutputStream fis = new FileOutputStream("G:/aaa/十三姨.txt");
String str = "黄飞鸿 大战 马保国 之 年轻人不讲武德,耗子尾汁\n";
int num = 1000000;
while (num > 0) {
fis.write(str.getBytes());
num--;
}
fis.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
public static void bufferedWrite() throws FileNotFoundException, IOException {
long start = System.currentTimeMillis();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("G:/aaa/十三姨.txt"));
String str = "黄飞鸿 大战 马保国 之 年轻人不讲武德,耗子尾汁\n";
int num = 1000000;
while (num > 0) {
bos.write(str.getBytes());
num--;
}
bos.close();
long end = System.currentTimeMillis();
// 33
System.out.println(end - start);
}
public static void readTest() throws FileNotFoundException, IOException {
long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("G:/aaa/你大爷的.txt");
while (fis.read() != -1) {
}
fis.close();
// 10000ms
long end = System.currentTimeMillis();
System.out.println(end - start);
}
public static void bufferedReadFile() throws FileNotFoundException, IOException {
long start = System.currentTimeMillis();
/*
* BufferedInputStream 默认情况下底层是一个8KB字节缓冲数组,所有的读取文件的操作都是在当前
* 缓冲数组中完成的,读取在内存数组中获取数据,如果数组数据读取完毕,一次性从硬盘读取8KB数据。
*/
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("G:/aaa/你大爷的.txt"));
while (bis.read() != -1) {
}
// 130ms
bis.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}
2.4 缓冲字符流操作读写
package com.qfedu.b_buffered;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("G:/aaa/十三姨.txt"));
System.out.println(br.readLine());
br.close();
BufferedWriter bw = new BufferedWriter(new FileWriter("G:/aaa/十三姨夫.txt"));
bw.write("吴京\n");
bw.write("张译\n");
bw.write("管虎\n");
bw.write("郭帆\n");
bw.close();
}
}
3. Lambda表达式【重点】
3.1 Lambda表达式使用条件
1. 存在接口
2. 接口中有且只有一个未实现方法,该接口可以认为是【函数式接口】。在原码中存在使用注解@FunctionalInterface 来约束当前接口
3. Lambda表达式用于方法中,要求当前方法的参数是接口,需要为接口的实现类对象。
【说重点】
一个接口中有且只有一个未实现的abstract方法
--| 目标 就是为了使用该方法
----| class 类来遵从当前接口,需要必须实现缺省属性为abstract的方法,
------| 在方法中传入接口的实现类,最终目标是为了通过实现类对象来调用方法。
Lambda就是直接实现当前方法运行内容 ==> 方法体!!!
3.2 无参数无返回值Lambda
package com.qfedu.c_lambda;
/*
* 无参数无返回值Lambda
* 和接口名字无关,只是在考虑当前接口中唯一没有实现的方法,返回值类型为void,参数为空
*
* @FunctionalInterface 函数式接口注解/标记,要求当前接口中有且只有一个未完成方法
*/
@FunctionalInterface
interface A {
void test();
}
public class Demo1 {
public static void main(String[] args) {
// low
testLambda(() -> {
System.out.println("无参数无返回值Lambda表达式");
});
// 如果Lambda表达式有且一行代码,可以省略大括号!!!
testLambda(() -> System.out.println("这才是最好的!!!"));
}
public static void testLambda(A a) {
a.test();
}
}
3.3 有参数无返回值Lambda
消费方法接口
当前Lambda表达式对应接口中的方法,有参数,但是没有返回值,这是一个消费方法接口,数据通过当前Lambda处理之后,没有任何的反馈。是最终处理模式!!!
package com.qfedu.c_lambda;
import java.util.ArrayList;
/*
* 消费接口,接收数据,但是没有反馈
*/
@FunctionalInterface
interface Consumer<T> {
// 接口数据方法 需要的类型还是泛型!!!
void accept(T t);
}
public class Demo2 {
public static void main(String[] args) {
testLambda("让我看到你的眼!!!",
// 脑补数据类型 t ==> String类型 t会成为当前Lambda表达式对应代码块中的局部变量参数
(str) -> System.out.println(str));
ArrayList<String> list1 = new ArrayList<String>();
list1.add("雪碧");
list1.add("芬达");
list1.add("可口可乐");
list1.add("酷儿");
list1.add("酸梅汤");
testLambda(list1, (list) -> {
for (String string : list1) {
System.out.println(string);
}
});
testLambda(10, (i) -> System.out.println("low : " + i));
}
/**
* 当前方法带有自定义泛型,泛型对应的具体数据类型,通过第一个参数约束
*
* @param <T> 自定义泛型
* @param t 用于约束当前泛型对应具体数据类型的参数
* @param consumer 消费处理数据的接口
*/
public static <T> void testLambda(T t, Consumer<T> consumer) {
consumer.accept(t);
}
}
3.4 无参数有返回值Lambda
生产者方法接口,什么都不要,返回的全是输出!!!
package com.qfedu.c_lambda;
interface Supplier<T> {
T get();
}
public class Demo3 {
public static void main(String[] args) {
String str = "<<稻香>> 周杰伦";
// 方法中使用的Lambda表达式是可以在当前大括号范围以内使用对应的局部变量!!!
String reverse = testLambda(str, () -> new StringBuilder(str).reverse().toString());
System.out.println(reverse);
int[] arr = {1, 3, 5, 7, 29, 2, 4, 6, 8, 20};
int maxIndex = testLambda2(arr, () -> {
int index = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[index] < arr[i]) {
index = i;
}
}
return index;
});
System.out.println(maxIndex);
}
public static <T> T testLambda(T t, Supplier<T> supplier) {
return supplier.get();
}
// Max value index in current int Array;
public static int testLambda2(int[] arr, Supplier<Integer> supplier) {
return supplier.get();
}
}
3.5 有参数有返回值Lambda
对应的方法都是有脸有面!!!
非常nice的方法!!!
Comparator<T>
int compare(T o1, T o2);
Arrays.sort(T[] arr, Comparator<T> compare)
Function<T, R> 转换!!!
R apply(T t);
package com.qfedu.c_lambda;
import java.util.Arrays;
interface Function<T, R> {
R apply(T t);
}
public class Demo4 {
public static void main(String[] args) {
Student[] allStus = new Student[10];
for (int i = 0; i < allStus.length; i++) {
int id = i + 1;
String name = "苟磊" + (i + 1);
int age = (int) (Math.random() * 17);
char gender = '男';
allStus[i] = new Student(id, name, age, gender);
}
/*
* Arrays.sort(allStus, new Comparator<Student>() {
*
* @Override public int compare(Student o1, Student o2) { // TODO Auto-generated
* method stub return o1.getAge() - o2.getAge(); } });
*/
Arrays.sort(allStus, (stu1, stu2) -> stu1.getAge() - stu2.getAge());
for (Student student : allStus) {
System.out.println(student);
}
System.out.println();
// 字符串转Student对象
String str = "11,苟帅,99,X";
Student transform = transform(str, Student.class, (info) -> {
String[] split = info.split(",");
int id = Integer.valueOf(split[0]);
String name = split[1];
int age = Integer.valueOf(split[2]);
char gender = split[3].charAt(0);
return new Student(id, name, age, gender);
});
System.out.println(transform);
}
public static <T, R> R transform(T t, Class<R> cls, Function<T, R> fun) {
return fun.apply(t);
}
}