Java | 函数式接口与Lambda表达式之间微妙的关系

Posted 唐山程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java | 函数式接口与Lambda表达式之间微妙的关系相关的知识,希望对你有一定的参考价值。

java是一种面向对象的语言,java中的一切都是对象,即数组,每个类创建的实例也是对象。在java中定义的函数或方法不可能完全独立,也不能将方法函数作为参数或返回值给实例。


在java7及以前,我们一直都是通过匿名内部类把方法或函数当做参数传递,如下是一个线程实例。


@Test public void testAnonymous() { new Thread(new Runnable() { @Override public void run() { System.out.println("匿名内部类"); } }).start(); }
输出结果为:“匿名内部类”

而在java8之后增加了一种语言特性,Lambda表达式。Lambda表达式为Java添加了缺失的函数式编程特点。而Lambda表达式是对象,它依赖于一个特别的类型-----函数式接口。


Lambda表达式语法:()-  >  {} 

接下来让我们了解一下 Lambda 表达式的结构。


  • 一个Lambda表达式可以有零个或多个参数;

  • 参数的类型既可以明确声明,也可以根据上下文来推断。例如:(int a)与(a)效果相同;

  • 所有参数需包含在圆括号内,参数之间用逗号相隔。例如:(a, b) 或 (int a, int b) 或 (String a, int b, float c);

  • 空圆括号代表参数集为空。例如:() -> 42;

  • 当只有一个参数,且其类型可推导时,圆括号()可省略。例如:a -> return a*a;

  • Lambda表达式的主体可包含零条或多条语句;

  • 如果Lambda表达式的主体只有一条语句,花括号{}可省略。匿名函数的返回类型与该主体表达式一致;

  • 如果Lambda表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中形成代码块)。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空。



简单介绍完Lambda表达式,接下来介绍一下函数式接口 

什么是函数式接口:

有且仅有一个抽象方法的接口称作函数式接口

例如:上述的Runnable就是一种函数式接口,其内部只有一个run方法


其中注解@FunctionalInterface 就是标注此接口为函数式接口的注释,当你接口不是函数式接口的时候,这个注解会帮你显式的表达出编译层面的错误,用以提示该接口不是函数式接口,如图:


Java | 函数式接口与Lambda表达式之间微妙的关系


上述线程代码可以更改为: 


@Testpublic void testAnonymous() { new Thread(() -> System.out.println("匿名内部类")).start();}
输出结果:“匿名内部类”


可以简单理解为,我们为run方法写了一个实现类,而run方法是无参的,所以()->

根据Lambda表达式特性,body中只有一条语句,我们可以省略{ }


所以最后结果为()-> System.out.println("匿名内部类").start( );


使用Lambda表达式的方法不止一种。在下面的例子中,我们先是用常用的箭头语法创建Lambda表达式,之后,使用Java 8全新的双冒号(::)操作符将一个常规方法转化为Lambda表达式:


@Test public void testAnonymous() { //传统for循环 List<Integer> list = Arrays.asList(1, 2, 3); for (Integer a : list) { System.out.println(a); }
//Lambda版-箭头语法 list.forEach(a -> System.out.println(a));
//Lambda版-双冒号语法 list.forEach(System.out::println);    }

三种运算方式输出结果一样,我们点进去看看forEach底层实现,看看forEach是如何实现的


Java | 函数式接口与Lambda表达式之间微妙的关系


可以看到forEach()中需要的不是常规的参数,而是Consumer<? super T >这个类型的参数,继续点进去看看Consumer是个什么类型


Java | 函数式接口与Lambda表达式之间微妙的关系

原来forEarch中的参数,是一个函数类型的,而他的抽象方法是一个T泛型,也就是说我们在用forEach的时候需要指定一个类型


所以forEarch写法为 forEach(类型 - > 实现 )


java8新推出的数据流中的map也是同样的原理,有兴趣的小伙伴自行测试。


最后总结:Lambda = ()- > {}  =  ::  (滑稽)



Java | 函数式接口与Lambda表达式之间微妙的关系




Java | 函数式接口与Lambda表达式之间微妙的关系
Java | 函数式接口与Lambda表达式之间微妙的关系 千家企业简历 快快加入我们带你飞~~
Java | 函数式接口与Lambda表达式之间微妙的关系
  Java | 函数式接口与Lambda表达式之间微妙的关系
在看点这里

以上是关于Java | 函数式接口与Lambda表达式之间微妙的关系的主要内容,如果未能解决你的问题,请参考以下文章

Java如何支持函数式编程?

Java之lambda表达式与函数式接口

Java8函数式编程:Lambda表达式类型与常用函数接口

lambda表达式与函数式(FunctionalInterface)接口

lambda表达式语法与函数式编程接口

初识函数式编程与函数式接口