1.Stream流
1.1 体验Stream流
需求:按照下面的要求完成集合的创建和遍历
创建一个集合,存储多个字符串元素
把集合中所有以"杨"开头的元素存储到一个新的集合
把"杨"开头的集合中的长度为3的元素存储到一个新的集合
遍历上一步得到的集合
public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();ArrayList<String> newList = new ArrayList<>();ArrayList<String> newList2 = new ArrayList<>();list.add("杨金辉");list.add("杨大");list.add("杨老二");list.add("小杨哥");list.add("赵信");for (String s : list) {if (s.startsWith("杨")){newList.add(s);}}System.out.println(newList);for (String s : newList) {if (s.length()==3){newList2.add(s);}}System.out.println(newList2);}
1.2 为什么要用Stream流
简化集合操作的
1.3 Stream流思想
1.4 Stream流的三类方法
我们可以把stream流看做是一条流水线。
Stream流的使用,它有这样的一些操作,首先来说是生成流,你要使用Stream流,你得有一个Stream流
forEach指的是为每一个元素执行操作
获取Stream流
创建一条流水线,并把数据放到流水线上准备进行操作
中间方法
流水线上的操作。
一次操作完毕之后,还可以继续进行其他操作。
终结方法
一个Stream流只能有一个终结方法
是流水线上的最后一个操作
1.5 Stream流的获取方法
单列集合
可以使用Collection接口中的默认方法stream()生成流
default Stream stream()
双列集合
间接的生成流
可以先通过keySet或者entrySet获取一个Set集合,再获取Stream流
数组
数组:Arrays.stream(数组) / Stream.of(数组);
同种数据类型的多个数据
1,2,3,4,5….
“aaa”,“bbb”,“ccc”….
使用Stream.of(T…values)生成流
代码:
ArrayList<Integer> list = new ArrayList<>();
Stream<Integer> stream = list.stream();Map<String,Integer> map = new HashMap<>();
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Stream<Map.Entry<String, Integer>> stream1 = entries.stream();Integer[]arr={1,2,3,4,5};
Stream<Integer> stream2 = Arrays.stream(arr);
Stream<Integer> arr1 = Stream.of(arr);Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
Stream<String> aaa = Stream.of("aaa", "bbb", "ccc");
1.6 Stream流的常见中间操作方法
Stream filter(Predicate predicate):用于对流中的数据进行过滤
Predicate接口中的方法
boolean test(T t):对给定的参数进行判断,返回一个布尔值
Stream limit(long maxSize):截取指定参数个数的数据 取集合中的前几个
Stream skip(long n):跳过指定参数个数的数据 跳过集合中的前几个
static Stream concat(Stream a, Stream b):合并a和b两个流为一个流
Stream distinct():去除流中重复的元素。依赖(hashCode和equals方法)
map(Function(<? Super T>,<? Extends R> mapper)):数据类型转化
1.7 Stream流的常见终结操作方法
void forEach(Consumer action):对此流的每个元素执行操作
Consumer接口中的方法 void accept(T t):对给定的参数执行此操作
long count():返回此流中的元素数
我们可以理解stream流的操作为:未加工的产品 -------加工--------加工后的产品
public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("马大哈");list.add("马守信");list.add("赵强");list.add("马强");list.add("马飞");list.add("张三民");list.add("张三民");// 未加工的产品 -------加工--------加工后的产品//统计加工之后的产品list.stream().forEach(s -> System.out.println(s));//统计加工之后的产品个数long count1 = list.stream().count();System.out.println("加工后的产品个数为:" + count1);//找所有姓马的
list.stream().filter(s -> s.startsWith("马")).forEach(s -> System.out.println(s));//统计名字为3个字的个数long count = list.stream().filter(s -> s.length() == 3).count();System.out.println(count);//取集合中前两个姓马的
list.stream().filter(s -> s.startsWith("马")).limit(2).forEach(System.out::println);//跳过集合中前两个姓马的
list.stream().filter(s -> s.startsWith("马")).skip(2).forEach(System.out::println);//map加工方法: 第一个参数原材料 -> 第二个参数是加工后的结果。//对集合中每个元素都加入前缀list.stream().map(new Function<String, String>() {@Overridepublic String apply(String s) {return "高合的" + s;}}).forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});//简化list.stream().map(s -> "高合的" + s).forEach(s -> System.out.println(s));//需求 把所有的名称都加到一个学生类中list.stream().map(new Function<String, Student>() {@Overridepublic Student apply(String s) {return new Student(s);}}).forEach(new Consumer<Student>() {@Overridepublic void accept(Student student) {System.out.println(student);}});//简化后list.stream().map(s -> new Student(s)).forEach(s -> System.out.println(s));
// list.stream().map(Student::new).forEach(System.out::println); // 构造器引用 方法引用// 合并流。Stream<String> s1 = list.stream().filter(s -> s.startsWith("张"));Stream<String> s2 = Stream.of("java1", "java2");// public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)Stream<String> s3 = Stream.concat(s1 , s2);s3.distinct().forEach(s -> System.out.println(s));}
Student
public class Student {private String name;有参/无参/get/set/tostring
}
补充
这里的System.out::println确实是实现Consumer<T>接口的匿名函数,而且这里用的是Lambda表达式中的方法引用语法。方法引用实际上是将一个Lambda表达式的实现指向一个已经实现了的方法,语法为——方法的隶属者::方法名。
对于System.out::println来说,System.out就是方法的隶属者,println就是已实现的方法。我们依然找到它的源码。
1.8 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集合中
代码展示:
List<String> list = new ArrayList<>();
list.add("马大哈");
list.add("马守信");
list.add("马守信");
list.add("赵强");
list.add("马强");
list.add("马飞");
list.add("张三民");
list.add("张三民");// List<String> collect = list.stream().filter(new Predicate<String>() {
// @Override
// public boolean test(String s) {
// return s.length() == 3;
// }
// }).collect(Collectors.toList());List<String> collect = list.stream().filter(s -> s.length() == 3).collect(Collectors.toList());System.out.println(collect);// Set<String> collect1 = list.stream().filter(new Predicate<String>() {
// @Override
// public boolean test(String s) {
// return s.length() == 3;
// }
// }).collect(Collectors.toSet());Set<String> collect1 = list.stream().filter(s -> s.length() == 3).collect(Collectors.toSet());System.out.println(collect1);// Map<Student, Integer> collect2 = list.stream().filter(new Predicate<String>() {
// @Override
// public boolean test(String s) {
// return s.length() == 3;
// }
// }).collect(Collectors.toMap(new Function<String, Student>() {
// @Override
// public Student apply(String s) {
// return new Student(s);
// }
// }, new Function<String, Integer>() {
// @Override
// public Integer apply(String s) {
// return 1;
// }
// }));
// Map<Student, Integer> collect2 = list.stream().filter(s -> s.length() == 3).collect(Collectors.toMap(s -> new Student(s), s -> 1));Map<Student, Integer> collect2 = list.stream().filter(s -> s.length() == 3).collect(Collectors.toMap(Student::new, s -> 1));System.out.println(collect2);//转为数组类型Stream<String> stream = list.stream().filter(s -> s.startsWith("马"));String[] strings = stream.toArray(String[]::new);// 可以不管,拓展一下思维!!System.out.println(Arrays.toString(strings));
1.9 总结
1.Stream流的作用
结合了Lambda表达式,简化集合、数组的操作
2.stream的使用步骤
a.获取Stream流对象
b.使用中间方法处理数据
c. 使用终结方法处理数据
3.如何获取Stream流对象
a.单列集合: Collection中的默认方法stream
b.双列集合:不能直接获取
c. 数组: Arrays工具类型中的静态方法stream
d.一堆零散的数据: stream接口中的静态方法of
4.常见方法
中间方法:filter, limit, skip, distinct, concat, map
终结方法:forEach, count, collect
1.10.1 Stream流的练习1
1.10.1 过滤元素并遍历集合
需求:过滤元素并遍历集合
定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
将集合中的奇数删除,只保留偶数。
遍历得到的集合输出2,4,6,8,10
//1.定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
list.add(8);
list.add(9);
list.add(10);
//将集合中的奇数删除,只保留偶数。遍历得到的集合输出2,4,6,8,10
list.stream().filter(integer -> integer % 2 == 0).forEach(System.out::println);
结论:在Stream流中无法直接修改集合,数组等数据源中的数据。
1.10.2 Stream流的练习2
练习:
创建一个ArrayList集合,并添加以下字符串。字符串中前面是姓名,后面是年龄
“zhangsan,23”
“lisi,24”
“ wangwu,25”
保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
public static Collector toMap(Function keyMapper , Function valueMapper):把元素收集到Map集合中
public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("zhangsan,23");list.add("lisi,24");list.add("wangwu,25");// Map<String, Integer> collect = list.stream().filter(s -> {
// String[] split = s.split(",");
// return Integer.parseInt(split[1]) >= 24;
// }).collect(Collectors.toMap(new Function<String, String>() {
// @Override
// public String apply(String s) {
// return s.split(",")[0];
// }
// }, new Function<String, Integer>() {
// @Override
// public Integer apply(String s) {
// return Integer.parseInt(s.split(",")[1]);
// }
// }));Map<String, Integer> collect = list.stream().filter(s -> Integer.parseInt(s.split(",")[1]) >= 24).collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1])));System.out.println(collect);}
1.10.3 Stream流的练习3
现在有两个ArrayList集合,分别存储6名男演员和6名女演员,要求完成如下的操作
男演员只要名字为3个字的前两人
女演员只要姓杨的,并且不要第一个姓杨的
把过滤后的男演员姓名和女演员姓名合并到一起
把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
演员类Actor,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法
public static void main(String[] args) {ArrayList<Actor> man = new ArrayList<>();man.add(new Actor("杨树林"));man.add(new Actor("文松"));man.add(new Actor("宋小宝"));man.add(new Actor("赵本山"));man.add(new Actor("小沈阳"));man.add(new Actor("王金龙"));ArrayList<Actor> woman = new ArrayList<>();woman.add(new Actor("欧阳娜娜"));woman.add(new Actor("热依扎"));woman.add(new Actor("古力娜扎"));woman.add(new Actor("杨颖"));woman.add(new Actor("杨千嬅"));woman.add(new Actor("杨丽"));//男演员只要名字为3个字的前两人Stream<Actor> manStream = man.stream().filter(actor -> actor.getName().length() == 3).limit(2);//女演员只要姓杨的,并且不要第一个姓杨的Stream<Actor> womanStream = woman.stream().filter(actor -> actor.getName().startsWith("杨")).skip(1);//把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据Stream.concat(manStream,womanStream).forEach(System.out::println);}
2.File
思考:以前是如何存储数据的?
int a = 10;
int [] arr = {1,2,3,4,5};
ArrayList<String> list = new ArrayList<>();
弊端是什么?
不能永久化存储,只要代码运行结束,所有数据都会丢失。
思考:计算机中,有没有一个硬件可以永久化存储?
我们可以对硬盘进行哪些操作?
对文件进行读写的前提条件?
1.我们得知道这个文件在哪
IO就可以对硬盘中的文件进行读写File表示要读写的文件在哪,也可以对文件进行创建,删除等操作
总结
1.IO流是什么?
a.可以将数据从本地文件中读取出来
b.可以将数据从内存保存到本地文件
2.File类是什么?
a.在读写数据时告诉虚拟机要操作的(文件/文件夹)在哪
b.对(文件/文件夹)本身进行操作。包括创建,删除等。
2.1 File类概述和构造方法
File:它是文件和目录路径名的抽象表示
文件和目录可以通过File封装成对象
File封装的对象仅仅是一个路径名。它可以是存在的,也可以是不存在的。
方法名 | 说明 |
---|---|
File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例 |
File(String parent, String child) | 从父路径名字符串和子路径名字符串创建新的 File实例 |
File(File parent, String child) | 从父抽象路径名和子路径名字符串创建新的 File实例 |
路径写法: / \\ File.separator
代码:
File file1 = new File("E:/file/ikun2.jpeg");
File file2 = new File("E:\\file\\ikun2.jpeg");
File file3 = new File("E:" + File.separator + "file" + File.separator + "ikun2.jpeg");
System.out.println(file1.length());
System.out.println(file2.length());
System.out.println(file3.length());
System.out.println("------------");
File file4 = new File("E:/file/","ikun2.jpeg");
System.out.println(file4.length());
File file5 = new File(new File("E:/file/"),"ikun2.jpeg");
System.out.println(file5.length());
2.2 绝对路径和相对路径
绝对路径:从盘符开始
File file1 = new File(“D:\\itgaohe\\a.txt”);
相对路径:相对当前项目下的路径
1.从项目中找到目标文件右键 copy path—> path from content root
2.如果是分模块创建 则加上模块名!!!!
File file2 = new File(“a.txt”);
//如果是分模块创建 则加上模块名!!!!
File file3 = new File(“模块名\\a.txt”);
2.3 File类创建功能
方法名 | 说明 |
---|---|
public boolean createNewFile() | 创建一个新的空的文件 |
public boolean mkdir() | 创建一个单级文件夹 |
public boolean mkdirs() | 创建一个多级文件夹 |
File f3 = new File("E:\\abc\\aa\\aaa");
// System.out.println(f3.createNewFile());
// System.out.println(f3.mkdir());
// System.out.println(f3.mkdirs());
2.4 File类删除功能
方法名 | 说明 |
---|---|
public boolean delete() | 删除由此抽象路径名表示的文件或目录 |
删除目录时的注意事项:
delete方法直接删除不走回收站。
如果删除的是一个文件,直接删除。
如果删除的是一个文件夹,需要先删除文件夹中的内容,最后才能删除文件夹。
2.5 File类判断和获取功能
方法名 | 说明 |
---|---|
public boolean isDirectory() | 测试此抽象路径名表示的File是否为目录 |
public boolean isFile() | 测试此抽象路径名表示的File是否为文件 |
public boolean exists() | 测试此抽象路径名表示的File是否存在 |
public String getAbsolutePath() | 返回此抽象路径名的绝对路径名字符串 |
public String getPath() | 将此抽象路径名转换为路径名字符串 |
public String getName() | 返回由此抽象路径名表示的文件或目录的名称 |
// 1.绝对路径创建一个文件对象
File f1 = new File("D:/resources/xueshan.jpeg");
// a.获取它的绝对路径。
System.out.println(f1.getAbsolutePath());
// b.获取文件定义的时候使用的路径。
System.out.println(f1.getPath());
// c.获取文件的名称:带后缀。
System.out.println(f1.getName());
// d.获取文件的大小:字节个数。
System.out.println(f1.length()); // 字节大小
// e.获取文件的最后修改时间
long time = f1.lastModified();
System.out.println("最后修改时间:" + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(time));
// f、判断文件是文件还是文件夹
System.out.println(f1.isFile()); // true
System.out.println(f1.isDirectory()); // false//相对路径创建一个
//File f3 = new File("src/com/itgaohe/123.txt");
2.6 File类高级获取功能
方法名 | 说明 |
---|---|
public File[] listFiles() | 获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(重点) |
listFiles方法注意事项:
当调用者不存在时,返回null
当调用者是一个文件时,返回null
当调用者是一个空文件夹时,返回一个长度为0的数组
当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内容
当调用者是一个需要权限才能进入的文件夹时,返回null
File file = new File("E:\\abc");File[] files = file.listFiles();//获取一级文件目录for (File file1 : files) {System.out.println(file1);}
2.7 练习:
练习一:在当前模块下的images文件夹中创建一个a.txt文件
练习二:删除一个文件
练习三:在当前模块下的images文件夹中创建一个aaa文件夹
练习四:删除一个文件夹
File file = new File("E:\\IdeaProject\\GHA2340\\java_makeup01\\file01\\image\\a.txt");
System.out.println(file.length());
System.out.println(file.delete());File file1 = new File("E:\\IdeaProject\\GHA2340\\java_makeup01\\file01\\image\\aaa");
System.out.println(file1.delete());
2.8 案例:File的练习
练习1:在当前模块下的aaa文件中创建一个a.txt文件
File file = new File("E:\\IdeaProject\\GHA2340\\java_makeup01\\file01\\image\\aaa\\a.txt");
file.createNewFile();
练习2:删除一个多级文件夹
public static void main(String[] args) {deleteDir(new File("E:\\abc"));
}public static void deleteDir(File dir) {//1.判断dir是否存在 并且还是个文件夹if (dir.isDirectory() && dir != null && dir.exists()) {//dir != null 说明有内容 不能直接删除!//2.提取一级文件对象File[] files = dir.listFiles();//3.判断一级文件对象是否存在 如果存在则遍历全部的一级文件对象并且删除if (files != null && files.length > 0) {//文件夹中有内容//4.遍历 判断file是文件还是文件夹for (File file : files) {if (file.isFile()) {//5.如果是文件 则直接删除file.delete();} else {//6.不是文件 还是文件夹deleteDir(file);}}}//删除dir.delete();}
}
练习3:统计一个文件夹中每种文件的个数并且打印
打印格式如下:
txt: 3个
doc:4个
jpg: 6个
public static void main(String[] args) {int txt = 0;int doc = 0;int jpg = 0;//1.定位文件夹File file = new File("E:/abc");String[] list = file.list();for (String s : list) {System.out.println(s);if (s.endsWith("txt")){txt++;}else if (s.endsWith("doc")){doc++;}else if (s.endsWith("jpg")){jpg++;}}System.out.println("txt:" + txt + "个");System.out.println("doc:" + doc + "个");System.out.println("jpg:" + jpg + "个");
}
习3:统计一个文件夹中每种文件的个数并且打印
打印格式如下:
txt: 3个
doc:4个
jpg: 6个
public static void main(String[] args) {int txt = 0;int doc = 0;int jpg = 0;//1.定位文件夹File file = new File("E:/abc");String[] list = file.list();for (String s : list) {System.out.println(s);if (s.endsWith("txt")){txt++;}else if (s.endsWith("doc")){doc++;}else if (s.endsWith("jpg")){jpg++;}}System.out.println("txt:" + txt + "个");System.out.println("doc:" + doc + "个");System.out.println("jpg:" + jpg + "个");
}