Stream流
体验stream流的作用
需求:按照下面的要求完成集合的创建和遍历
创建一个集合,存储多个字符串元素
package a01mystream;
import java.util.ArrayList;
public class streamdemo1 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("张无忌");
list1.add("周芷若");
list1.add("赵敏");
list1.add("胡强");
list1.add("张强");
list1.add("张三丰");
//把所有以"张开头的元素存储到集合中
ArrayList<String> list2 = new ArrayList<>();
for (String name :list1){
if (name.startsWith("张")){
list2.add(name);
}
}
//把张开头的,长度为3的再存储到新集合中
ArrayList<String> list3 = new ArrayList<>();
for (String name : list2){
if (name.length()==3);
list3.add(name);
}
//遍历打印最终结果
for (String name : list3){
System.out.println(name);
}
}
}
Stream流写法
list1.stream().filter(name->name.startWith("张")).filter(name -> name.length == 3).forEach(name -> System.out.println(name))
Stream流的作用
集合lambda表达式,简化集合,数组的操作
Stream流的使用步骤
1.先得到一条Stream流(流水线),并把数据放上去
//1.单列集合
default Stream<E>stream()//Collicatin中的默认方法
//2.双列集合
无
//无法直接使用stream流
//3.数组
public staic<T>Stream<T>stream(T[] arry)
//Arrays工具中的静态方法
//4.一堆零散数据
public staic<T>Stream<T>of(T...values)
//stream接口中的静态方法
细节:
Stream接口中静态方法of细节
2.利用Stream流中的API进行各种方法操作
3.使用终结方法对流水线数据进行操作
Stream流的中间方法
Stream<T>filter(Predicate<?super T>predicate)
//过滤
Stream<T>limit(long maxSize)
//获取前几个元素
Stream<T>skip(long n)
//跳过前几个元素
Stream<T>distinct()
//元素去重,依赖(hashCode和equals方法)
Static<>Stream<T>concat(Stream a,Stream b)
//合并a和b两个流为一个流
Stream<R>map(Funcation<T , R> mapper)
//转换流中的数据类型
注意1:中间方法,返回新的stream流,原来的stream流只使用一次,建议使用链式编程
注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据
Stream流的终结方法
void forEach(Consumer action)
//遍历
long count()
//统计
toArry()
//收集流中的数据放到数组中
collect(Collector collector)
//收集流中的数据,放到集合中
收集方法collect
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌-男-15","周芷若=女-16","赵敏-女-13","张强-男-20","张三丰-男-60","谢广坤-男-18");
//收集到list集合当中
//需求:
//把所有男性收集起来
list.stream().filter(s ->"男".equals(s.split("-")[1])).collect(Collectors.toList()).forEach(s -> System.out.println(s));
//收集到Set集合当中
//需求:
//把所有男性收集起来
Set<String> newlist2 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toSet());
System.out.println(newlist2);
//收集到Map集合当中
//需求:
//把所有男生收集起来
Map<String, Integer> map2 = list.stream().filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toMap(
s -> s.split("-")[0],
s -> Integer.parseInt(s.split("-")[2])
));
System.out.println(map2);
}
}
总结:
1.Stream流的作用
结合了lambda表达式,简化集合,数组的操作
2.Stream的谁用步骤
- 获取Stream流对象
- 使用中间方法处理数据
- 使用终结方法处理数据
3.如何获取Stream流对象
- 单列集合;Collection中的默认方法stream
- 双列集合:不能直接获取
- 数组:Arrays工具类型中的静态方法stream
- 一堆零散数据:Stream接口中的静态方法of
4.常见方法;
- 中间方法:filter,limit,skip,distinct,concat,map
- 终结方法:foeEach,count,collect
练习:
package Streamdemo;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Streamtest2 {
/*练习
* 创建一个ArrayList集合,并添加以下字符,字符串前面是姓名,后面是年龄
* "zhangsan,23
* "lisi-24
* "wangwu,25
* 保留年龄大于24岁的人,并将结果收集到MAp集合,姓名为键,年龄为值*/
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("zhangsan,23");
list.add("lisi,24");
list.add("wqangwu,25");
Map<String, Integer> map = 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(map);
}
}
方法引用
把已经有的方法拿过来用,当做函数接口中抽象方法的方法体.
1.引用处必须是函数式接口,引用方法必须已经存在
2.被引用方法的形参和返回值需要跟抽象方法保持一致.
3.被引用的方法的功能要能满足当前需求
package functiondemo;
import java.util.Arrays;
public class functiondemo1 {
public static void main(String[] args) {
//方法引用
Integer[] arr = {3,5,6,7,8,9};
Arrays.sort(arr,functiondemo1::subtraction);
System.out.println(Arrays.toString(arr));
}
//已存在方法
public static int subtraction(int num1,int num2){
return num2-num1;
}
}
方法引用的分类
1. 引用静态方法
2. 引用成员方法
格式
其他类:其他类对象::方法明
本类: this::方法名
父类:super::方法名
3. 引用构造方法
格式:类名::new
范例:Student::new
4.其他调用方法
使用类名引用成员方法
格式:类名::成员方法
范例:String::substring
引用数组的构造方法
格式:数据类型::new
范例:int[]::new数组类型需要跟流中数据类型保持一致
练习:
package functiondemo;
import java.util.ArrayList;
import java.util.Collections;
public class functiontest {
/*练习1:集合中存储一些字符串数据,比如:张三,23.
* 收集到Student类型的数组中(使用方法引用完成)*/
public static void main(String[] args) {
//1.创建集合并添加元素
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌-23","菠萝吹雪-23","孙火旺-18","小美-21","小帅-23","牛爷爷-100");
//2.先把字符串变成student对象,然后再把student对象收集起来
Student[] arr = list.stream().map(Student::new).toArray(Student[]::new);
System.out.println(arr);
}
}
package functiondemo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Function;
public class functiontest2 {
/*创建集合添加学生对象,学生对象属性:name,age
* 只获取姓名并放到数组当中(使用方法引用完成)*/
public static void main(String[] args) {
ArrayList<Student> list =new ArrayList<>();
list.add(new Student("zhangsan",23));
list.add(new Student("lisi",24));
list.add(new Student("wamgwu",25));
//获取姓名并放到数组当中
String[] arr = list.stream().map(Student::getName).toArray(String[]::new);
System.out.println(arr);
/*String[] arr =list.stream().map(new Function<Student, String>() {
@Override
public String apply(Student student) {
return student.getName();
}
}).toArray(String::new);
System.out.println(Arrays.toString(arr));*/
}
}
异常
异常代表程序出现的问题
异常体系的最上层父类,异常分几类
父类:Exception
异常分为两类:编译时异常,运行时异常
区别
编译时异常:没有继承RuntimeException的异常,直接继承与Exception.编译阶段会显示错误提示
运行时异常:RuntimeException本身和子类.编译阶段没有错误提示,运行时直接出现.
异常的作用
作用一:异常是用来查询bug的关键参考信息
作用二:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的
执行情况
异常处理方式
1.JVM的处理方式
把异常的名称,异常原因及异常出现位置等信息输出在控制台
2.自己处理
灵魂四问
第一问:如果try没有遇到问题该会怎么执行?
会把try里面所有的代码全部执行完毕,不会执行catch里面的代码
第二问:如果try中可能会遇到多个问题,怎么执行?
会写多个catch与之对应,父类异常需要写在下面
第三问:如果try中遇到的问题没有被捕获,怎么执行?
相当于try…catch白写了,当前异常会交给虚拟机处理
如果try中遇到了问题,那么try下面其他代码会执行吗?
不会执行.try中遇到问题,直接跳转到对应的catch,如果没有对应的catch与之对应,则交给虚拟机处理.
3.抛出异常
异常中常见的方法
Throwable的成员方法
public String getMessage()
//返回此throwable的详细消息字符串
public String toString()
//返回此可抛出的简短描述
public void printStackTrace()
//把异常的错误输出在控制台
package Exceptiondemo;
public class Exceptiondemo1 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
String message = e.getMessage();
System.out.println(message);
}
System.out.println("看看我执行了吗");
}
}
package Exceptiondemo;
public class Exceptiondemo1 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
String str = e.toString();
System.out.println(str);
}
System.out.println("看看我执行了吗");
}
}
package Exceptiondemo;
public class Exceptiondemo1 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
System.out.println("看看我执行了吗");
}
}
抛出处理
throws:
写在方法定义处,表示声明一个异常告诉调用者,使用本方法可能有哪些异常
public void 方法()throws 异常类名1,异常类名2...{
}
//编译时异常:必须要写
//运行时异常:可以不写
throw:
写在方法内,结束方法手动抛出异常对象,交给调用者方法中下面的代码不再执行
public void 方法(){
throw new NullPolinterException();
}
练习
package Exceptiondemo;
import java.util.Scanner;
public class Exceptiontest {
/*需求:
* 键盘录入自己心仪的女朋友姓名和年龄.
* 姓名长度在3-10之间,
* 年龄的范围为18-40岁
* 超出这个范围的异常数据不能赋值,需要重新录入,一直录到正确为止
* 提示:
* 需要考虑用户在键盘录入时的所有情况.
* 比如:录入年龄时超出范围,录入年龄时录入了abc等情况*/
public static void main(String[] args) {
//1.创建键盘录入的对象
Scanner sc = new Scanner(System.in);
//2.创建女朋友对象
Girlfriend gf = new Girlfriend();
while (true) {
try {
//3.接收女朋友的姓名
System.out.println("请输入你心仪女朋友的名字");
String name = sc.nextLine();
gf.setName(name);
//接收女朋友的年龄
System.out.println("请输入心仪女朋友的年龄");
String agestr = sc.nextLine();
int age = Integer.parseInt(agestr);
gf.setAge(age);
//如果所有数据都是正确的那么跳出循环
break;
} catch (NumberFormatException e) {
System.out.println("年龄的格式有误,请输入数字");
continue;
}catch (RuntimeException e) {
System.out.println("姓名的长度或者年龄的范围有误");
continue;
}
}
//5.打印
System.out.println(gf);
}
}
package Exceptiondemo;
public class Girlfriend {
private String name;
private int age;
public Girlfriend() {
}
public Girlfriend(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() throws RuntimeException{
int len = name.length();
if (len <3 || len >10){
throw new RuntimeException();
}
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() throws RuntimeException{
if (age < 18 || age > 40){
throw new RuntimeException();
}
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Girlfriend{name = " + name + ", age = " + age + "}";
}
}
自定义异常
- 定义异常类
- 写继承关系
- 空参构造
- 带参构造
意义:为了让控制台的报错信息更加见名知意
技巧:
NameFormate:当前异常的名字,表示姓名格式化问题
Exception:表示当前一个异常类
继承:
运行时:RuntimeException
编译时:Exception 核心 提醒程序猿检查本地信息
file
- File对象就表示一个路径,可以是文件的路径,也可以是文件夹路径
- 这个路径可以是存在的也可以是不存在的
public File (String path)
//根据文件路径创建文件对象
public File (String parent, String child)
//根据父路径名字符串和子路径名字符串创建文件对象
public File (File parent ,string child)
//根据父路径对应文件对象和子路径名字符串创建文件对象
File常见的成员方法
(判断,获取)
public boolean isDirectory()
//判断此路径名表示的File是否为文件夹
public boolean isFile()
//判断此路径名表示的File是否为文件
public boolean exists()
//判断此路径名表示的File是否存在
public long length()
//返回文件的大小(字节数量)
public String getAbsolutePath()
//返回文件的绝对路径
public String getPath()
//返回定义文件时使用的路径
public String getName()
//返回文件的名称,带后缀
public long lastModified()
//返回文件最后修改的时间(时间毫秒值)
1.length 返回文件的大小
细节1 :这个方法只能获取文件的大小,单位是字节
如果单位我们要的是M,G,可以不断除以1024
细节2:这个方法无法获取文件的大小
如果我们要获取一个文件的大小,需要把这个文件夹里面所有文件大小都累加到一起.
2.getAbsolutePath 返回文件的绝对路径
3.getPath 返回定义文件时使用的路径
4.getName 获取名字
细节1:
a.txt:a文件名 txt后缀名,扩展名
细节2:
文件夹:返回值就是文件夹的名字
5.lastModified 返回文件最后修改时间(时间毫秒值)
**
(创建,删除)
**
public boolean createNewFile()
//创建一个新的空的文件
public boolean mkdir()
//创建单级文件夹
public bollean mkdirs()
//创建多级文件夹
public boolean delete()
//删除文件,空文件夹
1.creatNewFile 创建一个新的空文件夹
//细节1:如果当前路径表示的文件不存在则创建成功,方法返回true
//如果当前路径表示文件存在则创建失败,方法返回false
//细节2;如果父级路径不存在,那么方法会有异常IOException
//细节3:创建的一定是文件,如果路径中不包含后缀名,则创建一个没有后缀的文件
File f1 = new File("C:\\aaa\\fan.txt");
boolean b = f1.createNewFile();
System.out.println(b);
2.mkdir make Directory,文件夹(目录)
//
//细节1:windows当中路径是唯一的,如果当前路径已经存在,则创建失败返回false
//细节2:mkdir只能创建单级文件夹,无法创建多级文件夹
File f2 = new File("C:\\aaa\\ddd");
boolean b = f2.mkdir();
System.out.println(b);
3.mkdirs 创建多级文件夹
细节:既可以创建单级文件夹,又可以创建多级文件夹
4.delete
细节1:
如果删除的是文件,则直接删除,不走回收站
如果删除的是空文件夹,则直接删除,不走回收站
如果删除的是有内容的文件夹,则删除失败
(获取并遍历)
public File[] listFiles()
//获取当前路径下所有内容
细节:
- 当调用者File表示的路径不存在时,返回null
- 当调用者File表示的路径是文件时,返回null
- 当调用者File表示的路径返回的是空文件时,返回一个长度为0的数组
- 当调用者File表示的路径是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
- 当调用者File表示的路径是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
IO流
存储和读取数据的小方案
IO流按照流向分类:
输出流:程序——>文件
输入流:文件——>程序
IO流按照操作文件的类型分类:
字节流:可以操作所有类型的文件
字符流:只操作纯文本文件
IO流体系
FileOutputStream
操作本地文件的字节输出流,可以把程序中的数据写到本地文件中
书写步骤:
- 创建字节输出流对象
细节1:参数是字符串表示的路径或者是File对象都可以
细节2:如果文件不存在会创建一个新文件,但要保证父级路径存在 - 写数据
- 释放资源
//1.创建对象
//写出 输出流 OutputStream
//本地文件File
FileOutputStream fos = new FileOutputStream("mybyteStream\\a.txt");
//2.写入数据
fos.write(97);
//3.释放资源
fos.close();