关于Lambda表达式的整理

前段时间的面试基本结束了,最后也有了不错的结果,之后一段时间到入职打算好好整理一些东西。
想到马上Java9也要出来了,Android也马上支持Java8,自己都没有好好整理过java8比较重要的知识点,可以说8很多改动都是为了Lambda服务的,所以整理一下Lambda的内容。

关于闭包

首先闭包是指,将当前作用域中的变量通过值或者引用的方式封装到lambda表达式中,成为表达式的一部分,它使你的lambda表达式从一个普通的函数变成带隐藏参数的函数,当然闭包也可以不通过lambda实现

简单理解为闭包就是定义在函数内部的函数

Lambda 表达式与匿名类的区别

  • Lambda 表达式与匿名类的主要不同在于两者的编译方法
  • 对于匿名类,关键词 this 解读为匿名类,而对于 Lambda 表达式,关键词 this 解读为写就 Lambda 的外部类

什么时候用

任何可以接受一个函数式接口的地方都可以用lambda表达式
lambda作用在于

  • 逻辑更紧凑
  • 引入闭包,更简洁的实现闭包
  • 允许函数方法作为对象传递

函数式接口

定义

所谓的函数式接口,也叫SAM接口(Single Abstract Method interfaces),当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法

  • 函数式接口里允许定义默认方法
  • 函数式接口里允许定义静态方法
  • 函数式接口里允许定义java.lang.Object里的public方法
    //以下都是不会报错的
    @FunctionalInterface
    interface GreetingService{
        void sayMessage(String message);

        default void doSomeMoreWork1()
        {
            // Method body
        }
        static void printHello(){
            System.out.println("Hello");
        }
        @Override
        boolean equals(Object obj);
    }

@FunctionalInterface注解

加不加@FunctionalInterface对于接口是不是函数式接口没有影响,只是提醒编译器去检查该接口是否仅包含一个抽象方法,用于编译级错误检查

新增java.util.function

  • Predicate:用于判断一个对象是否满足某种条件,只有一个test抽象函数,接受一个泛型T对象返回boolean
  • Consumer:用于对对象进行消费操作,只有一个accept抽象函数,接受一个泛型对象无返回
  • Function:用于对象的转换,只有一个apply抽象函数,接受一个泛型T,返回一个泛型R
  • Supplier:用于创建对象
  • 还有一些衍生的可以自己看包下源码

使用

使用相信大家都会一些,我就不列举,网上大把的文章,下面两篇总结不错

深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)

10个实例表达式

原理

Java 编译器编译 Lambda 表达式并将他们转化为类里面的私有静态函数

  • 它使用 Java 7 中新加的 invokedynamic,运行时调用LambdaMetafactory.metafactory动态的生成内部类,实现了接口
  • 生成一个类私有静态函数,在生成的实现类中调用

关于 Java 如何将 Lambda 表达式编译为字节码

国外的一篇写的不错

通俗易懂的解释

interface Print<T> {
    public void print(T x);
}
public class Lambda {   
    public static void PrintString(String s, Print<String> print) {
        print.print(s);
    }
    public static void main(String[] args) {
        PrintString("test", (x) -> System.out.println(x));
    }
}

通过编译最终等价于

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());
    }
}

关于性能

Oracle写的lambda表现文档

16页讲到最差(capture)也和inner class一样, non-capture好的情况是inner class的5倍

image1
image1

但是在使用Stream的时候并不是所有情况都比普通迭代快的

下面这篇文章比较了各种情况下imperative code与functional code的性能表现

The effects of programming with Java 8 Streams on algorithm performance

关于Streams

Lambda最佳结合应该就是Stream了,函数式编程与简洁的结合
Java 8的Stream内置了许多类似于数据库的操作filter、sort、map、reduce等
用法就不贴了,大把文章
官方的在这里

Stream优点:

  • 以数据库操作数据的方式,专注于如何做这个某个步骤,表达式的方式

  • 高并发(看到map、reduce就应该能想到了)

刚开始看Stream感觉和RxJava非常像,但是仔细思索后有发现其实是两个不同的东西,只是长得像而已。
下面这个最高票回答总结的非常好,总体来说

  • stream是单次使用,是基于被动PULL
  • rx是基于观察者模式,可多次订阅,是基于主动PUSH

Stream与Rxjava的不同

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 本文是对 Brian Goetz 的 State of Lambda 一文的翻译 为什么要翻译这个系列? andr...
    aaron688阅读 3,949评论 4 31
  • 摘要:此篇文章主要介绍 Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同...
    OneAPM阅读 2,093评论 0 26
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,991评论 19 139
  • lambda表达式(又被成为“闭包”或“匿名方法”)方法引用和构造方法引用扩展的目标类型和类型推导接口中的默认方法...
    183207efd207阅读 1,500评论 0 5
  • 《断剑》 文/刘汉皇 剑死了,在绝望中死去在轰鸣的车间死去在高大的炼钢炉融化死去的还有他的魂,他的梦 他饮过匈奴的...
    刘汉皇阅读 527评论 15 8