为了了解Lambda表达式,我们必须了解什么是函数式接口,这是Lambda表达式得以实现的依据。
在java中,函数式接口指注解了@FunctionalInterface(非必须)的接口。
函数式接口具有一下特性:
- 接口中有且仅有一个抽象方法(必须)。
除却以上性质与普通的接口没有区别。
由以上定义,那么问题来了,为什么要使用函数式接口?
让我们先看一个接口的实现案例。
// 传统的接口实现方式interface MyInterface { void test();}class MyInterfaceImpl implements MyInterface{ public void test() { // 各种处理 }}class Client { public void process() { MyInterface mif = new MyInterfaceImpl(); mif.test(); }}
目前看上去我们的实现是没有什么问题的,无外乎定义一个接口,然后定义接口的实现类,在客户端调用的过程中父类引用子类对象。。。
但是,如果这么定义的话,意味着实现类是可以复用的。实际上应该反过来思考,就因为需要复用实现类,我们才这么定义接口与实现。
有基础的小伙伴肯定反应过来我想说的问题:如果一个接口的实现根据业务需求在项目中指调用两三次,并且每次的实现方式还不同,我需要为了这三个不一样的实现分别写三个不同的实现类吗?
其实没有必要,由此引出接下来的内容:匿名内部类实现接口。
// 匿名内部类的接口实现方式interface MyInterface { void test();}class Client { public void process() { MyInterface mif = new MyInterface() { @Override public void test() { // 各种处理 } }; mif.test(); } /* 其实不难看出,对于只有一个抽象方法的接口,匿名内部类的实现方式比较冗余 首先new MyInterface(){}并不是非写不可, @Override,public,void,test也同样。 可能有同学看到这里已经蒙了:这人在说啥?我接下来解释。 接口只有一个抽象方法也就是说没有重载,所以我们通过明确写出方法的参数列(类型也不需要,可推定) 已经方法体就可以确定重写的是哪个方法,也就省去了@Override public void test。 又因为变量声明了一个接口类型所以就知道需要实例化的对象接口也就省去了new MyInterface(){} 至此代码变为了以下这种形式: MyInterface mif = () -> { /* 各种处理 */ }; */}
// 匿名内部类的接口实现方式interface MyInterface { void test();}class Client { public void process() { MyInterface mif = new MyInterface() { @Override public void test() { // 各种处理 } }; mif.test(); } /* 其实不难看出,对于只有一个抽象方法的接口,匿名内部类的实现方式比较冗余 首先new MyInterface(){}并不是非写不可, @Override,public,void,test也同样。 可能有同学看到这里已经蒙了:这人在说啥?我接下来解释。 接口只有一个抽象方法也就是说没有重载,所以我们通过明确写出方法的参数列(类型也不需要,可推定) 已经方法体就可以确定重写的是哪个方法,也就省去了@Override public void test。 又因为变量声明了一个接口类型所以就知道需要实例化的对象接口也就省去了new MyInterface(){} 至此代码变为了以下这种形式: MyInterface mif = () -> { /* 各种处理 */ }; */}
虽然上述的实现方式可以让我们比较方便的实现需求频繁变动且复用需求低的接口,但人类是非常懒的,为了让我们实现上述功能的同时写更少的代码,技术人员发明了lambda