Lambda表达式深入解析

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
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值