什么是Lambda表达式?java
在如 Lisp、Python、Ruby 编程语言中,Lambda 是一个用于表示匿名函数或闭包的运算符编程
为什么须要lambda表达式?闭包
- 在 Java 中,咱们没法将函数做为参数传递给一个方法,也没法声明返回一个函数的方法。
- 在 JavaScript 中,函数参数是一个函数,返回值是另外一个函数的状况是很是常见的;JavaScript 是一门很是典型的函数式语言。
看以下匿名内部类实例:编程语言
1 import javax.swing.*; 2 import java.awt.event.ActionEvent; 3 import java.awt.event.ActionListener; 4 5 public class SwingTest { 6 public static void main(String[] args) { 7 JFrame jFrame = new JFrame("My JFrame"); 8 JButton jButton = new JButton("My Button"); 9 // 匿名内部类 10 jButton.addActionListener(new ActionListener() { 11 @Override 12 public void actionPerformed(ActionEvent e) { 13 System.out.println("Button Pressed"); 14 } 15 }); 16 jFrame.add(jButton); 17 jFrame.pack(); 18 jFrame.setVisible(true); 19 jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 20 } 21 }
如上代码很简单,经过第 10 行给第 8 行的按钮注册了一个监听器。而咱们知道,当事件触发真正起做用的其实是执行第 12 行的 actionPerformed 方法,为此咱们建立了 ActionListener 实例。ide
而 Lambda 表达式可让咱们只专一于方法的实现,在注册监听器时咱们能够忽略具体须要建立哪一个类型的实例。其实在 Idea 中自己就已经给咱们提示了,以下:函数式编程
即匿名内部类的写法是能够用 Lambda 表达式替换的,以下:函数
1 import javax.swing.*; 2 3 public class SwingTest { 4 public static void main(String[] args) { 5 JFrame jFrame = new JFrame("My JFrame"); 6 JButton jButton = new JButton("My Button"); 7 // Lambda 表达式 8 jButton.addActionListener(event -> System.out.println("jButton Pressed")); 9 jFrame.add(jButton); 10 jFrame.pack(); 11 jFrame.setVisible(true); 12 jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 13 } 14 }
在例 2 中经过第 8 行的 Lambda 表达式替换了例 1 中 10-15 行的匿名内部类写法,不只代码更简洁,并且含义更直观明了。ui
在 Java 8 中 Lambda 表达式最原始的写法以下:this
(类型 prarm1,类型 param2,类型 param3, ...) -> { // 方法体 }
能够将参数类型省略,编译器可自动推断:spa
(prarm1, param2, param3, ...) -> { // 方法体 }
若是只有一个参数,还能够省略小括号:
prarm1 -> { // 方法体 }
若是方法体只有一行代码,那么大括号也能够省略:
prarm1 -> <方法实现>
用例 2 中的 Lambda 为例演变过程以下:
// 原始写法 jButton.addActionListener((ActionEvent event) -> { System.out.println("jButton Pressed"); }); // 省略参数类型 jButton.addActionListener((event) -> { System.out.println("jButton Pressed"); }); // 省略小括号 jButton.addActionListener(event -> { System.out.println("jButton Pressed"); }); // 省略大括号 jButton.addActionListener(event -> System.out.println("jButton Pressed"));
在 Java 8 中, Iterable 接口中新增了一个默认函数 forEach 让咱们能够更方便的遍历它:
1 package java.lang; 2 3 import java.util.Iterator; 4 import java.util.Objects; 5 import java.util.Spliterator; 6 import java.util.Spliterators; 7 import java.util.function.Consumer; 8 9 public interface Iterable<T> { 10 Iterator<T> iterator(); 11 12 default void forEach(Consumer<? super T> action) { 13 Objects.requireNonNull(action); 14 for (T t : this) { 15 action.accept(t); 16 } 17 } 18 19 default Spliterator<T> spliterator() { 20 return Spliterators.spliteratorUnknownSize(iterator(), 0); 21 } 22 }
能够看到它接收一个 java.util.function.Consumer 类型参数,查看 JavaDoc:
该类上标注了一个 @FunctionalInterface 注解,而且注释中还说明了这个接口是一个函数式接口。查看该注解的 JavaDoc:
能够得到以下信息:
看以下示例:
package zze.java8; @FunctionalInterface interface MyInterface { void test(); } public class Test2 { public void test(MyInterface myInterface) { System.out.println("Test2.test"); myInterface.test(); } public static void main(String[] args) { Test2 test2 = new Test2(); test2.test(() ->System.out.println("MyInterface.test")); /* * Test2.test * MyInterface.test */ } }
能够看到, Test2 的实例方法 test 其实是接收一个 MyInterface 对象,而 MyInterface 是一个函数式接口,因此咱们能够经过传入 Lambda 表达式做为 myInterface 参数,即:此时传入的 Lambda 表达式就是对函数函数式接口 MyInterface 的实现对象。因此上面代码其实也能够修改成以下:
Test2 test2 = new Test2(); MyInterface myInterface = () -> System.out.println("MyInterface.test"); test2.test(myInterface); System.out.println(myInterface.getClass()); System.out.println(myInterface.getClass().getSuperclass()); System.out.println(myInterface.getClass().getInterfaces()[0]); /* Test2.test MyInterface.test class zze.java8.Test2$$Lambda$1/990368553 class java.lang.Object interface zze.java8.MyInterface */
总结: