Java8 lambda 入门

147 阅读4分钟

1.基本介绍

    java 8中一个非常重要的新特性就是lambda表达式,它允许把函数当作参数来使用,是面向函数式编程的一种思想。Lambda 表达式是一种匿名函数(对 Java 而言这并不完全正确,但现在姑且这么认为),简单地说,它是没有声明的方法,也即没有访问修饰符、返回值声明和名字。 

2.为什么java需要lambda

    在函数式编程语言中,函数是一等公民,它们可以独立存在,你可以将其赋值给一个变量,或将他们当做参数传给其他函数。函数式语言提供了一种强大的功能——闭包,相比于传统的编程方法有很多优势,闭包是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。Java 现在提供的最接近闭包的概念便是 Lambda 表达式,虽然闭包与 Lambda 表达式之间存在显著差别,但至少 Lambda 表达式是闭包很好的替代者。  

    Lambda 表达式为 Java 添加了缺失的函数式编程特点,使我们能将函数当做一等公民看待。但是,在 Java 中,Lambda 表达式是对象,他们必须依附于一类特别的对象类型——函数式接口(functional interface),这个将在下面介绍。 

 3.基本表达式

(args) -> expression; 
(args) -> { 
            statment1; 
            .... 
            return statment; 
           } 

 4.lambda表达式的重要特征

可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。 
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。 
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。 
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。 

5.一个简单的例子

/**
 * @author wangC
 * @version 1.0
 * @date 2020/10/24 17:46
 */
public class LambdaTest {

    public static void main(String[] args){
        //相当于是创建了一个 MathInterface 的实现对象 
        //lambda表达式对应的是MathInterface#evaluate的实现方法,使用add.evaluate 来进行调用
        MathInterface add = (x,y) -> x+y;
        MathInterface substract = (x,y) -> x-y;
        MathInterface multiply = (x,y) -> x*y;
        MathInterface divide = (x,y) -> x/y;

        System.out.println(add.evaluate(1,2));
        System.out.println(substract.evaluate(10,5));
        System.out.println(multiply.evaluate(2,3));
        System.out.println(divide.evaluate(9,3));

        HumanInterface wangC = name -> System.out.println("hai "+ name);
        wangC.sayHai("wangC");
    }
}

/**
 * 函数式接口:函数式接口是只包含一个方法的接口。
 */

/**
 * 创建方法有返回值的函数式接口
 */
@FunctionalInterface
interface MathInterface{
    int evaluate(int x,int y);
}

/**
 * 创建方法无返回值的函数式接口
 */
@FunctionalInterface
interface HumanInterface{
    void sayHai(String name);
}

结果

3
5
6
3
hai wangC

6.lambda与1.7写法的比较

public class CompareTest {

    public static void main(String[] args){
        //匿名内部类的替换
        //原有的写法
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("in inner class version.");
            }
        }).start();
        //lambda 的写法
        new Thread(() -> System.out.println("in lambda version.")).start();

        //lambda 表达式只能引用标记了 final 的外层局部变量,
        // 这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
        final String msg = "lambda 表达式只能引用标记了 final 的外层局部变量";
        PrintInterface print = () -> System.out.println(msg);
        print.printSomething();

        String msg2 = "使用 Java 8 全新的双冒号(::)操作符将一个常规方法转化为 Lambda 表达式";
        PrintBInterface pringB = System.out::println;
        pringB.printSomething(msg2);
    }
}

@FunctionalInterface
interface PrintInterface{
    void printSomething();
}

@FunctionalInterface
interface PrintBInterface{
    void printSomething(String message);
}

结果:

in inner class version.
in lambda version.
lambda 表达式只能引用标记了 final 的外层局部变量
使用 Java 8 全新的双冒号(::)操作符将一个常规方法转化为 Lambda 表达式

7.lambda与匿名内部类的区别

    a.使用匿名类与 Lambda 表达式的一大区别在于关键词的使用。对于匿名类,关键词 this 解读为匿名类,而对于 Lambda 表达式,关键词 this 解读为写就 Lambda 的外部类。 

    b.Lambda 表达式与匿名类的另一不同在于两者的编译方法。Java 编译器编译 Lambda 表达式并将他们转化为类里面的私有函数,它使用 Java 7 中新加的 invokedynamic 指令动态绑定该方法。