在 Java 版本的历次更新迭代中,Java8 是一个特殊的存在,与以往的版本升级不同。我们对 Java8 似乎抱有更大的期待,因为它是 Java5 之后最重要的一次升级,提供了十多个新特性,其中 Lambda 表达式是 Java8 新特性中最重要的一个。
Lambda 表达式允许开发者将函数作为参数传给某个方法,即支持函数式编程,这并不是一种新技术,很多基于 JVM 的语言如 Groovy 和 Scala 都支持函数式编程,Java 官方直到 Java8 才引入函数式编程机制。在 Java8 诞生之前,开发者更多的关注点在于对象的属性,这也是面向对象编程思想的核心,即对数据进行抽象,而函数式编程则是对行为进行抽象,是面向函数进行编程。
Java8 通过引入 Lambda 表达式来支持函数式编程,Lambda 表达式允许我们将一个函数作为参数进行传递,一个函数定义了一个行为,语法如下所示。
(参数) -> (方法体)
我们首先通过一个例子来直观理解什么是 Lambda 表达式:启动一个线程,不使用 Lambda 表达式的代码如下所示。
new Thread(new Runnable() { @Override public void run() { System.out.println("do it...""); }}).start();
使用 Lambda 表达式的代码如下所示。
new Thread(()-> System.out.println("do it...")).start();
new Thread() 中传递的就是一个函数,它定义了线程的具体任务,即行为。通过对比可以得出结论,使用 Lambda 表达式可以替代传统的匿名类开发方式,不需要创建匿名类即可完成业务逻辑的代码编写,开发效率更高。
Lambda 表达式由 3 部分组成:1、参数。2、->。3、函数主体。
这里需要注意,能够使用 Lambda 表达式的必须是一个函数接口,函数接口是指该接口中只包含一个方法,如 Runnable 接口。
@FunctionalInterfacepublic interface Runnable { /** * When an object implementing interfaceRunnable
is used * to create a thread, starting the thread causes the object's *run
method to be called in that separately executing * thread. *
* The general contract of the method run
is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run();}
如果一个接口中包含超过两个方法,则不能使用 Lambda 表达式,接下来我们介绍几种常用的函数接口类型。
1、没有参数、没有返回值的函数接口
public interface MyInterface { public void test();}
具体使用如下所示,定义一个 test 方法,将函数接口作为参数传入。
public class Test { public static void main(String[] args) { Test test = new Test(); //不使用Lambda表达式 test.test(new MyInterface() { @Override public void test() { System.out.println("123"); } }); //使用Lambda表达式 test.test(()-> System.out.println("333")); } public void test(MyInterface myInterface){ myInterface.test(); }}
运行结果如下图所示。
2、带参数的函数接口
public interface MyInterface { public void test(int x);}
具体使用如下所示。
public class Test { public static void main(String[] args) { Test test = new Test(); test.test((int x)-> System.out.println("传入的参数是:"+x)); } public void test(MyInterface myInterface){ int x = 10; myInterface.test(x); }}
运行结果如下图所示。
参数的数据类型也可以不声明,根据上下文自动获取,如下所示。
test.test((int x)-> System.out.println("传入的参数是:"+x));等于test.test((x)-> System.out.println("传入的参数是:"+x));
3、有返回值的函数接口
public interface MyInterface { public boolean test();}
具体使用如下所示。
public class Test { public static void main(String[] args) { Test test = new Test(); test.test(()-> true); } public void test(MyInterface myInterface){ System.out.println(myInterface.test()); }}
运行结果如下图所示。
4、有参数、有返回值的函数接口
public interface MyInterface { public int test(int x,int y);}
具体使用如下所示。
public class Test { public static void main(String[] args) { Test test = new Test(); test.test((int x,int y)-> x+y); } public void test(MyInterface myInterface){ int x = 10; int y = 20; System.out.println("10和20之和是:"+myInterface.test(x,y)); }}
运行结果如下图所示。
如果函数接口的方法体只有一条语句,可省略 {},如下所示。
test.test((int x,int y)-> x+y);
如果函数接口的方法体包含多条语句,需要在 {} 中添加相关语句,如下所示。
test.test((int x,int y)-> { System.out.println("参数是:"+x+