1.Lambda介绍
lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body可以是一个表达式或一个代码块)
- 匿名的,有输入输出,但没有函数名
- Function
- 简洁的
- Java 1.7中,发布了一个名为 invokedynamic 的新JVM操作码,Java 8 Lambda使用它
2.Lambda表达式的语法
2.1 基本语法
(parameters) -> expression
或
(parameters) ->{ statements;}
2.2 简单例子
//1.接受参数,并有返回值
Comparator<Apple> byColorLambda = (Apple a1, Apple a2)->{
return a1.getColor().compareTo(a2.getColor());
};
//2.接受参数,参数类型可以不指定,通过推导的方式
Comparator<Apple> byColorLambda = (a1, a2)->{
return a1.getColor().compareTo(a2.getColor());
};
//3.不加花括号,return可以省略
Comparator<Apple> byColorLambda = (a1, a2)->a1.getColor().compareTo(a2.getColor());
//4.不需要参数,返回值为 5
() -> 5
//5.接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
//6.接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
//7.Function
Function<String, Integer> byLenLambda = a -> a.length();
//8.Predicate
Predicate<Apple> p = a -> a.getColor().equals("green");
2.3 Lambda本质
1.本质上是一个Functional Interface的实现,下面通过几个例子,阐述下。
1.(int x, int y) -> {
System.out.println(x);
System.out.println(y);
};
==>
@FunctionalInterface
public interface Test{
public void fun(int x, int y)
}
2.() -> 42;
==>
@FunctionalInterface
public interface Test{
public int fun()
}
2.查看字节码,其实可以了解到生成了内部类,用于实现Function interface,并提供了一个静态方法,用于调用此内部类的方法
@FunctionalInterface
interface Print<T> {
public void print(T x);
}
public class Lambda {
public static void PrintString(String s, Print<String> print) {
print.print(s);
}
private static void lambda$0(String x) {
System.out.println(x);
}
final class $Lambda$1 implements Print{
@Override
public void print(Object x) {
lambda$0((String)x);
}
}
public static void main(String[] args) {
PrintString("test", new Lambda().new $Lambda$1());
}
}
2.4 Lambda使用
public class LambdaUsage {
public static void main(String[] args) {
Runnable r1 = () -> System.out.println("Hello");
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
ProcessRun(r1);
ProcessRun(r2);
ProcessRun(()->System.out.println("Hello"));
}
private static void ProcessRun(Runnable r) {
r.run();
}
2.5 几中Function interface
Predicate boolean test(T t)
Consumer accept(T t);
Function<T, R> R apply(T t);
Supplier<T> T get();
2.5.1 Predicate
1.抽象方法
boolean test(T t);
即对t进行断言,返回true或者false
类似的IntPredicate、LongPredicate、DoublePredicate、BiPredicate
2.例子
public static List<Apple> findPredicateApple(List<Apple> apples, Predicate<Apple> predicate) {
List<Apple> newApples = new ArrayList<>();
for (Apple apple : apples) {
if (predicate.test(apple)) {
newApples.add(apple);
}
}
return newApples;
}
public static List<Apple> findLongPredicateApple(List<Apple> apples, LongPredicate predicate) {
List<Apple> newApples = new ArrayList<>();
for (Apple apple : apples) {
if (predicate.test(apple.getWeight())) {
newApples.add(apple);
}
}
return newApples;
}
public static List<Apple> findBiPredicateApple(List<Apple> apples, BiPredicate<String, Long> predicate) {
List<Apple> newApples = new ArrayList<>();
for (Apple apple : apples) {
if (predicate.test(apple.getColor(), apple.getWeight())) {
newApples.add(apple);
}
}
return newApples;
}
public static void main(String[] args) {
List<Apple> apples = Arrays.asList(new Apple(120, "green"),
new Apple(110, "yellow"),
new Apple(160, "green"),
new Apple(140, "red"));
List<Apple> greenApples = findPredicateApple(apples, apple -> apple.getColor().equals("green"));
System.out.println(greenApples);
List<Apple> weight140Apples = findLongPredicateApple(apples, w -> w==160);
System.out.println(weight140Apples);
List<Apple> biApples = findBiPredicateApple(apples, (c, w) -> c.equals("green") && (w == 160));
System.out.println(biApples);
}
2.5.2 Consumer
1.抽象方法
void accept(T var1);
接收一个泛型的参数T,然后调用accept,对这个参数做一系列的操作,没有返回值
类似的IntConsumer、LongConsumer、DoubleConsumer、BiConsumer
2.例子
public static void consumerApple(List<Apple> apples, Consumer<Apple> consumer){
for (Apple apple : apples){
consumer.accept(apple);
}
}
public static void biConsumerApple(List<Apple> apples, BiConsumer<String, Long> consumer){
for (Apple apple : apples){
consumer.accept(apple.getColor(), apple.getWeight());
}
}
public static void main(String[] args) {
List<Apple> apples = Arrays.asList(new Apple(120, "green"),
new Apple(110, "yellow"),
new Apple(160, "green"),
new Apple(140, "red"));
consumerApple(apples, apple -> System.out.println(apple));
biConsumerApple(apples, (c, w) -> System.out.println("color: " + c +", weigth: " + w));
}
2.5.3 Function
1.抽象方法
R apply(T var1);
将Function对象应用到输入的参数上,然后返回计算结果
接收一个泛型的参数T,进行计算,返回结果R
类似的IntFunction、LongFunction、DoubleFunction、BiFunction
2.例子
public String functionApple(Apple apple, Function<Apple, String> func){
return func.apply(apple);
}
String apple = functionApple(new Apple(110, "red"), a -> a.toString());
2.5.3 Supplier
1.抽象方法
T get();
接口没有入参,返回一个T类型的对象,类似工厂方法
类似的IntSupplier、LongSupplier、DoubleSupplier、BiSupplier
2.例子
Supplier<Apple> supplier = ()->new Apple(110, "yellow");
Apple apple = supplier.get();
System.out.println(apple);
Supplier<String> s = String::new;
System.out.println(s.get().getClass());
2.6 优点和缺点
1.优点:
- 最直观的,就是不用再写大量的匿名内部类
- Java 8 使用 invokedynamic 来调用lambda,如果你有10个lambda,它将不会导致任何匿名类,从而减少最终的jar大小
- 非常容易并行计算
- 可能代表未来的编程趋势
- 结合 hashmap 的 computeIfAbsent 方法,递归运算非常快。java有针对递归的专门优化。
2.缺点:
-
若不用并行计算,很多时候计算速度没有比传统的 for 循环快。(并行计算有时需要预热才显示出效率优势)
-
不容易调试
-
若其他程序员没有学过 lambda 表达式,代码不容易让其他语言的程序员看懂
-
在 lambda 语句中强制类型转换貌似不方便,一定要搞清楚到底是 map 还是 mapToDouble 还是 mapToInt
2.7 其他
Lambda表达式中引用的外部变量是常量
int i = 1;
Runnable r = () -> System.out.println(i); //此时编译器将i修饰为final
Runnable r = () -> System.out.println(i++); //这样会报错的,因为编译器将i修饰为final
//同样在匿名内部类也一样
int i = 1;
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(i++); //这样会报错的,因为编译器将i修饰为final
}
}