前言:小编我刚刚完成了跳槽,正在新公司无所事事,就开始自学寻坑之路。以后还会发发主流框架,主流插件,反正什么主流我都不会(你咬我啊!!!)最新的java9都已经铺天盖地了,小编我可是连java8都还没去看过,所以我一直在底层过着搬砖人的日子。言归正传。本章主要讲了Java8新特征的Lambda表达式。
简介:
- 什么是Lambda表达式?
- Lambda表达式在Java8实现
- 什么是FunctionInterface 函数式接口?
- 目标类型(Target Typing)
- 实践简简单单加减运算代码栗子☺
- Lambda表达式总结
1.什么是Lambda表达式?
“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。
上面是百度的介绍,看不懂吧!不需要看懂,只要知道lambda 表达式是一种由数学的λ演算衍变成计算机语言抽象匿名函数。(抽象:这个是不是很熟悉,匿名:这个是不是很熟悉,函数:这个就更熟悉),这样拆分下是不是很简单☺。
2.Lambda表达式在Java8中实现
Lambda表达式是可以将函数当作参数,或者将代码本身当作采参数来进行函数处理。
很多JVM平台上的语言(Groovy、Scala等)从诞生之日就支持Lambda表达式,但是Java开发者没有选择,只能使用匿名内部类代替Lambda表达式。Java8现在需要反转过来,要用Lambda表达式来代替匿名内部类。
- 匿名内部类的基本实现
abstract class Person {
public abstract void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
- 接口上使用匿名内部类
interface Person {
public void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
- Lambda表达式实现
interface Person {
public void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = ()->{
System.out.println("eat something");
};
p.eat();
}
}
简单描述下Lambda表达式的格式:
Interface interface =( 抽象方法入参 ) -> { 抽象方法实现 }
发现了没? 并没有接口里的抽象方法名。
这就奇怪了,咱们都知道Java多态的特征,假设Person接口有多个抽象方法重载,又或者假设多个抽象方法方法名不同,都没有入参,怎么就能够重写了Person接口中的eat方法呢?Java8是用什么样的方式来控制Lambda表达式的实现呢?
JAVA开发者就定义了一种接口:
FunctionInterface 函数式接口,用于Lambda表达式的处理什么是
FunctionInterface 函数式接口,接着看第三点。
3.什么是FunctionInterface 函数式接口?
简单来说,函数式接口是只包含一个抽象方法的接口。比如Java标准库中的java.lang.Runnable和 java.util.Comparator都是典型的函数式接口。
java 8提供 @FunctionalInterface作为注解,这个注解是非必须的,只要接口符合函数式接口的标准(即只包含一个抽象方法的接口),虚拟机会自动判断, 但 最好在接口上使用注解@FunctionalInterface进行声明,以免团队的其他人员错误地往接口中添加新的方法。
@FunctionalInterface
public interface Person{
void eat();
}
or
public interface Person{
void eat();
}
// @FunctionalInterface 这个可写可不写
注意点:
- 如果要写lambda表达式,接口尽量加上@FunctionalInterface注解,它能保证接口有且只有一个抽象方法
- 默认方法和静态方法不会破坏函数式接口的定义。
- 接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
- 如果一个接口符合”函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。
@FunctionalInterface
public interface Person{
// 抽象方法 void eat();
// java.lang.Object中的方法不是抽象方法 public boolean equals(Object var1);
// default不是抽象方法 public default void defaultMethod(){
}
// static不是抽象方法 public static void staticMethod(){
}
}
如果函数式接口定义好了,Lambda表达式里只有接口的引用变量,我们怎么知道我们定义的某个lambda表达式可以用到某个函数式接口呢?
不要着急请看第四点,目标类型
4.目标类型(Target Typing)
对于lambda表达式的类型是通过它的应用上下文来推导出来的。这个过程我们称之为类型推导(type inference)。
在上下文中我们期望获得到的类型则称之为目标类型(Target typing)
简单概述,
JVM在加载时候帮你推导,帮你获取到你想获取的类型。条件就是
“抽象方法的入参参数”,也就是Lambda表达式中的Interface interface =( 抽象方法入参 ) -> { 抽象方法实现 }
JVM根据函数式接口的引用变量(interface)去推导是那一个函数式接口,
JVM会根据Lambda表达式中的“抽象方法入参”去推导在上述函数式接口里面的那个抽象方法。
5.实践简简单单加减运算代码栗子☺
复杂的我就不写了,因为我怕自己看不懂,尴尬。。。。哈哈
@FunctionalInterface
public interface LambdaOperation {
int test(int x,int y);
// java.lang.Object中的方法不是抽象方法
public boolean equals(Object var1);
// default不是抽象方法
public default void defaultMethod(){
}
// static不是抽象方法
public static void staticMethod(){
}
}
public class LambdaTest {
public static void main(String[] args) {
LambdaOperation lambdaOperation;
lambdaOperation=(int x,int y)->x+y;
lambdaOperation=(int x,int y)->x-y;
lambdaOperation=(int x,int y)->x*y;
lambdaOperation=(int x,int y)->x/y;
lambdaOperation=(int x,int y)->x%y;
int result=lambdaOperation.test(1, 1);
System.out.println(result);
}
}
6.Lambda表达式个人总结
Lambda表达式是函数式编程的重要基础,Java作为OOP的老成员,如今拓展了函数式编程的Lambda,这无异于给了广大Java搬转者一个解决问题的思想。
技术是固定的,大家都会,唯一不同的就是每个人的思想,所以做出来的东西都是不同的。
其实我们作为程序搬运工,主要是解决程序中的问题,多个思想多种解决方法,择优则做,只要能够很好的解决当前的问题就是正确的方式,用的工具反而没有那么重要,就像对程序员来说语言不重要,重要的是解决问题的思想。所以我比较建议Java搬砖者多去练练Lambda表达式,多多拓展下自己的思维,这比学死技术要提升的更快。
最后,以上描述是个人花时间去学习和实践的成果,如有不对,请大家指出来,大家共同进步,谢谢,☺