Java8 Lambda表达式教程

分手后的思念是犯贱 2023-09-29 15:11 132阅读 0赞

1. 什么是λ表达式

λ表达式本质上是一个匿名方法。让我们来看下面这个例子:

public int add(int x, int y) {
return x + y;
}

转成λ表达式后是这个样子:

(int x, int y) -> x + y;

参数类型也可以省略,Java编译器会根据上下文推断出来:

(x, y) -> x + y; //返回两数之和

或者

(x, y) -> { return x + y; } //显式指明返回值

可见λ表达式由三部分组成:参数列表,箭头(->),以及一个表达式或语句块。

下面这个例子里的λ表达式没有参数,也没有返回值(相当于一个方法接受0个参数,返回void,其实就是Runnable里run方法的一个实现):

() -> { System.out.println(“Hello Lambda!”); }

如果只有一个参数且可以被Java推断出类型,那么参数列表的括号也可以省略:

list-> { return list.size(); }

2. λ表达式的类型(它是Object吗?)

λ表达式可以被当做是一个Object(注意措辞)。λ表达式的类型,叫做“目标类型(target type)”。λ表达式的目标类型是“函数式接口(functional interface)”,这是Java8新引入的概念。它的定义是:一个接口,如果只有一个显式声明的抽象方法,那么它就是一个函数式接口。一般用@FunctionalInterface标注出来(也可以不标)。举例如下:

@FunctionalInterface
public interface Runnable { void run(); }

public interface Callable { V call() throws Exception; }

public interface ActionListener { void actionPerformed(ActionEvent e); }

public interface Comparator { int compare(T o1, T o2); boolean equals(Object obj); }

注意最后这个Comparator接口。它里面声明了两个方法,貌似不符合函数式接口的定义,但它的确是函数式接口。这是因为equals方法是Object的,所有的接口都会声明Object的public方法——虽然大多是隐式的。所以,Comparator显式的声明了equals不影响它依然是个函式数接口。

你可以用一个λ表达式为一个函数式接口赋值:

Runnable r1 = () -> {System.out.println(“Hello Lambda!”);};

然后再赋值给一个Object:

Object obj = r1;

但却不能这样干:

Object obj = () -> {System.out.println(“Hello Lambda!”);}; // ERROR! Object is not a functional interface!

必须显式的转型成一个函数式接口才可以:

Object o = (Runnable) () -> { System.out.println(“hi”); }; // correct

一个λ表达式只有在转型成一个函数式接口后才能被当做Object使用。所以下面这句也不能编译:

System.out.println( () -> {} ); //错误! 目标类型不明

必须先转型:

System.out.println( (Runnable)() -> {} ); // 正确

假设你自己写了一个函数式接口,长的跟Runnable一模一样:

@FunctionalInterface
public interface MyRunnable {
public void run();
}

那么

Runnable r1 = () -> {System.out.println(“Hello Lambda!”);};
MyRunnable2 r2 = () -> {System.out.println(“Hello Lambda!”);};

都是正确的写法。这说明一个λ表达式可以有多个目标类型(函数式接口),只要函数匹配成功即可。
但需注意一个λ表达式必须至少有一个目标类型。

JDK预定义了很多函数式接口以避免用户重复定义。最典型的是Function:

@FunctionalInterface
public interface Function {
R apply(T t);
}

这个接口代表一个函数,接受一个T类型的参数,并返回一个R类型的返回值。

另一个预定义函数式接口叫做Consumer,跟Function的唯一不同是它没有返回值。

@FunctionalInterface
public interface Consumer {
void accept(T t);
}

发表评论

表情:
评论列表 (有 0 条评论,132人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java 8-Lambda表达式

    行为参数化 行为参数化:让方法接受多种行为作为参数,并在内部使用,来完成不同的行为。 行为参数化可让代码更好地适应不断变化的要求,减轻未来的工作量。 传递代码,就

    相关 Java 8 Lambda 表达式

      最近频繁的看到一个技术:Lambda 表达式   貌似下个项目要用到这个技术,就来学习一下。   `Java8`新特性引入了一个新的操作符`->`

    相关 Java 8 Lambda 表达式

    Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。 Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。 使用 Lamb...