Java 学习记录 第七天
学习目标
了解Java流、文件、io的概念
学习内容
- Java流(stream)
- Java文件(File)
- io
Java流(stream)
一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。
Java 中的 流 ( Stream ) 表示来自 源 ( source ) 的一系列对象,它支持统计、求和、求平均值等聚合操作。
流具有以下特征:
- 元素序列: 流以顺序方式提供特定类型的一组元素。流只会按需获取/计算元素。但它从不存储元素。
- 源 ( Source ): 流可以将集合,数组或 I/O 资源作为输入源。
- 聚合操作: 流支持聚合操作,如 filter、map、limit、reduce、find、match 等
- 管道 ( pipelining ): 大多数流操作都返回流本身,以便可以对其结果进行流水线操作。这些操作称为 中间 操作,它们的功能是获取输入,处理它们并将输出返回到目标。collect() 方法是一个终端操作,通常在流水线操作结束时出现,以标记流的结尾。
- 原子性迭代 ( Automatic iterations ): 与需要显式迭代的集合相比,流操作在内部对所提供的源元素进行迭代。
Java 8 在推出流的同时,对集合框架也进行了一些比较大变更。主要是在 Collection 接口上提供了两种生成 Stream 的方法:
流的创建:
- stream() 方法,该方法以集合作为源,返回集合中的所有元素以在集合中出现的顺序组成的流。
- parallelStream() 方法,该方法以集合作为源,返回一个支持并发操作的流。
流支持的聚合操作:
- forEach() 方法: Java 8 为 Stream 提供了一种新方法 forEach(),用于迭代流的每个元素。
- map() 方法: 方法会迭代流中的元素,并为每个元素应用一个方法,然后返回应用后的流。
- filter() 方法: 方法根据一个谓词来过滤元素。这个谓词是一个方法,以流中的每一个元素作为参数,如果返回 true 则会被过滤掉。
- limit() 方法: 方法用于减少( 限制 ) 流中的元素数量。
- sorted() 方法: 方法用于给流中的元素进行排序。
import java.util.Random;
public class Test1 {
public static void main(String[] args) {
// 下面的代码片段演示了如何使用 forEach 打印 10 个随机数。
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
}
}
上面这个代码片段中,Random 对象的 ints() 方法会返回一个整数流。而 limit() 方法则限制了流中的元素个数。从某些方面说,可以理解为当源产生了 10 个随机数之后就关闭源。输出结果如下:
下面的代码,使用 map() 方法把求出每个元素的平方,然后过滤掉重复的元素,最后在转换为列表集合:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Test1 {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> squaresList = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());
System.out.println("\n重组后的数组: " + squaresList);
}
}
map( i -> i*i) 操作求取流中每个元素的平方,并返回一个新的流。distinct() 方法则用于过滤流中的重复元素。输出结果如下:
下面的代码,使用 filter() 方法过滤不是后羿的英雄:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Test1 {
public static void main(String[] args) {
List<String> heros = Arrays.asList("后羿", "鲁班", "孙尚香", "后羿", "");
long count = heros.stream().filter(hero -> hero.equals("后羿")).count();
System.out.println("\n返回数组中后羿的数量:" + count);
}
}
通过 filter(hero -> hero.equals(“后羿”)) 把不是后羿的英雄过滤掉,再使用 count() 返回数量,输出结果如下:
用刚刚的例子再说明下排序:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Test1 {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> squaresList = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());
List<Integer> squaresSortList = squaresList.stream().sorted().collect(Collectors.toList());
System.out.println("\n重组后的数组: " + squaresList);
System.out.println("\n重组排序后的数组: " + squaresSortList);
}
}
将得到数组通过 sorted() 方法再进行排序后输出,结果为:
并发处理
parallelStream() 是需要并发处理的流的替代方案。stream() 方法产生的流只能是串行处理,可以理解为只在一个线程中,按照流中元素的顺序一个接一个的处理。而并发处理,就是传说中的 map-reduce 方法,可以充分利用多核优势。需要注意的是,parallelStream() 会打乱流的顺序,也就是返回的序列顺序不一定是输入的序列顺序。
因为 stream() 返回是串行流,而 parallelStream() 返回的是并行流。因此在串行和并行之间切换是非常简单的。
收集器( Collectors )
- Collectors.toList() 方法可以将流中的元素收集起来,并转换为列表。
- Collectors.joining() 方法可以将流中的元素收集起来,并使用指定的字符串拼接符拼接成一个字符串。
统计 ( Statistics )
Java 8 同时新增了大量的统计收集器来来获取流中的元素的一些统计信息。
前提是我们先要在流上调用 summaryStatistics() 方法返回统计信息概要,然后在调用相应的方法来获取具体的统计信息。
这边就简单做几个方法的记录,因为实在太多了,以后要用再查文档吧。
Java文件(File)
Java标准库的java.io.File对象表示一个文件或者目录:
- 创建File对象本身不涉及IO操作;
- 可以获取路径/绝对路径/规范路径:getPath()/getAbsolutePath()/getCanonicalPath();
- 可以获取目录的文件和子目录:list()/listFiles();
- 可以创建或删除文件和目录。
import java.io.File;
import java.io.IOException;
public class Test3 {
public static void filesInfo(String dir) throws IOException {
File file = new File(dir);
if (!file.isDirectory()) {
throw new IOException(dir + " 不是目录");
}
if (file == null) {
throw new IOException("没有此路径");
}
File[] files = file.listFiles();
for (File f : files) {
if (f.isDirectory()) {
filesInfo(f.getAbsolutePath());
} else {
System.out.println(f.getAbsolutePath());
}
}
}
public static void main(String[] args) throws IOException {
filesInfo("D:\\JJFiles\\java-test\\test-demo-7");
System.out.println("~~~~~~~~~~~~~~~~~~~");
// 我的电脑没有G盘,特意做个实验
filesInfo("G:\\JJFiles\\java-test\\test-demo-7");
System.out.println("~~~~~~~~~~~~~~~~~~~");
}
}
输出结果如下:
io
Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。
Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Test2 {
public static void main(String[] args) throws IOException {
char c;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入英雄名字,按下\"q\"键退出");
do {
c = (char) br.read();
System.out.println(c);
}while (c != 'q');
}
}
输出结果如下:
明天再继续,时间不够了。
自学不易,点赞鼓励。
谢谢各位看官,如果有哪里写错的还望指出来哈,共同进步。