lambda表达式和方法引用

参考:
1
2

什么是lambda表达式

  • lambda意为λ,表示是一个函数,而一个函数只有唯一的输入输出映射,因此引出lambda表达式的定义

  • Lambda是一个唯一匿名方法

  • 一个接口,如果只有一个显式声明的抽象方法,那么它就是一个函数式接口。一般用@FunctionalInterface标注出来(也可以不标)

  • 因为该接口有一个抽象方法,在new的时候需要@Override这个抽象方法

格式

什么可以省略?

可推断的都可省略,因此尽可能使用泛型

方框中都可以省略

方框中都可以省略因为在调用这个方法的时候,public int add(int int ) return 都是唯一且确定且必须存在的,因此可以被唯一推断出来,所以可以省略,省略后为

(x,y) -> x+y;
因为只有一行语句,所以代码块{}可省,return可省

1.预定义的函数式接口

在JDK中定义了很多的函数式接口,例如BiFunction接口,就可以传入两个参数,返回一个参数,无需自定义;当然三个传参还是需要自定义的

1.1

函数型接口

1.JDK预定义了很多函数式接口以避免用户重复定义。最典型的是Function

@FunctionalInterface
public interface Function<T, R> { 
    R apply(T t);
}

这个接口代表一个函数,接受一个T类型的参数,并返回一个R类型的返回值。

消费型接口

2.另一个预定义函数式接口叫做Consumer,跟Function的唯一不同是它没有返回值。

@FunctionalInterface
public interface Consumer<T> { 
    void accept(T t);
}

供给型接口

3.Supplier 有一个get()方法

@FunctionnallInterface
public interface Supplier<T>{
	T get();
}

断定型接口

4.还有一个Predicate断定,用来判断某项条件是否满足。经常用来进行筛滤操作:

@FunctionalInterface
public interface Predicate<T> { 
    boolean test(T t);
}

1.2函数式接口的测试

public class LambdaTest {


    public static void main(String[] args) {

//1.Runnale接口测试————run()
        Runnable r = () -> System.out.println("测试");
        r.run();


//2.Function接口测试————— T apply(X x)
        Function<Integer, Integer> fun = (age) -> {
            System.out.println("年龄为:" + age);//年龄为:21
            return age + 1;
        };
        System.out.println("下次过生日的年龄:" + fun.apply(21));//下次过生日的年龄:22

//3.Consumer接口测试————accept(T t)
        //3.1加泛型,推断s为String类型
        Consumer<String> con = (s) -> System.out.println(s + "666666");//双击关注666666
        con.accept("双击关注");
        //3.2不加泛型需要指定,默认为Object
        Consumer con2 = (s) -> System.out.println(s + "777777");//养猪厂子777777
        con2.accept("养猪厂子");

//4.Supplier接口测试
        //4.1不加泛型,则不推断
        Supplier sup = () -> {
            return new Integer(1);
        };
        //4.2加泛型,则可推断返回值为Integer
        Supplier<Integer> sup2 = () -> 1;

//5.Predicate接口测试
        Predicate<Integer> pred = (i) -> i > 10;
        System.out.println(pred.test(11));//ture
        System.out.println(pred.test(9));//false
    }
	}

2.自定义函数式接口

定义函数式接口,接收多个参数

@FunctionalInterface
public interface MyFunction<X,Y,Z,T> {
    T fun(X x,Y y ,Z z);
}

使用

//6.自定义MyFunction接口
        MyFunction<Integer,Integer,Integer,String> myFun =
                (age,weight,higth) -> "年龄为:" + age
                                    + "体重为:" + weight
                                    + "身高为:" + higth;

        String myInfo = myFun.fun(21, 145, 181);
        System.out.println(myInfo);//年龄为:21体重为:145身高为:181

