java8 lambda表达式与函数式接口

709 阅读2分钟

序言

虽然平时在写代码的时候会用java8的部分语法,比如最常用的集合类的stream、map、forEach等,但也就停留在差不多会用的阶段,有时候碰上复杂一点的集合处理还得网上查一下。所以决定把java8相关的语法升级在从头学一下。

lambda表达式

写java代码,在java8以前,没有lambda表达式的时候,很多都是以内部类的方式来处理的。最常见的就是事件处理,例如:

public class SwingTest {

    public static void main(String[] args) {
        JFrame jFrame = new JFrame("juejin");
        JButton jButton = new JButton("掘金");

        jButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Button Pressed!");
            }
        });

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

效果如下:

WeChatc69e093edef669ff6d429a2bd12fd3b8.png 当我们点击掘金这个大Button的时候,就会执行actionPerformed对应的方法。当对我们来说,整个内部类中,我们需要的就是 System.out.println("Button Pressed!");这一句话。 通过lambda表达式,我们可以简写成如下形式:

jButton.addActionListener(e -> System.out.println("Button Pressed!"));

一句话就解决问题,简洁了很多。 lambda表达式的基本结构:
(param1, param2, param3) -> {

}

函数式接口

先上代码:

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
    list.forEach(new Consumer<Integer>() {
        @Override
        public void accept(Integer i) {
            System.out.println(i);
        }
    });
}

forEach接收参数 Consumer,从源码中我们可以看到Consumer有一个@FunctionalInterface注解。

@FunctionalInterface就表示函数式接口。
关于函数式接口:

  1. 如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口。
  2. 如果我们在某个接口上声明了FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口。
  3. 如果某个接口只有一个抽象方法,但我们并没有给该接口声明FunctionalInterface注解,那么编译器依旧会将该接口看作是函数式接口。
  • Lambda表达式作用
    • Lambda表达式为Java添加了缺失的函数式编程特性,使我们能将函数当做一等公民看待
    • 在将函数作为一等公民的语言中, Lambda表达式的类型是函数。但在Java中, Lambda表达式是对象,他们必须依附于一类特别的对象类型—函数式接口(functional interface)

自定义一个函数式接口并调用:

public class Test2 {

    public void myTest(MyInterface myInterface) {
        System.out.println("------------------");
        myInterface.test();
        System.out.println("------------------");
    }

    public static void main(String[] args) {
        Test2 test2 = new Test2();

        test2.myTest(new MyInterface() {
            @Override
            public void test() {
                System.out.println("mytest");
            }
        });

        test2.myTest(() -> System.out.println("mytest"));
    }

}

函数式接口的实例可以通过lambda表达式、方法引用、构造方法引用来创建。
Note that instances of functional interfaces can be created with lambda expressions, method references, or constructor references.