栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

lambda函数引用学习记录

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

lambda函数引用学习记录

lambda表达式

当一个函数中的参数有一个接口,并且接口中只有一个需要实现的方法(java8之后接口中可以有默认方法default修饰)

比如接口:
	interface MyInterface{
        public void print(String a);
    }
方法
	public void do1(MyInterface myInterface){
        myInterface.print("aaa");
    }
使用
	@Test
    public void test(){
    	//传统方式
        do1(new MyInterface() {
            @Override
            public void print(String a) {
            	System.out.println(a);
            }
        });
        //lambda表达式
        do1((s1)->{System.out.println(s1);});
        //简化
        do1(s1-> System.out.println(s1));
    }
函数引用
常用的几种形式
形式lambda表达式函数引用注释
类::静态方法(arg1,arg2)->{类.静态方法(arg1,arg2)};类::静态方法参数全部作为静态方法中的参数
实例对象::方法(arg1,arg2)->{示例对象.普通方法(arg1,arg2)};示例对象::普通方法参数全部作为普通方法中的参数
类::普通方法(arg1,arg2)->{arg1.普通方法(arg2)};类::静态方法第一个参数作为调用者,之后的全部作为普通方法中的参数
类::new(arg1,arg2)->{new 类(arg1,arg2)};类::new参数全部作类的构造函数参数,类必须提供与接口参数类型个数一致的构造方法
1、类::静态方法

接口中的方法需要我们自己实现逻辑,那么如果有已经定义好的相似结构方法我们是不是直接引用即可,可能你还是很懵。下面直接上例子
上面的System.out.println(s1)其实就是已经定义好类直接调用方法,可以看println方法的声明和我们接口中的方法声明结构是一致的

	@Test
    public void test(){
        do1(s -> System.out.println(s));
        do1(System.out::println);
    }
    public void do1(Consumer consumer){
        System.out.println("function");
        consumer.accept("aa");
    }

总结:System.out.println()方法可以直接调用,也就是类似于类调用静态方法这种形式,
接口中的方法参数全部作为调用的静态方法中的参数,这就是类::静态方法这种函数引用形式

2、实例对象::方法

例子:

	@Test
    public void test(){
        A a = new A();
        //do1((s1,s2)->a.service(s1,s2));
        do1(a::service);
    }
    public void do1(BiConsumer consumer){
        consumer.accept("aaa","bbb");
    }
    class A{
        private void service(String a,String b){
            System.out.println(a+b);
        }
    }

总结:接口中的参数作为普通方法的参数

//接口
consumer.accept("aaa","bbb");
//lambda
do1((s1,s2)->a.service(s1,s2));
do1(a::service);
//普通方法
service(String a,String b) 

3、类::普通方法
接口中只有一个参数,普通方法就没有参数
	@Test
    public void test2(){
        BiConsumer print = Lambda2::print;
        do2(print);
    }
    public void print(String b){
        System.out.println(b);
    }
    public void do2(BiConsumer print){
        print.accept(new Lambda2(),"aaaaa");
    }

接口中两个参数,普通方法中一个参数
	@Test
    public void test2(){
        Consumer print = Lambda2::print;
        do2(print);
    }
    public void print(){
        System.out.println("a");
    }
    public void do2(Consumer print){
        print.accept(new Lambda2());
    }

上面是自定义类的普通方法,下面是一个使用String类的普通方法

	@Test
    public void test3(){
        BiFunction function=String::substring;
        do3((str,index)->str.substring(index));
        do3(String::substring);
    }
    public void do3(BiFunction function){
        String str = function.apply("abcdefg", 2);
        System.out.println(str);
    }


接口中的第一个参数作为调用者,后面的参数作为普通方法的参数

4、类::new
	@Test
    public void test(){
        do1(User::new);
    }
    public void do1(BiFunction function){
        User user = function.apply("jack", 20);
        System.out.println(user);
    }
    @Data
    class User{
        private String username;
        private Integer age;
        public User(String username, Integer age) {
            this.age=age;
            this.username=getUsername();
        }
    }

参数全部作类的构造函数参数,类必须提供与接口参数类型个数一致的构造方法

补充

引用的方法有重载怎么确定用的哪个方法?

例如:String的subString方法
	 public String substring(int beginIndex)
	 public String substring(int beginIndex, int endIndex)

答:是根据函数式接口中声明的方法参数来确定

	@Test
    public void test3(){
        BiFunction function=String::substring;
        do3((str,index)->str.substring(index));
        do3(String::substring);
        TriFunction function1 = String::substring;
        do4((str,index,off)->str.substring(index,off));
        do4(String::substring);
    }
    public void do3(BiFunction function){
        String str = function.apply("abcdefg", 2);
        System.out.println(str);
    }
    public void do4(TriFunction function){
        String str = function.apply("abcdefg", 2,4);
        System.out.println(str);
    }

当然 如果不想用与接口方法对应的重载方法,那么就不能使用函数引用,回归到lambda表达式
	@Test
    public void test4(){
        do5((str,index,off)->{return str.substring(index);});
        do5((str,index,off)-> str.substring(index));
    }
    public void do5(TriFunction function){
        String str = function.apply("abcdefg", 2,4);
        System.out.println(str);
    }
总结

函数引用就是将已经定义好的方法直接拿过来用,必须保证函数式接口声明与调用的方法结构。更像是一种约定,代码简洁了,但得按照更严格的格式。除了类::普通方法这种引用,接口的第一个参数作为调用者,后面的参数作为普通方法的参数、其他形式的引用都是把接口的全部参数作为调用方法的全部参数。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/632027.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号