引入lambda
第一次使用
在test01 我们写了一个内部类 比较大小 实际有用的话就这一句 很麻烦
在test02 用lambda表达式优化
package com.lijiawei;
import org.junit.Test;
import java.net.Inet4Address;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeSet;
public class Testlambda {
@Test
public void test01(){
//原来使用treeset排序得写一个匿名内部类
Comparator<Integer> com = new Comparator<Integer>(){
@Override
public int compare(Integer o1,Integer o2) {
return Integer.compare(o1,o2);//实际就这一句话有用
}
};
TreeSet<Integer> ts = new TreeSet<Integer>(com);
ts.add(2);
ts.add(1);
System.out.println(ts);
}
@Test
public void test02(){
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
TreeSet<Integer> ts = new TreeSet<Integer>(com);
ts.add(2);
ts.add(1);
System.out.println(ts);
}
@Test
public void test03(){
}
}
一个需求
查询所有年纪大于20的人
List<Employee> list = Arrays.asList(
new Employee("张三",28,5000),
new Employee("李四",8,10000),
new Employee("王五",38,2000),
new Employee("赵六",48,4500)
);
@Test
public void test03(){
List<Employee> a = filterAge(list);
System.out.println(a);
}
//查出年龄大于10岁的
public List<Employee> filterAge(List<Employee> list){
List<Employee> employees = new ArrayList<>();
for (Employee e :list){
if(e.getAge()>10){
employees.add(e);
}
}
return employees;
}
//查出工资大于5000的
public List<Employee> filterAge2(List<Employee> list){
List<Employee> employees = new ArrayList<>();
for (Employee e :list){
if(e.getSalary()>5000){ //和上面的方法就变了这一句话
employees.add(e);
}
}
return employees;
}
如果我又加一个需求 要求出工资大于5000并且年龄大于20的人 那是不是又得写一个方法 需求一变 就要改变原来的代码 这样不好
策略模式优化
定义一个接口
package com.Inter;
public interface Myfilter<T> {
public boolean test(T t);
}
定义实现类
package com.Inter;
import com.pojo.Employee;
public class ImplMyfilter implements Myfilter<Employee>{
@Override
public boolean test(Employee employee) {
return employee.getAge()>35;
}
}
测试类
public List<Employee> show(List<Employee> list , Myfilter<Employee> im ){
List<Employee> employees =new ArrayList<>();
for (Employee employee:list){
if(im.test(employee)){
employees.add(employee);
}
}
return employees;
}
@Test
public void test04(){
List<Employee> show = show(list, new ImplMyfilter());//如果需求变了 我把这个实例换一下就行
System.out.println(show);
}
如果需求在变 我们只需要增加一个实现类 在调用的时候 new 这个新写的实现类即可 使用场景:商场打折
我们发现策略模式有个缺点 : 创建新功能就得写一个类 所以在优化
匿名内部类优化
匿名内部类直接实现 就不用写类实现了
public void text(){
List<Employee> l = show(list, new Myfilter<Employee>() {
@Override
public boolean test(Employee employee) {
return employee.getSalary()>5000;
}
});
System.out.println(l);
}
匿名内部类优化可读性差 所以在优化
lambda表达式优化
@Test
public void text(){
List<Employee> l = show(list,(e) -> e.getSalary()>5000);
System.out.println(l);
}
还能更简洁 之后使用stream优化 先来学习lambda
lambda语法
注意: j.k1.8以前 匿名内部类引用同级别的变量 那个变量必须显示的写final 8之后默认加了final
-> 操作符分为俩部分 左侧 是抽象类中要重写的方法的参数列表 右侧是要执行的功能
接口中只有一个方法
1无参无返回值
Runnble r = ( ) ->System.Out.Print(“你好”);
2有一个参数无返回值
Consumer c = ( x) ->System.out.Print(“你好”);
只有一个参数 小括号可以不写
3有多个参数有返回值 有多条执行语句
多条语句 使用大括号抱起来
Comparator com= (x,y)->{
System.out.Print(“你好”);
return Integer.compare(x,y);
}
4 如果只有一条语句
return 和大括号可以省略
Comparator com= (x,y) -> Integer.compare(x,y);
5不写数据类型
上面的xy 都没有写数据类型 因为jjvm编译器可以类型推断
比如 String[] str=[“aa”,“bb”,“cc”] 这里的内容就是推断出来的 如果你分开写就报错
String[] str; str=[“aa”,“bb”,“cc”] //报错
再看这个上面写过的 我们e按下点的时候就提示有getSalary方法 他怎么知道我是什么类型的呢?根据目标类型推断出这是什么类型
List l = show(list,(e) -> e.getSalary()>5000);
因为不能写方法名 当接口有多个方法时java不知道重写的是哪个方法 所以借口不能写多个抽象方法
函数式接口
只有一个抽象方法的接口叫函数式接口 在接口上加注解@FunctionInterface 可以帮我们检查这个接口是不是函数式接口
内置函数式接口
每次们用一个功能 都要自己定义一个函数式接口 java想到了这一点 所以有四个内置的接口
Consumer void acept(T t) 消费型接口
public class TestLamda{
@Test
public void test(){
show(100,(a)-> System.out.println("消费了"+a));
}
public void show(Integer number, Consumer<Integer> consumer){
consumer.accept(number);
}
}
Supplier T get(); 供给型接口
package com.lijiawei;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class TestLamda{
@Test
public void test(){
List l = show(10,() -> (int)(Math.random()*10));
System.out.println(l);
}
public List<Integer> show(Integer number, Supplier<Integer> supplier){
List<Integer> lists = new ArrayList<>();
for (int i = 0; i <number ; i++) {
lists.add(supplier.get());
}
return lists;
}
}
Function<T,R> R apply(T t) 函数式接口
package com.lijiawei;
import org.junit.Test;
import java.util.function.Function;
public class TestLamda{
@Test
public void test(){
String a = show(" helloworld ",(x) ->x.trim() );
System.out.println(a);
}
public String show(String str, Function<String,String> function){
return function.apply(str);
}
}
predicate boolean test(T t ) 断言型接口
方法引用与构造器引用
以下三种写法有个前提 我们写的lambda体的方法的返回值和参数列表要与 函数时接口的抽象方法保持一致
在lambda表达式中 我们写了参数列表 和 方法体并返回了一个东西 这写都是手动写出来的 引用不写但要保持一致
对象::实例方法名
package com.lijiawei;
import org.junit.Test;
import java.util.function.Consumer;
public class TestLamda{
@Test
public void show(){
Consumer<String> consumer1 = System.out::println;
consumer1.accept("zz");
}
}
再看一个例子
无参有返回值 Math::random也必须无参无返回值
package com.lijiawei;
import org.junit.Test;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class TestLamda{
@Test
public void show(){
//Supplier<T> T get();
Empoyee emp = new Employee();
Supplier<Double> supplier =emp::getAge;
Double d = supplier.get();
System.out.println(d);
}
}
类::静态方法名
package com.lijiawei;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class TestLamda{
@Test
public void show(){
Comparator<Integer> com = Integer::compare;
int a = com.compare(5,4);
System.out.println(a);
}
}
类::实例方法名
先用lambda表达式 需求 比较俩个字符串是否一样
public void show(){
BiPredicate<String,String> bp = (x,y)->x.equals(y);
boolean b =bp.test("a","a");
System.out.println(b);
}
为什么类名能调用实例方法呢? 当第一个参数是实例方法的调用者 另一个参数是实例方法的参数时 才能这么调
方法引用格式
public void show(){
BiPredicate<String,String> bp = String::equals;
boolean b =bp.test("a","a");
System.out.println(b);
}
构造器引用
如果 方法体是获取对象
Supplier<Employee> s = ()->new Employee();
可以这么写 那用的是有参构造还是无参构造呢 得看函数接口的抽象方法的参数列表有多少个 构造器重载怎么办呢
泛型推断可以该用哪个构造器
Supplier<Employee> s = Employee::new;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FRPnO5fl-1584371457819)(C:\Users\李嘉伟\AppData\Roaming\Typora\typora-user-images\image-20200316230624253.png)]