Java Lambda表达式简介

Lambda

本文简单认识JDK8的重要新特性之一——Lambda表达式。 在JDK8之前,Java是不支持函数式编程的,所谓的函数编程,即可理解是将一个函数(也称为“行为”)作为一个参数进行传递。通常我们提及得更多的是面向对象编程,面向对象编程是对数据的抽象(各种各样的POJO类),而函数式编程则是对行为的抽象(将行为作为一个参数进行传递)。在JavaScript中这是很常见的一个语法特性,但在Java中将一个函数作为参数传递这却行不通,好在JDK8的出现打破了Java的这一限制。

通过创建一个线程来认识Lambda表达式

在JDK1.8之前,我们通常这样创建一个线程:

new Thread(new Runnable() {		
    @Override
    public void run() {
        System.out.println("hello innerclass!");
    }
}).start();

这段代码中,我们创建了一个实现了Runnable接口的匿名内部类对象,并将该对象作为参数传到Thread类的构造方法中,从而创建了一个线程。

下面展示一下如何通过Lambda表达式来创建一个线程:

new Thread(() -> System.out.println("hello lambda!")).start();

在这行代码中,我们通过一个Lambda表达式代替了传统的匿名内部类对象,代码简洁了很多。其中() -> System.out.println("hello lambda!")就是一个Lambda表达式。

从这个例子中可以看出,一个Lambda表达式包含以下三个部分:

  1. 最左边是一个(),表示该Lambda表达式的参数列表。

  2. 中间是Lambda操作符->(也叫箭头操作符)。

  3. 最右边是Lambda表达式中需要执行的功能函数体,即Lambda体。

    Lambda体可以是一行代码,也可以是代码块(即一对花括号包住的多行代码)。

比较上面两种创建线程的方法,可以发现有一个共同点,即都是通过调用Thread类的构造方法Thread(Runnable target)来创建的Thread对象。由此可以得到一个结论() -> System.out.println("hello lambda!")这个Lambda表达式本质上就是一个实现了Runnable接口的匿名内部类对象。

所以我们也可以将一个Lambda表达式赋给一个函数式接口类型的引用:

Runnable runnable = () -> System.out.println("hello lambda!");

那么什么样的接口才能转换成Lambda呢?

能够接收Lambda表达式的参数类型,是一个只包含一个抽象方法的接口。换句话说,只要是一个方法,其有一个参数的类型是只包含一个抽象方法的接口,那么,就可以传入一个Lambda表达式作为该方法的这个参数。

自定义一个函数式接口,并使用Lambda表达式进行参数传递

首先,先定义一个函数式接口:

public interface FunctionInterface {
	void function();
}

再定义一个方法,其参数类型为FunctionInterface类型:

public void func(FunctionInterface functionInterface) {
    functionInterface.function();
}

将Lambda表达式作为参数传入func(FunctionInterface functionInterface)方法,进行调用:

func(()-> System.out.println("lambda 实现functionInterface"));

可以看到,只要是一个接口中只包含一个抽象方法,则可以使用Lambda表达式,这样的接口称之为“函数式接口”。

关于函数式接口

Java 8为函数式接口引入了一个新注解@FunctionalInterface,主要用于编译级错误检查,加上该注解,编译器就会将该接口当成一个函数式接口,当你写的接口不符合函数式接口定义的时候,编译器会报错。

函数式接口是指有且只有一个抽象方法的接口,Object类中的public方法除外。换句话说就是,如果一个接口中除了重写的Object类中的public的抽象方法外,还有且仅有一个抽象方法,那么这个接口就是一个函数式接口。

什么叫Object类中的public方法除外呢?

举个例子,我们来看一下JDK8中的Comparator接口的源码:
在这里插入图片描述

从上图的源码中可以看到,Comparator接口中有两个抽象方法,但是它依然被@FunctionalInterface注解,也就是说它是符合函数式接口的概念。这是什么原因呢?这是因为equals方法是Object类中的public方法,在Comparator接口中重写了这个方法。这就是Object类中的public方法除外的意思。

Lambda表达式的几种形式

Java中的Lambda表达式主要有以下几种形式:

  1. 无参数无返回值

  2. 有参数无返回值

  3. 有参数有返回值

下面通过代码详细讲解:

  • 无参数,无返回值

    前面的两个例子都是无参数无返回值的例子,格式就是() -> System.out.println("hello lambda!")

  • 有参数,无返回值

    首先定义函数式接口,其抽象函数中声明了两个参数:

    public interface FunctionInterface {
    	void function(int x, int y);
    }  
    

    再定义一个方法来调用函数接口中定义的方法:

    public void func(FunctionInterface functionInterface) {
        int x = 1;
        int y = 2;
        functionInterface.function(x, y);
    }
    

    通过Lambda表达式进行调用:

    // 显示声明参数的数据类型
    func((int x, int y) -> System.out.println(x + y));
    // 也可以省略参数的数据类型
    func((x, y) -> System.out.println(x + y));
    

    从上面的例子可以看出,在使用Lambda表达式时,可以省略参数类型,编译器会根据上下文自动推断数据类型,当然有些情况下(比如定义函数式接口时的参数类型是一个泛型),编译器也不能推断出参数的数据类型,这时就会编译报错。

    当只有一个参数时,左边的小括号也是可以省略的,比如x -> System.out.println(x)

  • 有参数,有返回值

    先定义一个有参数有返回值的函数式接口:

    public interface FunctionInterface {
    	boolean function(int x, int y);
    }
    

    使用Lambda表达式调用:

    FunctionInterface fi = (x, y) -> {
        boolean b = x > y;
        return b;
    };
    System.out.println(fi.function(1, 2));
    

    就是这么简单,就是这么自然!!!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值