JAVA 搬砖人生所经历的事件系列之一(Java8中Lambda表达式)

前言:小编我刚刚完成了跳槽,正在新公司无所事事,就开始自学寻坑之路。以后还会发发主流框架,主流插件,反正什么主流我都不会(你咬我啊!!!)最新的java9都已经铺天盖地了,小编我可是连java8都还没去看过,所以我一直在底层过着搬砖人的日子。言归正传。本章主要讲了Java8新特征的Lambda表达式。

简介:

  1. 什么是Lambda表达式?
  2. Lambda表达式在Java8实现
  3. 什么是FunctionInterface 函数式接口?
  4. 目标类型(Target Typing)
  5. 实践简简单单加减运算代码栗子☺
  6. 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 这个可写可不写

注意点:

  1. 如果要写lambda表达式,接口尽量加上@FunctionalInterface注解,它能保证接口有且只有一个抽象方法
  2. 默认方法和静态方法不会破坏函数式接口的定义。
  3. 接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
  4. 如果一个接口符合”函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@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表达式,多多拓展下自己的思维,这比学死技术要提升的更快。

最后,以上描述是个人花时间去学习和实践的成果,如有不对,请大家指出来,大家共同进步,谢谢,☺

    原文作者:IamBOBO
    原文地址: https://zhuanlan.zhihu.com/p/30699832
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