Stream流-初体验
Stream 流:专门用来快速处理集合或数组的一个工具
体验Stream流
需求:按照下面的要求完成集合的创建和遍历
- 创建一个集合,存储多个字符串元素
- 把集合中所有以 “张” 开头的元素存储到一个新的集合
- 把 “张” 开头的集合中的长度为3的元素存储到一个新的集合
- 遍历上一步得到的集合
传统方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public static void main(String[] args){
//集合的批量添加
ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子", "谢广坤"));
//遍历list1,把以张开头的元素添加到1ist2中。
ArrayList<String> list2 = new ArrayList<>();
for (String s : list1){
if(s.startswith("张")){
list2.add(s);
}
}
//遍历list2集合,把其中长度为3的元素,再添加到1ist3中。
ArrayList<String> list3 = new ArrayList<>();
for (String s : list2){
if(s.length() == 3){
list3.add(s);
}
}
//遍历list3集合,输出打印
for(String s : list3){
System.out.println(s);
}
}
|
Stream流的方式写
1
2
3
|
list1.stream().filter(s -> s.startswith("张"))
.filter(s -> s.length() == 3)
forEach(s -> System.out.println(s));
|
Stream流-思想特点
Stream流思想
假设有流水线如下
Stream流的三种方法
- 获取 Stream 流:创建一条流水线,并把数据放到流水线上准备进行操作
- 中间方法(流水线上的操作):一次操作完毕之后,还可以继续进行其他操作
- 终结方法(流水线上的最后一个操作):一个 Stream 流只能有一个终结方法
Stream流-获取方法
Stream流的获取方法
单列集合
- 可以使用 Collection 接口中的默认方法 stream() 生成流
- default Stream stream()
双列集合
- 间接的生成流
- 可以先通过 keySet 或者 entrySet 获取一个 Set 集合,再获取 Stream 流
数组
同种数据类型的多个数据
- 1, 2, 3, 4, 5…..
- “aaa”, ”bbb”, ”ccc”……
- 使用Stream.of(T…values)生成流
单列集合
1
2
3
4
5
6
7
8
9
|
public static void main(String[] args){
//单列集合
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
Stream<String> stream = list.stream();
stream.forEach(s -> System.out.println(s));
}
|
双列集合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public static void main(String[] args){
HashMap<String,Integer> hm = new HashMap<>();
hm.put("zhangsan", 23);
hm.put("lisi", 24);
hm.put("wangwu", 25);
hm.put("zhaoliu", 26);
hm.put("qianqi", 27);
//双列集合不能直接获取Stream流
//keyset
//先获取到所有的键
//再把这个Set集合中所有的键放到stream流中
hm.keyset().stream().forEach(s -> system.out.println(s)); //zhangsan,lisi,wangwu,zhaoliu,qianqi
//entryset
//先获取到所有的键值对对象
//再把这个Set集合中所有的键值对对象放到Stream流中
hm.entryset().stream().forEach(s -> System.out.println(s));//zhangsan=23,lisi=24......
}
|
hm.values().stream() //获取 map 集合中值的 stream 流
数组
1
2
3
4
5
6
7
8
9
|
public static void main(String[] args){
int[] arr = {1, 2, 3, 4, 5};
Arrays.stream(arr).forEach(new IntConsumer(){
@Override
public void accept (int value){
System.out.println(value);
}
});
}
|
同种类型的多个数据
1
2
3
4
5
6
7
8
|
public static void main(String[] args){
Stream.of (1, 2, 3, 4, 5, 6, 7, 8, 9).forEach (new Consumer<Integer>(){
@Override
public void accept(Integer integer){
System.out.println(integer);
}
});
}
|
小结
Stream流的获取
- 单列集合:集合对象.stream();
- 双列集合:不能直接获取,需要间接获取
- 集合对象.keySet().stream();
- 集合对象.entrySet().stream();
- 数组:Arrays.stream(数组名);
- 同种数据类型的多个数据:Stream.of(数据1,数据2,数据3……);
中间方法-filter
Stream 流的常见中间操作方法
Stream filter (Predicate predicate): 用于对流中的数据进行过滤
- Predicate 接口中的方法
- Boolean test(T t):对给定的参数进行判断,返回一个布尔值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//filter方法获取流中的每一个数据
//而test方法中的s,就依次表示流中的每一个数据。
//我们只要在test方法中对s进行判断就可以了,
//如果判断的结果为true,则当前的数据留下
//如果判断的结果为false,则当前数据就不要。
list.stream().filter(
new Predicate<string>(){
@Override
public boolean test(string s){
boolean result = s.startsWith("张");
return result;
}
}
)
.forEach(s -> System.out.println(s));
list.stream().filter(s -> s.startWith("张")).forEach(s -> System.out.println(s));
|
其他常用中间方法
Stream 流的常见中间操作方法
- Stream limit (long maxSize):截取指定参数个数的数据,例如:输入3,代表截取前三个
- Stream skip (long n):跳过指定参数个数的数据
- static Stream concat(Stream a, Stream b):合并a和b两个流为一个流
- Stream distinct():去除流中重复的元素(依赖hashCode和equals方法)
- public Stream map(Function mapper):把当前Stream流转换为其他类型的Stream流
concat
concat 是静态方法,可以用 类名.concat 来调用
1
2
3
|
Stream<String> stream1 = list.stream();
Stream<String> stream2 = list2.stream();
Stream<String> stream3 = Stream.concat(stream1, stream2);
|
findFirst()
Optional optional = Stream()…….findFirst()
流 findFirst() 返回描述此流的第一个元素的 Optional (一个容器对象,可能包含或可能不包含,非 null 值);如果该流为空,则返回空的 Optional。
1
|
Optional<String> first = list.stream().findFirst();
|
findFirst() 会得到 Optional 类,然后 Optional 类可以调用 isPresent() 方法和 get() 方法
| 方法名 |
描述 |
| isPresent() |
确定此 Optional 实例中是否存在值 |
| get() |
用于获取此 Optional 实例的值 |
isPresent()
Java 中的 java.util.Optional 类的 isPresent() 方法用于确定此 Optional 实例中是否存在值。如果此 Optional 实例中不存在任何值,则此方法返回 false,否则返回 true。
- 用法: public boolean isPresent()
- 参数:此方法不接受任何参数。
- 返回值:此方法返回一个布尔值,该布尔值说明此 Optional 实例中是否存在一个值。
get()
Java 中的 java.util.Optional 类的 get() 方法用于获取此 Optional 实例的值。如果此 Optional 实例中不存在任何值,则此方法将引发 NullPointerException。
- 用法: public T get()
- 参数:此方法不接受任何参数。
- 返回值:此方法返回 Optional 类的实例的值。
- 异常:如果此 Optional 实例中不存在任何值,则此方法将引发 NoSuchElementExcpetion。
Strean流的串行和并行
- 并行流:List.parallelStream()
- 串行流(顺序流):List.stream()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<Integer> ints = Arrays.asList(50, 10, 2, 40, 9, 8);
// 使用顺序流计算列表中所有数字的总和
long sumSequential = ints.stream()
.mapToLong(n -> n)
.sum();
System.out.println("Sum using sequential stream: " + sumSequential);
// 使用并行流计算列表中所有数字的总和
long sumParallel = ints.parallelStream()
.mapToLong(n -> n)
.sum();
System.out.println("Sum using parallel stream: " + sumParallel);
}
}
|
mapToLong:将非长整型的流(如 IntStream/Stream) 中的每个元素,通过指定的映射函数(ToLongFunction)转换为 long 类型,最终返回一个基本类型的 LongStream(而非包装类型的 Stream)。
值得注意的是,不是所有的流操作都可以有效地并行化。有些操作(如 findFirst() 或 anyMatch())在并行流上的性能可能并不比顺序流好,因为它们通常需要在找到结果后立即停止处理。
map、flatMap区别
- map:对流中每一个元素进行处理
- flatMap:流扁平化,让你把一个流中的 “每个值” 都换成另一个流,然后把所有的流连接起来成为一个流
总结:map 是对一级元素进行操作,flatmap 是对二级元素操作。
本质区别:map 返回一个值;fltmap 返回一个流,多个值,
应用场景:map 对集合中每个元素加工,返回加工后结果;flatmap 对集合中每个元素加工后,做扁平化处理后(拆分层级,放到同一层)然后返回
对流中的数据进行排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
//字母排序
List<String> string1 = Arrays.asList("abc", "bc", "bcf", "efg", "abcd", "bca", "jkl", "jkl");
List<String> sorted = string1.stream().sorted().collect(Collectors.toList());
//数字排序
List<Integet> ints = Arrays.asList(50, 10, 2, 40, -9, 8);
List<Integet> collect = ints.stream().sorted().collect(Collectors.toList());
//汉字排序
List<String> strings2 = Arrays.asList("张三", "李四", "王五", "赵柳", "张哥", "李哥", "王哥");
List<String> collect1 = strings2.stream().sorted(Collections.reverseOrder(Collator.getInstance(Locale.CHINA))).collect(Collectors.toList());
//Collections.reverseOrder(Collator.getInstance(Locale.CHINA)) 的意思就是,通过中国地域设置的 Collator 实例来创建一个逆序比较器。这个比较器会按照中国地域设置的规则,对字符串进行逆序比较和排序。
//根据比较器指定的规则排序
List<Teacher> l = new ArrayList<>();
l.add(new Teacher(14,"zs"));
l.add(new Teacher(11,"ww"));
l.add(new Teacher(24,"ls"));
l.add(new Teacher(24,"ks"));
List<Teacher> collect = l.stream().sorted((a, b) -> {
int i = a.getAge() - b.getAge();
i = i == 0 ? a.getName().compareTo(b.getName()) : i;
return i;
}).collect(Collectors.toList());
|
stream中有两个sorted方法:
- Stream sorted():根据元素的自然顺序排序
- Stream sorted(Comparator<? super T> comparator):根据比较器指定的规则排序
Stream流-终结方法
Stream流的常见终结操作方法
- void foreach (Consumer action):对此流的每个元素执行操作
Consumer接口中的方法,void accept(T t):对给定的参数执行此操作
- long count():返回此流中的元素数量
1
2
3
4
5
6
7
8
9
10
11
12
|
//在forEach方法的底层,会循环获取到流中的每一个数据。
//并循环调用accept方法,并把每一个数据传递给accept方法
//s就依次表示了流中的每一个数据
//所以,我们只要在accept方法中,写上处理的业务逻辑就可以了
list.stream().forEach(
new Consumer<String>(){
@Override
public void accept(string s){
System.out.println(s);
}
}
);
|
Stream流-不能直接修改数据源中的数据
Stream流的收集操作
需求:过滤元素并遍历集合
定义一个集合,并添加一些整数 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
将集合中的奇数删除,只保留偶数。
遍历集合得到 2, 4, 6, 8, 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class Mystream6{
public static void main(String[] args){
ArrayList<Integer> list = new ArrayList<>();
for(int i = 1; i <= 10; i++){
list.add(i);
}
list.stream().filter(number -> number%2 == 0).forEach(number -> System.out.println(number));
//---------------------------------------
for(Integer integer : list){
System.out.println(integer);
}
}
}
|
结论:在Stream流中无法直接修改集合、数组等数据源中的数据
收集方法-toList和toSet
Stream流的收集操作
使用Stream流的方式操作完毕之后,我想把流中的数据存起来,该怎么办呢?
Stream流的收集方法
- R collect (Collector collector)
工具类Collectors提供了具体的收集方式
- public static Collector toList(): 把元素收集到 List 集合中
- public static Collector toSet(): 把元素收集到 Set 集合中,会去除重复的元素
- public static Collector toMap(Function keyMapper,Function valueMapper): 把元素收集到 Map 集合中
1
2
3
4
5
6
7
8
9
10
|
public class Test{
public static void main(String[] args){
//filter负责过滤数据
//collect负责收集数据
//获取流中剩余的数据,但是他不负责创建容器,也不负责把数据添加到容器中,
//Collectors.toList():在底层会创建一个List集合。并把所有的数据添加到List集合中
List<Integer> list = list1.stream().filter(number -> number%2 == 0)
.collect(Collectors.toList());
}
}
|
Stream流-练习
现在有两个ArrayList集合,分别存储 6名男演员 和 6名女演员,要求完成如下的操作
- 男演员只要名字为3个字的前两人
- 女演员只要姓杨的,并且不要第一个
- 把过滤后的男演员姓名和女演员姓名合并到一起
- 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历打印对象
演员类Actor,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法
1
2
3
4
5
6
|
Stream<String> stream1 = manList.stream().filter(s -> s.length() == 3).limit(2);
Stream<String> stream2 = womanList.stream().filter(s -> s.startWith("杨")).skip(1);
Stream.concat(stream1, stream2).foreach(s ->
Actor a = new Actor(s);
System.out.println(a);
);
|
File和IO的概述
思考: 以前是如何存储数据的
1
2
3
|
int a = 10;
int [] arr = {1,2,3,4,5};
ArrayList<String> list = new ArrayList<>();
|
通过变量、数组、集合等等方式进行数据存储,这样的方式存储有没有什么弊端呢?
弊端是什么?
不能永久化存储,只要代码运行结束,所有数据都会丢失。
思考:计算机中,有没有一个硬件可以永久化存储?
永久存储: 代码结束了,数据还在,甚至电脑重启之后,我的数据还在
硬盘
我们可以对硬盘进行哪些操作?
对文件进行读写的前提条件?
我们得知道这个文件在哪
IO可以对硬盘中的文件进行读写
File表示要读写的文件在哪,也可以对文件进行创建,删除等操作
小结
IO流是什么?
- 可以将数据从本地文件中读取出来
- 可以将数据从内存保存到本地文件,实现数据的永久化存储
File类是什么?
- 在读写数据时告诉虚拟机要操作的(文件/文件夹)在哪
- 对(文件/文件夹)本身进行操作。包括创建,删除等
File-构造方法
File类概述和构造方法
File: 它是文件和目录路径名的抽象表示
- 文件和目录可以通过File封装成对象
- File封装的对象仅仅是一个路径名,它可以是存在的,也可以是不存在的
| 方法名 |
说明 |
| File(String pathname) |
通过将给定的路径名字符串转换为抽象路径名来创建新的File实例 |
| File(String parent, String child) |
从父路径名字符串和子路径名字符串创建新的File实例 |
| File(File parent, String child) |
从父抽象路径名和子路径名字符串创建新的File实例 |
File(String pathname)
通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
场景: 使用File类中的方法
1
2
|
String path = "C:\\it\\a.txt";
File file = new File(path);
|
问题:为什么要把字符串表示形式的路径变成File对象?
为了使用File类里面的方法
new File("…") 不会创建新文件,它将创建一个包含文件名的新对象(在内存中),然后,您可以对其执行 exists()、canRead() 和 isDirectory() 之类的操作,并目可以调用 createNewFile() 从中创建实际文件
File (String parent, String child)
从父路径名字符串和子路径名字符串创建新的File实例
场景: 路径的拼接
1
2
3
4
|
String path1 = "c:\\it";
String path2 = "a.txt";
File file = new File(path1, path2);//把两个路径拼接。
System.out.println(file); //"C:\it\a.txt"
|
File (File parent, String child)
从父抽象路径名和子路径名字符串创建新的File实例
场景: 路径的拼接
1
2
3
4
|
File file1 = new File("C:\\it");
String path = "a.txt";
File file = new File(file1, path);
System.out.println(file); //"C:\it\a.txt"
|
File-绝对路径和相对路径
绝对路径和相对路径
绝对路径:永远不发生变化的路径,绝对路径一般是由盘符作为开始
1
|
File file1 = new File("C:\\it\\a.txt");
|
相对路径:相对当前项目下的路径 (根据参照物对比出来的路径,相对路径不是以盘符作为开始)
1
2
|
File file2 = new File("a.txt");
File file3 = new File("模块名\\a.txt");
|
1
2
3
4
5
6
7
8
9
10
11
12
|
public class FileDemo2{
public static void main(String[] args){
//这个路径固定不变了
File file = new File("D:\\it\\a.txt");
//当前项目下的 a.txt
File file2 = new File("a.txt");
//当前项目下---指定模块下的 a.txt
File file3 = new File("filemodule\\a.txt");
}
}
|
注意事项:
- Java项目中的相对路径参照物都是 “当前项目”
- Java项目任何书写路径的地方,都可以书写"绝对路径",也可以书写"相对路径".
- 相对路径和绝对路径的概念,仅限于当前Java项目 (在JavaWeb阶段,参照物会发生变化)
File-创建功能
file对象可以表示一个文件,也可以表示一个文件夹,表示的路径可以存在,也可以不存在,如果不存在,可以把它给创建出来
File类创建功能
| 方法名 |
说明 |
| public boolean createNewFile() |
创建一个新的空的文件 |
| public boolean mkdir() |
创建一个单级文件夹 |
| public boolean mkdirs() |
创建一个多级文件夹 |
以下三个方法均是由file对象调用的
- public boolean createNewFile(): 创建一个新的空的文件
注意点:
- 如果文件存在,那么创建失败,返回false
- 如果文件不存在,那么创建成功,返回true
- createNewFile 方法不管调用者有没有后缀名,只能创建文件,不会创建文件夹,如果没有后缀名,就创建一个没有后缀名的文件
- public boolean mkdir(): 创建一个单级文件夹
注意点:
- 只能创建单级文件夹,不能创建多级文件夹
- 不管调用者有没有后缀名,只能创建单级文件夹
- public boolean mkdirs():创建一个多级文件夹
注意点:
- 可以创建单级文件夹,也可以创建多级文件夹
- 不管调用者有没有后缀名,只能创建文件夹
既然mkdirs能创建单级,也能创建多级。那么mkdir就没什么用了
我们看mkdirs()的源码 ,发现它里面也会调用makedir(),他会先用makedir()试试,看是不是的单极文件夹,如果创建成功,就返回了,创建不成功才会创建多级文件夹
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public boolean mkdirs() {
if (exists()) {
return false;
}
if (mkdir()) {
return true;
}
File canonFile = null;
try {
canonFile = getCanonicalFile();
} catch (IOException e) {
return false;
}
}
|
File-删除方法
File类删除功能
| 方法名 |
说明 |
| public boolean delete() |
删除由此抽象路径名表示的文件或目录 |
以下方法均是由file对象调用的
public boolean delete() //删除当前路径代表的文件或文件夹
注意点:
- 不走回收站的。
- 如果删除的是文件,那么直接删除,如果删除的是文件夹,那么能删除空文件夹
- 如果要删除一个有内容的文件夹,只能先进入到这个文件夹,把里面的内容全部删除完毕,才能再次删除这个文件夹
简单来说:只能删除文件和空文件夹
public void deleteOnExit() //请求在虚拟机终止时删除由此抽象路径名表示的文件或目录。
程序执行完才删除
当虚拟机终止时,删除此文件或文件夹
File-获取和判断方法
File类判断和获取功能
| 方法名 |
说明 |
| public boolean isDirectory() |
测试此抽象路径名表示的File是否为目录 |
| public boolean isFile() |
测试此抽象路径名表示的File是否为文件 |
| public boolean exists() |
测试此抽象路径名表示的File是否存在 |
| public String getName() |
返回由此抽象路径名表示的文件或目录的名称 |
| public string getAbsolutePath() |
获取绝对路径 |
| public string getParent() |
获取父级路径 |
| public file getParentFile() |
获取父级路径的file对象(也就是用父级路径创建的file对象) |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public static void method1(){
File file = new File("C:\\it\\a.txt");
boolean result1 = file.isFile();
boolean result2 = file.isDirectory();
System.out.println(result1); //true
System.out.println(result2); //false
}
public static void method2(){
File file = new File("C:\\it");
boolean result1 = file.isFile();
boolean result2 = file.isDirectory();
System.out.println(result1); //false
System.out.println(result2); //true
}
|
public String getName(): 返回由此抽象路径名表示的文件或目录的名称
注意点:
- 如果调用者是文件,那么获取的是文件名和后缀名
- 如果调用者是一个文件夹,那么获取的是文件夹的名字
File-listFile
File类高级获取功能
| 方法名 |
说明 |
| public File[] listFiles() |
返回此抽象路径名表示的目录中的文件和目录的File对象数组 |
| public static File[] listRoots() |
获取硬盘上的所有盘符 |
public File[] listFiles(): 返回此抽象路径名表示的目录中的文件和目录的File对象数组
- 进入文件夹,获取这个文件夹里面所有的文件和文件夹的File对象,并把这些File对象都放在一个数组中返回
- 包括隐藏文件和隐藏文件夹都可以获取
注意事项:
(1) 当调用者不存在时?
返回null
(2) 当调用者是一个文件时?
返回值为 null,listFiles() 有一个进入文件夹的动作,文件是不能进入的,文件只能打开写里面的内容,所以如果调用者是文件时,调用 list Files() 会返回一个 null
(3) 当调用者是一个空文件夹时?
返回一个长度为 0 的数组
(4) 当调用者是一个有内容的文件夹时?
进入文件夹,获取这个文件夹里所有的文件和文件夹的 File 对象,并把这些 File 对象都放在一个数组中返回
(5) 当调用者是一个有隐藏文件的文件夹时?
将里面所有文件和文件夹的路径放在Fil数组中返回,包含隐藏内容
(6) 当调用者是一个有权限才能进入的文件夹时 ?
java 是不允许进去的,返回值为 null
File-练习一
练习一: 在当前模块下的aaa文件夹中创建一个a.txt文件
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public static void main(String[] args){
File file = new File("filemodule\\aaa\\a.txt");
file.createNewFile(); //报错,原因:aaa文件夹不存在
//注意点:文件所在的文件夹必须要存在
File file1 = new File("filemodule\\aaa");
if(!file1.exists()){
//如果文件夹不存在,就创建出来
file1.mkdirs();
}
File newFile = new File(file1, "a.txt"); //将 "filemodule\\aaa" 和 "a.txt" 拼接起来
newFile.createNewFile();
}
|
File-练习二
练习二: 删除一个多级文件夹
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
private static void deleteDir(File src){
//先删掉这个文件夹里面所有的内容,
//递归:方法在方法体中自己调用自己。
//注意:可以解决所有文件夹和递归相结合的题目
//1.进入---得到src文件夹里面所有内容的File对象。
File[] files = src.listFiles();
//2.遍历---因为我想得到src文件夹里面每一个文件和文件夹的File对象
for(File file : files){
if(file.isFile()){
//3.判断---如果遍历到的File对象是一个文件,那么直接删除
file.delete();
}else{
//4.判断
//递归
deleteDir(file); //参数一定要是src文件夹里面的文件夹File对象
}
}
//最后再删除这个文件夹
src.delete();
}
|
File-练习三
练习三: 统计一个文件夹中每种文件的个数并打印。
打印格式如下:
1
2
3
4
|
txt: 3个
doc: 4个
jpg: 6个
……
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
public static void main(String[] args){
//统计一个文件夹中,每种文件出现的次数。
//统计---定义一个变量用来统计。---弊端:同时只能统计一种文件
//利用map集合进行数据统计,键---文件后缀名 值----次数
File file = new File("filemodule"); //相对路径,当前模块
HashMap<String, Integer> hm = new HashMap<>();
getcount(hm, file);
System.out.println(hm);
}
private static void getCount(HashMap<String, Integer> hm,File file){
File[] files = file.listFiles();
for(File f : files){
if(f.isFile()){
String fileName = f.getName();
String[] fileNameArr = fileName.split("\\."); //只统计常规的,例如:aaa.txt,不考虑a.b.txt这样的
if(fileNameArr.length == 2){
String fileEndName = fileNameArr[1];
if(hm.containskey(fileEndName)){ //判断集合中是否存在这个键
//已经存在
//将已经出现的次数获取出来
Integer count = hm.get(fileEndName);
//这种文件又出现了一次
count++;
//把己经出现的次数给覆盖掉
hm.put(fileEndName,count);
}else{
//不存在
//表示当前文件是第一次出现
hm.put(fileEndName, 1);
}
}
}else{
getCount(hm, f);
}
}
}
|
File.createNewFile | File.createTempFile
1
2
3
4
5
6
|
/**
* fileName: 临时文件的名字, 生成后的文件名字将会是【fileName + 随机数】
* suffix: 文件后缀,例如.txt, .tmp
* parentFile: 临时文件目录,如果不指定,则默认把临时文件存储于系统临时文件目录上
*/
public static File createTempFile(String fileName, String suffix, File parentFile)
|
File.createNewFile
createNewFile();返回值为 boolean;
1
2
3
|
File file = new File("D:\\test\\1.txt");
boolean res = file.createNewFile();
if(!res)System.out.println("创建失败!");
|
如果 D:/test 目录下没有 1.txt 文件,则创建该文件;
如果没有 test 目录,直接抛出异常;
如果 1.txt 已经存在,那么文件创建失败。
可以得知,createNewFile() 方法,根据抽象路径创建一个新的空文件,当抽象路径指定的文件存在时,创建失败。
File.createTempFile
File.createTempFile(String prefix, String suffix);
根据指定的前缀和后缀在默认的文件夹里创建文件
方法默认的保存路径为:C:\Documents and Settings\Administrator\Local Settings\Temp
File.createTempFile(String prefix, String suffix, File directory);
在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。
createTempFile() 方法,在指定的目录下创建一个 temp 文件,directory 类型为 File ,如果路径不存在,则创建失败。
删除方法
1
2
3
4
5
|
//立即删除文件
file.delete();
//在JVM退出时删除文件
file.deleteOnExit();
|
总结:临时文件能够使用默认路径,可以避免存在创建文件是因为路径错误导致创建文件失败的问题。
如果需求中需要创建一个临时文件,这个临时文件可能作为存储使用,但在程序运行结束后需要删除文件,可以使用 deleteOnExit 方法