java常用lambda
合理使用Lambda表达式,不仅能简化几行代码,还能做到合理的代码抽象。当我们在实现两个很大的方法时,如果大部分的代码都是相同的,只有一小点代码不一样时,我们可以通过将Lambda表达式作为参数传入,以达到不同的表意目的。
前面提到的函数式接口(Functional Interfaces),它表示只有一个抽象方法的接口,可以用来指向Lambda表达式。例如:
Consumer c = (s) -> System.out.println(s);
Java 8在java.util.function包中实现了新的几个:
-
Function<T, R>:接受一个参数T,返回结果R
-
Predicate<T>:接受一个参数T,返回boolean
-
Supplier<T>:不接受任何参数,返回结果T
-
Consumer<T>:接受一个参数T,不返回结果
-
UnaryOperator<T>:继承自Function<T, T>,接受一个参数T,返回相同类型T的结果
-
BiFunction<T, U, R>:接受两个参数T和U,返回结果R
-
BinaryOperator<T>:继承自BiFunction<T, T, T>,接受两个相同类型T的参数,返回相同类型T的结果
-
……
另外,我们最为熟悉的函数式接口还有:
-
Runnable:实际上是不接受任何参数,也不返回结果
-
Comparable<T>:实际上是接受两个相同类型T的参数,返回int
-
Callable<V>:不接受任何参数,返回结果V
通常我们应该尽量使用标准的函数式接口,如果我们要自定义的话,可以使用@FunctionalInterface注解,例如:
@FunctionalInterface public interface funcInterface { public abstract B op(A a); }
在将函数式接口作为参数时,需要注意尽量避免方法重载。由于Lambda表达式根据所在环境的目标类型来决定Lambda表达式的类型(也就是Target Typing), 因此方法重载有时会导致编译器犯晕。我们可以使用不同的方法名来解决这个问题。
在这里,我们还需要澄清几点:
-
Lambda表达式并不是函数式接口。它能赋值给函数式接口,是因为编译器将它包装成了对应的函数式接口;
-
更进一步,Lambda表达式也不是匿名类:
-
它并没有定义新的作用域,外面定义的局部变量在Lambda表达式内部是可见的;
-
它不能改变外部变量的值,只能读取final或者effectively final的变量;
-
它不能前向读取外部变量,也就是只有在外部变量申明之后才能读取,而在匿名内部类是可以的;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~