为何须要lambda 表达式java
函数对 Java 而言并不重要,在 Java 的世界里,函数没法独立存在。Lambda 表达式为 Java 添加了缺失的函数式编程特色,使咱们能将函数当作一等公民看待。尽管不彻底正确,咱们很快就会见识到 Lambda 与闭包的不一样之处,可是又无限地接近闭包。在支持一类函数的语言中,Lambda 表达式的类型将是函数。可是,在 Java 中,Lambda 表达式是对象,他们必须依附于一类特别的对象类型——函数式接口(functional interface)。express
什么是lambda 表达式编程
Java 中的 Lambda 表达式一般使用 (argument) -> (body) 语法书写,例如:闭包
(arg1, arg2...) -> { body } (type1 arg1, type2 arg2...) -> { body }
如下是一些 Lambda 表达式的例子:ide
(int a, int b) -> { return a + b; }函数式编程
() -> System.out.println("Hello World");函数
(String s) -> { System.out.println(s); }ui
() -> 42this
() -> { return 3.1415 };spa
让咱们了解一下 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表达式举例,
import java.util.Arrays; import java.util.Comparator; import java.util.List; public class LambdaTest { /** * (arg1, arg2...) -> { body } * <p> * (type1 arg1, type2 arg2...) -> { body } * * @param args */ public static void main(String[] args) { FunctionalWorkInterface.class.getName(); /** * lambda 表达式 */ Arrays.asList("a", "b", "d").forEach(e -> { System.out.print(e); }); Arrays.asList(1, 2, 8, 4, 5, 7).forEach(e -> System.out.println(e)); Arrays.asList("a", "b", "d").sort((e1, e2) -> e1.compareTo(e2)); List<Integer> arr = Arrays.asList(1, 2, 8, 4, 5, 7); /** * 定义一个lambda 表达式 * 集中不一样形式的 lambda 表达式定义方式 */ Comparator<Integer> comparator = (Integer a, Integer b) -> { return a.compareTo(b); }; arr.sort(comparator); arr.sort((a, b) -> { return a - b; }); // 不须要return arr.sort((a, b) -> a - b); arr.forEach(e -> System.out.println(e)); //旧方法: new Thread(new Runnable() { @Override public void run() { System.out.println("Hello from thread"); } }).start(); //新方法: new Thread( () -> System.out.println("Hello from thread") ).start(); } }
@FunctionalInterface是 Java 8 新加入的一种接口,用于指明该接口类型声明是根据 Java 语言规范定义的函数式接口。Java 8 还声明了一些 Lambda 表达式可使用的函数式接口,当你注释的接口不是有效的函数式接口时,会产生@FunctionalInterface 编译层面的错误。
好比 下面这个接口就是函数式接口java.util.Comparator ,
@FunctionalInterface public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); default Comparator<T> reversed() { return Collections.reverseOrder(this); } default Comparator<T> thenComparing(Comparator<? super T> other) { Objects.requireNonNull(other); return (Comparator<T> & Serializable) (c1, c2) -> { int res = compare(c1, c2); return (res != 0) ? res : other.compare(c1, c2); }; } default <U> Comparator<T> thenComparing( Function<? super T, ? extends U> keyExtractor, Comparator<? super U> keyComparator) { return thenComparing(comparing(keyExtractor, keyComparator)); } }
根据定义,函数式接口只能有一个抽象方法,若是你尝试添加第二个抽象方法,将抛出编译时错误。例如:
Error:(3, 1) java: 意外的 @FunctionalInterface 注释
com.common.FunctionalWorkInterface 不是函数接口
在 接口 com.common.FunctionalWorkInterface 中找到多个非覆盖抽象方法
存在多个抽象方法就会报错。
下面是 函数式接口 注解的用法
package com.common; /** * 使用函数式接口 注解标注一个接口 ,该接口只能有一个抽象方法。 */ @FunctionalInterface interface FunctionalWorkInterface { void doSomeWork(); } public class TestMain { public static void execute(FunctionalWorkInterface worker) { worker.doSomeWork(); } public static void main(String[] args) { //invoke doSomeWork using Annonymous class execute(new FunctionalWorkInterface() { @Override public void doSomeWork() { System.out.println("do some work..."); } }); //invoke doSomeWork using Lambda expression execute(() -> System.out.println("do some work from lambda...")); } }
这上面的例子里,建立了自定义的函数式接口并与 Lambda 表达式一块儿使用。
execute() 方法如今能够将 Lambda 表达式做为参数。
使用匿名类与 Lambda 表达式的一大区别在于关键词的使用。对于匿名类,关键词 this 解读为匿名类,而对于 Lambda 表达式,关键词 this 解读为写就 Lambda 的外部类。
Lambda 表达式与匿名类的另外一不一样在于二者的编译方法。Java 编译器编译 Lambda 表达式并将他们转化为类里面的私有函数,它使用 Java 7 中新加的 invokedynamic 指令动态绑定该方法。
import java.util.Arrays; import java.util.Comparator; import java.util.List; public class LambdaThisTest { public void sort(List<Integer> list) { list.sort((a, b) -> { System.out.print(this.getClass().getName()); return a.compareTo(b); }); } public void sort02(List<Integer> list) { list.sort(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { System.out.println(this.getClass().getName()); return o1.compareTo(o2); } }); } public static void main(String[] args) { LambdaThisTest lambdaThisTest = new LambdaThisTest(); lambdaThisTest.sort(Arrays.asList(1, 5, 6)); lambdaThisTest.sort02(Arrays.asList(1, 5, 6)); } }
输出,
com.common.LambdaThisTestcom.common.LambdaThisTestcom.common.LambdaThisTest$1
com.common.LambdaThisTest$1
===========END===========