函数式编程
/*1函数式编程
优点:省内存(少创建好多类和对象);代码简洁.
缺点:可读性较差.*/
//声明集合
TreeSet<String> test = new TreeSet<>(new Comparator<>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
test.add("fff");
test.add("bb");
test.add("aa");
test.add("hh");
//遍历
for (String s1 : test) {
System.out.println(s1);
}
//用函数式编程实现上面的代码
TreeSet<String> treeSet = new TreeSet<>((o1, o2) -> -o1.compareTo(o2));//用了lambda表达式,倒序
treeSet.add("fff");
treeSet.add("bb");
treeSet.add("aa");
treeSet.add("hh");
//遍历
treeSet.forEach(System.out::println);//用函数式编程中函数,用了方法引用
Lambda表达式
lambda表达式基本语法:
函数式接口:一个接口中只有一个抽象方法,叫函数式接口.
eg: <函数式接口> <变量名> = (参数1,参数2…) -> { //方法体 };
lambda表达式注意事项:
Lambda引入了新的操作符:->(箭头操作符)->将表达式分成两部分
左侧:(参数1,参数2…)表示参数列表; 右侧:{}内部是方法体
形参列表的数据类型会自动推断,所以小括号只需要写形参参数名;
如果形参列表为空,只需保留();
如果形参只有1个,()可以省略,只需要参数的名称即可;
如果执行语句只有1句,且无返回值,{}可以省略,
若有返回值,则若想省去{},则必须同时省略return,且执行语句也 保证 只有1句;
lambda不会生成一个单独的内部类文件(省内存);
lambda表达式若访问了局部变量,则局部变量必须是final的,若是局部变量
List<Employee> empList = new ArrayList<>();
empList.add(new Employee("ab唐三", 18, 18000.0));
empList.add(new Employee("fefef萧炎", 28, 28000.0));
empList.add(new Employee("c小舞", 17, 8000.0));
empList.add(new Employee("kdf玉儿", 38, 28000.0));
empList.add(new Employee("b白菜", 48, 12000.0));
//获取年龄大于25的员工信息
List<Employee> empList4 = filterEmp(empList, (e) -> e.getEage() > 25);
empList4.forEach(System.out::println);
//获取年龄大于25的员工信息
empList.stream().filter((e) -> e.getEage() > 25).forEach(System.out::println);
System.out.println("--------------------------");
//获取工资大于10000的员工信息
empList.stream().filter((e) -> e.getEsalary() > 10000).forEach(System.out::println);
System.out.println("--------------------------");
//获取姓名长度为3的员工信息
empList.stream().filter((e) -> e.getEname().length() == 3).forEach(System.out::println);
}
/**
* 过滤员工信息的方法
*
* @return List<Employee>
*/
public static List<Employee> filterEmp(List<Employee> empList, MyPredicate<Employee> mp) {
//声明一个集合满足要求的员工信息
List<Employee> empList1 = new ArrayList<>();
//遍历原集合
for (Employee e1 : empList) {
//如果当前遍历员工满足要求,添加到新集合中存着
if (mp.test(e1)) {
empList1.add(e1);
}
}
return empList1;
}
函数式接口
如果一个接口中只有一个抽象方法,这个接口叫函数式接口
函数式接口可以使用Lambda表达式,lambda表达式会被匹配到这个抽象方法上
如果一个接口上面加@FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。
方法引用
是lambda表达式的一种简写形式。 如果lambda表达式方法体中只是调用 一个特定的已经存在的方法,则 可以使用方法引用。
使用“::”操作符将方法名和对象或类的名字分隔开来。以下是四种使用情况:
- 对象::实例方法
- 类::静态方法
- 类::实例方法
- 类::new 调用无参构造
//创建一个员工对象
Employee e1 = new Employee("王永亮", 18, 20000.0);
//对象::实例方法
Supplier<String> sup1 = e1::getEname;
System.out.println(sup1.get());
//类::静态方法
Supplier<Double> num1 = Math::random;
System.out.println(num1.get());
//类::实例方法
Function<Employee, String> fun1 = Employee::getEname;
System.out.println(fun1.apply(e1));
//:类::new ,调用无参构造创建实例对象
Supplier<Employee> sup3 = Employee::new;
System.out.println(sup3.get());
Stream API
一个Stream表面上与一个集合很类似,集合中保存的是数据,而流中对数据的 操作
Stream特点:
Stream 自己不会存储元素。
Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
获得Stream的方法(6种)
- 直接创建流
- 声明数组,将数组转换为流
- 将集合转换为流
- 用跌代方式生成无限流
- 用供给型接口直接生成无限流
Stream的常用中间操作
过滤,限制,跳过,去重,map映射,自然排序,定制排序
注意:Stream对象调用中间操作的方法后返回的还是Stream类型对象.
Stream的终止操作
allMatch——检查是否匹配所有元素
anyMatch——检查是否至少匹配一个元素
noneMatch——检查是否没有匹配的元素
findFirst——返回第一个元素
findAny——返回当前流中的任意元素
()count——返回流中元素的总个数
max——返回流中大值
min——返回流中小值
()reduce处理集合中元素得到个新数据
()将流转换为list集合
()将流转换为set集合