Java8-1-初识Lambda表达式与函数式接口

Java8被称做Java史上变化最大的一个版本。其中包含不少重要的新特性,最核心的就是增长了Lambda表达式和Stream API。这二者也能够结合在一块儿使用。首先来看下什么是Lambda表达式。
Lambda表达式,维基百科上的解释是一种用于表示匿名函数和闭包的运算符,感受看到这个解释仍是以为很抽象,接下来咱们看一个例子java

public class SwingTest {
    public static void main(String[] args) {
        JFrame jFrame = new JFrame("My JFrame");
        JButton jButton = new JButton("My 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); 
    }
}

这是一段Swing编程中的代码,给Button绑定一个监听事件,当点击Button时会在控制台输出"Button Pressed!"内容。这里使用了建立了一个匿名内部类的实例来绑定到监听器,这也是以往比较常规的代码组织形式。可是仔细看一下咱们会发现,实际上咱们真正关注的就是一个ActionEvent类型的参数e和向控制台输出的语句System.out.println("Button Pressed!");。
若是将上段程序中以匿名内部类的方式建立接口实例的代码替换成Lambda表达式后,代码以下
public class SwingTest {编程

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

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

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

}
关注最中间部分代码的变化,由原来的6行代码,如今1行就能够实现了。这就是Lambda表达式的一种简单形式。
能够看出Lambda表达式的语法是
(param1,param2,param3) -> {segmentfault

//todo

}
这里参数的类型程序能够根据上下文进行推断,可是并非全部的类型均可以推断出来,此时就须要咱们显示的声明参数类型,当只有一个参数时小括号能够省略。当todo部分只有一行代码时,外边的大括号能够省略。如咱们上面的示例
那么除了代码简洁了,Lambda表达式还给咱们带来了什么变化吗?
咱们回忆一下,在Java中,咱们是否没法将函数做为参数传递给一个方法,也没法声明返回值是一个函数的方法。在Java8以前,答案是确定的。
那么,在上面的例子中咱们竟然能够将一段代码逻辑做为参数传递给了监听器,告诉监听器事件触发时你能够这么作,而再也不须要以匿名内部类的方式做为参数。这也是Java8带来的另外一新特性:函数式编程。
支持函数式编程的语言有不少,在JavaScript中,把函数做为参数传递,或者返回值是一个函数的状况很是常见,JavaScript是一门很是常见的函数式语言。
Lambda为Java添加了缺失的函数式编程的特性,使咱们能将函数当作一等公民看待。
在函数式编程语言中,Lambda表达式的类型是函数。而在Java中,Lambda表达式是对象,它们必须依附于一类特别的对象类型——函数式接口(Functional Interface)
接下来咱们看下函数式接口的定义:
若是一个接口中,有且只有一个抽象的方法(Object类中的方法不包括在内),那这个接口就能够被看作是函数式接口。闭包

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

来看下Runnable接口的声明,在Java8后,Runnable接口多了一个FunctionalInterface注解,表示该接口是一个函数式接口。可是若是咱们不添加FunctionalInterface注解的话,若是接口中有且只有一个抽象方法时,编译器也会把该接口当作函数式接口看待。编程语言

@FunctionalInterface
public interface MyInterface {
    void test();
    String toString();
}

MyInterface这也是一个函数式接口,由于toString()是Object类中的方法,只是在这里进行了复写,不会增长接口中抽象方法的数量。
(到这里额外提一下,Java8中,接口里面的方法不单单只能有抽象方法,也能够有具体实现了的方法,被称做默认方法(default method),这部分后面会具体介绍)
既然在Java中,Lambda表达式是对象。那么这个对象的类型是什么呢?咱们再回顾下SwingTest程序,这里以匿名内部类的方式建立了一个ActionListener接口实例ide

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

使用Lambda表达式改进后函数式编程

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

也就是咱们使用Lambda表达式建立了一个ActionListener接口的实例,再看下ActionListener接口的定义函数

public interface ActionListener extends EventListener {
    /**
     * Invoked when an action occurs.
     */
    public void actionPerformed(ActionEvent e);
}

只有一个抽象方法,虽然没添加FunctionalInterface注解,可是也符合函数式接口的定义,编译器会认为这是一个函数式接口。
因此,使用Lambda表达式能够建立函数式接口的实例。即Lambda表达式返回的是函数式接口类型。
实际上,函数式接口实例的建立能够有三种方式(参考自FunctionalInterface注解说明):
1.Lambda表达式
2.方法引用(后续章节介绍)
3.构造方法引用(后续章节介绍)学习

小结:本篇咱们打开了学习Java8的大门,认识了什么是lambda表达式,了解了函数式接口的定义是什么,并借住几个例子展现了lambda表达式的便捷之处,若是以为本篇文章对你有所帮助帮忙赞一下哈。code

下一篇

相关文章
相关标签/搜索