Lambda Expression的表达形式
这篇文章继续和大家聊聊Java 8里面的Lambda表达式。
下面这段代码展示了Lambda表达式里面几种要素:
import java.util.ArrayList;
import java.util.List;
public class PlayWithCollections {
public static void main(String[] args) {
List<String> list = new ArrayList();
list.add("x");
list.add("y");
list.add("z");
list.forEach(System.out::println);
list.forEach(str -> {
String out = str.toUpperCase();
System.out.println(out);
});
}
}
上面的代码里,使用了List
的forEach()
方法。下面的代码是List
的forEach()
方法的实现代码:
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
可以看到,这个方法接受一个Consumer
类型的参数action
,然后遍历List自身内部的元素elementData
,把这些元素逐一传递给action
的accept()
方法。
可以看出Consumer
是一个functional interface,就是只定义了单一方法的interface。下面是Java标准库中Consumer
接口的代码:
package java.util.function;
import java.util.Objects;
/**
* Represents an operation that accepts a single input argument and returns no
* result. Unlike most other functional interfaces, {@code Consumer} is expected
* to operate via side-effects.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #accept(Object)}.
*
* @param <T> the type of the input to the operation
*
* @since 1.8
*/
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* Returns a composed {@code Consumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
上面的代码里,不需要关心andThen()
方法,可以看到它标记了default
属性。这个是Java 1.8
版本中新加入的语言特性,可以允许直接在interface里面实现这个方法1。
在这个Consumer
里面,Lambda expression会作为参数传入到accept(T t)
方法当中。
回到我们自己的代码,可以把一个函数传入:
list.forEach(System.out::println);
因为println(String x)
方法满足Consumer
的accept(T t)
接口定义:
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
所以可以用上面的双引号的形式直接传入。我们也可以定义自己的逻辑:
list.forEach(str -> {
String out = str.toUpperCase();
System.out.println(out);
});
如上所示,我们构造了一个接受单一参数str
的匿名函数,这个函数的逻辑直接写在了大括号里面。这样Java编译器会创建一个Consumer
的anonymous class的实现,并且用上面这个函数的逻辑作为accept(String t)
方法的实现。
-
关于
default method
,可以参考Oracle的文档说明:https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html ↩