首页 > 技术文章 > lambda表达式

brilliantl 2019-05-16 16:46 原文

lambda表达式

lambda表达式是什么?

lambda是一个操作符,用于表示匿名函数或闭包

为什么要用lambda表达式

在java8之前,我们的参数或者返回类型只能是原生的数据类型或者一个对象的引用。我们无法将函数作为一个参数传递给一个方法,也无法声明返回一个函数的方法
函数式编程是对行为的操作,lambda可以将方法作为参数进行传递

怎么使用lambda表达式

Lambda表达式常见的语法结构:(Param1,param2,param3)->{......}
先来看一个使用lambda的示例,我们发现在使用了lambda表达式之后,代码变得更简洁了,更容易理解了。我们要学习java的lambda表达式,首先要了解java8新出来的函数式接口。

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * @author lwy
 * @date 2019/4/25
 */
public class SwingTest {

    public static void main(String[] args) {
        JFrame jframe = new JFrame("My JFrame");
        JButton jButton = new JButton("My Button");
        
        //使用匿名内部类
//        jButton.addActionListener(new ActionListener() {
//            @Override
//            public void actionPerformed(ActionEvent e) {
//                System.out.println("Button Pressed");
//            }
//        });
        
        //使用lambda表达式
//        jButton.addActionListener( (ActionEvent e) -> System.out.println("Button Pressed"));
        jButton.addActionListener(e -> System.out.println("Button Pressed"));

        jframe.add(jButton);
        jframe.pack();
        jframe.setVisible(true);
        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

函数式接口

FunctionalInterface接口源码:

package java.lang;

import java.lang.annotation.*;

/**
 * An informative annotation type used to indicate that an interface
 * type declaration is intended to be a <i>functional interface</i> as
 * defined by the Java Language Specification.
 *
 * Conceptually, a functional interface has exactly one abstract
 * method.  Since {@linkplain java.lang.reflect.Method#isDefault()
 * default methods} have an implementation, they are not abstract.  If
 * an interface declares an abstract method overriding one of the
 * public methods of {@code java.lang.Object}, that also does
 * <em>not</em> count toward the interface's abstract method count
 * since any implementation of the interface will have an
 * implementation from {@code java.lang.Object} or elsewhere.
 *
 * <p>Note that instances of functional interfaces can be created with
 * lambda expressions, method references, or constructor references.
 函数式接口的实例可以被lambda表达式,方法引用,或构造器引用 创建。
 *
 * <p>If a type is annotated with this annotation type, compilers are
 * required to generate an error message unless:
 *
 * <ul>
 * <li> The type is an interface type and not an annotation type, enum, or class.
 * <li> The annotated type satisfies the requirements of a functional interface.
 * </ul>
 *
 * <p>However, the compiler will treat any interface meeting the
 * definition of a functional interface as a functional interface
 * regardless of whether or not a {@code FunctionalInterface}
 * annotation is present on the interface declaration.
 *
 * @jls 4.3.2. The Class Object
 * @jls 9.8 Functional Interfaces
 * @jls 9.4.3 Interface Method Body
 * @since 1.8
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

通过查看函数式接口源码,我们可以得知函数接口的定义:

  1. 如果一个接口只有一个抽象方法(
    注意:
    a. Java8中接口可以有默认方法,默认方法不属于抽象方法。
    b. 要是接口重写了java.lang.Object的方法,那么这个方法不不计入抽象方法数目。因为任何接口的任何实现都有实现Object),那么该接口就是一个函数式接口
  2. 如果我们在某个接口上声明了FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口,要是不符合会报错。
  3. 如果某个接口只有一个抽象方法,但我们并没有给该接口声明FunctionalInterface注解,那么编译器依旧会将该接口看作是函数式接口

lambda表达式的作用

  1. 为java添加了缺失的函数式编程特性,使我们能将函数当做一等公民看待,但是要注意在将函数当做一等公民的语言中,lambda表达式的类型是函数,但在java中,lambda表达式是对象,他们必须依附于一类特别的对象类型-函数式接口(functional interface)

注意事项

lambda表达式的语法结构为:
(参数)-> {主体}

  1. 一个lambda表达式可以有零个或者多个参数
  2. 参数的类型既可以明确声明,也可以根据上下文来推断。例如:(int a) == (a)
  3. 所有参数需要包括在圆括号中,参数之间用逗号相隔。例如:(a,b)或(int a,int b)
  4. 空圆括号代表参数集为空。
  5. 当只有一个参数时,且其类型推导时,圆括号()可以省略。例如:a->return a+a
  6. lambda表达式的主体可以包含零条或者多条语句,如果lambda表达式的主体只有一条语句时,花括号{}可以省略,匿名函数的返回值类型与该主体表达式一致。
  7. 如果lambda表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中,行成代码块。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空。

推荐阅读