3.方法引用

  • 当实现@FunctionalInterface的函数式接口使用lambda表达式时,
    如果方法体直接调用 某个类or对象 的 静态or非静态方法,
    且返回值和形参都高度相同or完全相同,那么就可以使用方法引用
  • 编译看左:类型的推断需要左边函数类的泛型来指定

3.1对象::非静态方法

Function fun = p :: myHight;即把fun中的唯一抽象函数apply() 和 myHight()方法绑定,调用fun.apply(1)相当于调用p.myHight(1)

public class LambdaTest2 {
    public static void main(String[] args) {

        //0. People的非静态方法myHight()的形参 和 Function类的apply()方法的形参对应
        //                            的返回值 和                      的返回值对应

        People p = new People(21,"张家豪");
        //1.用 对象p :: 非静态方法
        Function<Integer,String> fun = p :: myHight;
        //2.此时的fun对象中的apply()方法已经和 p对象中的myHight()方法绑定
        System.out.println(fun.apply(181));


    }
}



class People{
    int age;
    String name;

    public  String myHight(Integer hight){
        return "my hight is " + hight;
    }}

3.2类 :: 静态方法

。。。。。。。。
    //编译看左:左边需要指定泛型,才能推断出右边的参数类型
        Consumer<Integer> con = People::describe;
        con.accept(2);
    }
}


class People {
    int age;
    String name;

    public static void describe2(Integer i) {
        System.out.println("People类有" + i + "个属性参数");
        System.out.println("一个是name,一个是age");
    }

3.3类 :: 实例方法

参考

4.构造器引用

和方法引用类似
构造器的形参 = 函数式接口的抽象方法

        Function<String,People> fun1 = s -> new People(s);
        People p1 = fun1.apply("张豪猪");
        
        Function<String,People> fun2 = People::new;
        People p2 = fun2.apply("豪猪张");

        BiFunction<Integer,String,People> bifun1 = People::new;
        People p3 = bifun1.apply(21, "豪张猪");


    }
}

@AllConstructor
class People {
    int age;
    String name;

5.数组引用

数组引用算是构造器引用的一种,可以引用一个数组的构造

    Function<Integer,People[]> fun1 = p -> new People[p];
    People[] arr1 = fun1.apply(10);//创建一个长度为10的People数组
    
    Function<Integer,People[]> fun2 = People[]::new;
    fun2.apply(20);

}
}


class People {
int age;
String name;

区别与总结

1.类型推断

编译看左

有一个People的静态方法 public static void describe(Integer count) {。。}
则必须通过 Consumer <Integer> con = People::describe;
而不能 Consumer con = People::describe;
因为后者不能推断出con.accept()需要什么类型的参数

泛型顺序对应形参顺序

Function<x,y> fun = 是如何确定谁是形参谁是返回值的呢?

  • 第一个是形参,第二个是返回值

而此时因为一一对应,Function<Integer,String>一定是Integer为形参,String为返回值

  • 》》》当BiFunction<T, U, R> bifun= 时,R是返回值类型,T和U的顺序也已经固定

2.能省则省

凡是能唯一确定推断的都能省略

  • (s) ->{return 一个语句} 可写为 s -> 一个语句

3.代码绑定

例如:

  • Function<Integer,String> fun = p :: myHight就是把myHight()方法绑定给了fun.apply()
  • Supplier sup = () -> {…return i } ; 则是把{…return i }代码块绑定给sup.get()

4.方法引用和lambda的联系

方法引用本质就是lambda表达式,只是在上一个例子中Supplier<Integer> sup = () -> {.....return i } ;里面的{.....return i } 如果是被封装到了某一个特定的方法,那么可以直接使用方法引用,而不需要把代码块的内容挨个写出来

5.构造器引用和方法引用的联系

构造器引用本质是方法引用,方法体就是new 一个对象,并返回,因此形如:
但一定要有new

6.数组引用和构造引用的联系

之前的构造引用都是new一个对象,而数组引用是new一个数组,仅此而已,形如:创建长度为20的People[]

forEach的lambda表达式

参考

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值