lambda 表达式
lambda 表达式为统一实现接口提供了一个干净而又简洁的表达方式。它可以减少你代码篇幅。当用作匿名函数使用时,可忽略掉类型,作为推导则需要声明类型。
用方法实现函数接口,对已经存在的方法表示,也隶属于lanbda家族。
举例
介绍java的lambda表达式
函数接口
lambda只能使用在函数接口,替代接口和抽象方法。
interface Foo1 {
void bar();
}
interface Foo2 {
int bar(boolean baz);
}
interface Foo3 {
String bar(Object baz, int mink);
}
interface Foo4 {
default String bar() { // default so not counted
return "baz";
}
void quux();
}
使用注解@FunctionalInterface声明的函数接口,使用在非函数接口上时会编译报错,提示接口不能被改变。
@FunctionalInterface
interface Foo5 {
void bar();
}
@FunctionalInterface
interface BlankFoo1 extends Foo3 { // inherits abstract method from Foo3
}
@FunctionalInterface
interface Foo6 {
void bar();
boolean equals(Object obj); // overrides one of Object's method so not counted
}
相反,这不是一个函数接口,因为它有多个抽象方法:
interface BadFoo {
void bar();
void quux(); // <-- Second method prevents lambda: which one should
// be considered as lambda?
}
这也不是一个函数接口,因为它没有任何方法:
interface BlankFoo2 { }
下面的笔记,你将有意外的收获:
interface Parent { public int parentMethod(); }
和
interface Child extends Parent { public int ChildMethod(); }
java8也提供了很多模板函数接口在java.util.function包里。例如,这个 built-in 接口Predicate<T>包裹着一个单利方法为输入的值的类型T并返回一个boolean值
lambda 表达式的基本结构
fi持有一个类的接口,类似于匿名类。实现FunctionalInterface并声明一个方法System.out.println("Hello");}。换句话说,它等价于:
FunctionalInterface fi = new FunctionalInterface() {
@Override
public void theOneMethod() {
System.out.println("Hello");
}
};
当前的lambda仅等价于一个匿名类,这意味着表达式中像this,super或者toString()参照这个类里的分配,不创建实体。
当使用lambda时你不能指定方法的名字,当然你不需要他,因为一个函数接口必须只能有一个抽象方法,因此java overrides 它。
在lambda的类型不确定的情况下, (e.g. overloaded methods)你应该添加强制转换去告诉编译器应该是什么类型,例如:
Object fooHolder = (Foo1) () -> System.out.println("Hello");
System.out.println(fooHolder instanceof Foo1); // returns true
如果函数接口单一方法传参,本地匹配名称应放在lambda的花括号中。这里不需要声明参数或者返回从接口(如果你证明,也不会报错)。因此,下面的两个例子是等价的:
Foo2 longFoo = new Foo2() {
@Override
public int bar(boolean baz) {
return baz ? 1 : 0;
}
};
Foo2 shortFoo = (x) -> { return x ? 1 : 0; };
如果函数只有一个参数,可以省略括号:
Foo2 np = x -> { return x ? 1 : 0; }; // okay
Foo3 np2 = x, y -> x.toString() + y // not okay
隐式返回
如果lambda用作表达另一段代码,它被当作表达式的返回值,因此下面两个例子等价:
IntUnaryOperator addOneShort = (x) -> (x + 1);
IntUnaryOperator addOneLong = (x) -> { return (x + 1); };
lambda作为匿名函数的速记语法,它们接受本地局部变量语法相同。这些变量被指定final并且不能够在lambda内修改。
IntUnaryOperator makeAdder(int amount) {
return (x) -> (x + amount); // Legal even though amount will go out of scope
// because amount is not modified
}
IntUnaryOperator makeAccumulator(int value) {
return (x) -> { value += x; return value; }; // Will not compile
}
如果必须在花括号里改变变量,使用一个对象拷贝变量值。
接受lambda
因为一个lambda实现一个接口,没有必要创建一个方法接受lambda,lambda可接受任何函数接口。
public void passMeALambda(Foo1 f) {
f.bar();
}
passMeALambda(() -> System.out.println("Lambda called"));
lammbda表达式类型
一个lambda表达式,针对它自己,并没有一个特殊的类型。然而它真实的类型和参数,沿用返回值传递类型信息,这样信息被强制转换,lambda在接受一个一个函数接口时被指定类型在下文方法中:
Predicate<String> javaStringPred = o -> o.isEmpty();
Function<String, Boolean> javaFunc = o -> o.isEmpty();
Predicate<List> javaListPred = o -> o.isEmpty();
Consumer<String> javaStringConsumer = o -> o.isEmpty(); // return value is ignored!
com.google.common.base.Predicate<String> guavaPredicate = o -> o.isEmpty();
现在它们被指定,这些例子展示全部的不同类型,尽管lambda表达式看起来一样,但是它们不能互相指定。