使用Lambda表达式建立接口对象高效编程

一、前言

在java8中,增长了函数接口、Lambda和方法引用,使得建立函数对象变得很容易高效,本文经过情景引入,具体说明一下使用Lambda表达式建立接口对象是如何提升编程效率的。固然文中的所涉及的并不是Lambda的所有使用场景。java

二、代码情景导入

咱们已有共识:Java是面向对象的编程语言,若是咱们调用任何一个对象的方法,并往方法中传递参数,参数必须是类或接口的对象或者是基本类型变量。
按照这个共识,咱们看下面的代码:编程

//定义一个接口
interface Example{
    //接口中只定义了一个抽象方法
    void add(Integer a,Integer b);
}
//接口的实现类
class ExampleImpl implements Example {
    @Override
    public void add(Integer a, Integer b) {
        System.out.println("a+b=" + (a + b));
    }
}

//测试类
public class TestLambda {
    //测试类中定义了一个方法,并规定了接收参数的类型
    public void test(Example example) {
        example.add(1, 1);
    }
    public static void main(String[] args) {
        //声明一个接口类型的变量并经过接口实现类实例化
        Example example = new ExampleImpl();
        //main方法中调用本身类的其余方法必须先建立该类的对象,经过对象调用
        TestLambda testLambda = new TestLambda();
        //调用test,并把实例好的对象传给test
        testLambda.test(example);    
    }
}

本地运行,控制台显示结果为:a+b=2。固然结果不重要。看懂了上述代码,思考一下,代码能否精简,提升执行效率。
观察得出:设计模式

  1. 接口的意义好像不是很大,可否去掉,直接定义Example类?呵呵,去掉了咱们后面的研究没意义了。
  2. 实现类在本例中只用了一次,能否用匿名类替换?——能够

接下来在上面的代码基础上,咱们使用匿名类替换实现类,使得代码进一步精简,代码以下:编程语言

//定义一个接口
interface Example{
    //接口中只定义了一个抽象方法
    void add(Integer a,Integer b);
}
//去掉了接口的实现类

//测试类
public class TestLambda {
    //测试类中定义了一个方法,并规定了接收参数的类型
    public void test(Example example) {
        example.add(1, 1);
    }
    public static void main(String[] args) {
        //main方法中调用本身类的其余方法必须先建立该类的对象,经过对象调用
        TestLambda testLambda = new TestLambda();
        //调用test,并把Example类型的匿名类对象传给方法
        testLambda.test(new Example(){        
            @Override
            public void add(Integer a, Integer b) {
                System.out.println("a+b=" + (a + b));
                
            }
        });    
    }
}

使用匿名类,咱们精简了代码,还能不能更加精简呢?
匿名类知足了传统面向对象的设计模式对函数对象的需求,可是,匿名类的繁琐使得Java中进行函数编程的前景变得十分黯淡。咱们平时的方法函数如同简单函数f(x),像这种f(t(x))的复合函数不常见。所谓函数式编程就是将函数(一段操做)做为一个基本单位进行传递。之前的Java中参数只能是具体的变量,函数式编程打破这一规范,能够将整个方法做为一个参数传递。
下面咱们使用Lambda表达式,进一步精简代码:ide

//定义一个接口
interface Example{
    //接口中只定义了一个抽象方法
    void add(Integer a,Integer b);
}
//去掉了接口的实现类

//测试类
public class TestLambda {
    //测试类中定义了一个方法,并规定了接收参数的类型
    public void test(Example example) {
        example.add(1, 1);
    }
    public static void main(String[] args) {
        //main方法中调用本身类的其余方法必须先建立该类的对象,经过对象调用
        TestLambda testLambda = new TestLambda();
        //调用test,并把Lambda表达式传给方法
        testLambda.test((a,b)->System.out.println("a+b=" + (a + b)));    
    }
}

Lambda表达式代码:
(a,b)->System.out.println("a+b=" + (a + b))
最终执行效果同上。这样咱们经过使用Lambda表达式达到了代码干净简洁,执行效率高效的目的。函数式编程

三、反思

咱们前后经过匿名类和Lambda表达式对代码重构,使得代码精简,使用匿名类容易理解,可是使用Lambda表达式感受与咱们开头的共识向左,缘由是什么呢?这个表达式难道就是符合类型要求的对象?这个表达式到底是如何起做用的?我想你们必定存在不少疑问。
注意观察:定义的接口只有一个抽象方法。
疑问答案:在Java8中(向后兼容),造成了“带有单个抽象方法的接口是特殊的,值得特殊对待”的观念,这些接口被称为函数接口,Java容许利用Lambda表达式建立这些接口的实例。Lambda相似于匿名类的函数,可是比它简洁更多。Lambda表达式被称为函数对象。
类型推导:编译器利用一个被称为类型推导的过程,根据上下文推断出类型。首先代码案例中,testLambda.test()方法惟一(TestLambda类中没有重载的test方法),编译器会强制认为testLambda.test()方法中的实际参数类型即Lambda表达式类型为定义的形式参数类型Example,又因为接口只有一个抽象方法,Lambda表达式天然只能实现该抽象方法,Lambda表达式表达式中的参数类型天然就是接口中抽象方法的参数类型。函数

四、总结

能写成Lambda的接口的条件:接口中有且仅有一个抽象方法。如本案例中的接口Example,若是出现多个抽象方法,编译器的类型推导会出错。测试

函数式接口可使用(不强求)注解@FunctionalInterface 进行强制规范
image.png
更多Lambda语法知识,可参考官方文档。spa

相关文章
相关标签/搜索