什么是Lambda Expression

对于Lambda Expression,我的理解是,它是一个函数表达式,如下:

(int x, int y) -> x - y

符号左边定义了函数的输入,右边定义了输出。在上面的例子中,我们定义了一个关于x,y的函数,这个函数的作用是计算两者之差。那么它的类型是什么呢?比如1+1这个表达式它的(返回值)类型是int。对于函数表达式,它的类型一般是由上下文定的。

把上面的例子放到具体使用环境中,如下所示,我们可以根据上下文语义判断,该Lambda Expression的(返回值)类型是Comparator。

Arrays.sort(input[], (int x, int y) -> x - y );

为什么要引入Lambda Expression

Lambda Expression是Java 8引入的一个非常重要的新特性,它也是Java第一次尝试引入函数式编程的相关内容。

关于函数式编程,我想类比javascript,在js中函数也可以作为变量的基本类型之一,并且可以当做值一样进行传递。但是在Java中,函数是绑定在对象上的,如果需要调用一个函数foo(),需要先实例化一个对象Obj,然后再调用这个对象里的该函数Obj.foo()。如果Java中可以像js一样,直接传递函数,岂不是很酷?

为了实现这个功能,用到了:
- Functional Interface 函数式编程的概念
- Java8新增的接口 Function
- Java8新增的语法 Lambda Expression

具体怎么实现呢?本质上来说是,新创建一个对象,然后实现Function接口。这个对象即可以看成是一个函数。

除此之外,Lambda Expression还可以快速地创建匿名对象并实现接口方法。

下面,对这两种模式具体讲解。

Lambda Expression的使用 - 创建对象

在面向接口的编程中,我们会遇到许多函数式接口(Functional Interface),即只包含一个抽象方法的接口,比如java.lang.Runnable和java.util.Comparator都是典型的函数式接口。在实际使用过程中,我们需要新建一个对象,然后implements这个接口,再实现该接口的抽象方法。如下所示:

// 常规方法
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
log(e.getActionCommand());
}
});

这段代码实现的功能是给这个button加一个ActionListener,然后在这个button有操作的时候,log该操作的名称。这样写起来有点复杂,实际上我们真正关心的只是那一行log的代码而已。如果使用Lambda Expression,可以大大简化代码量,如下所示:

// Lambda Expression方法
button.addActionListener(e -> log(e.getActionCommand()));

下面,再给出一个经典的Comparator的例子参考。

// 常规方法
Arrays.sort(input[], new Comparator<Integer>() {
@Override
public int compare(int a, int b) {
return (a-b); // in ascending order
}
}); // Lambda Expression方法
Arrays.sort(input[], (int a, int b) -> a-b ); 

下面,再给出一个常用的Runnable的例子参考。

Thread thread = new Thread(() -> {
System.out.println("Hello " + Thread.currentThread().getName());
});
thread.start();

Lambda Expression的使用 - 传递函数

前面已经提到过了,Java不能传递函数,只能传递对象。为了实现传递函数的功能,设计上采取了一个折中的方法,创建了一个Function的接口。这样一来需要被传递的函数就可以作为一个新的对象,实现这个Function接口,来进行传递。如下示例:

在该例中,(String v) -> v.length()这个Lambda表达式就是传递的方法(函数)。

public class CollectionUtils {
  // 对传入的参数input进行processor操作,依旧以list的形式返回
  public static List map(List input, Function processor) {
    ArrayList result = new ArrayList();
    for (T obj : input) {
      result.add(processor.apply(obj));
  }
  return result;
} public static void main(String[] args) {
  List input = Arrays.asList(new String[] {"apple", "orange", "pear"});
  // 统计字符串的长度
  List lengths = CollectionUtils.map(input, (String v) -> v.length());
  // 将字符串转换为大写
  List uppercases = CollectionUtils.map(input, (String v) -> v.toUpperCase());
}

下面,再给出一个Callable的例子。例中,delayFeedback("task", 1)就是传递的方法(函数)。

Callable<String> delayFeedback(String feedback, long sleepSeconds) {
return () -> {
TimeUnit.SECONDS.sleep(sleepSeconds);
return feedback;
};
} ExecutorService executor = Executors.newWorkStealingPool(); List<Callable<String>> tasks = Arrays.asList(
delayFeedback("task1", 1),
delayFeedback("task2", 2),
delayFeedback("task3", 3)); String result = executor.invokeAny(tasks);

反思与总结

从上面的例子中,我们大概对Lambda Expression是什么,怎么使用有了一个大概的了解。

回到最初的问题,再次反思Lambda Expression到底是个什么东西。我觉得,首先,可以把它看作一个Anonymous Class。其次,这个Class一定继承了某个Function Interface。至于这Class是什么类型的,需要根据上下文判断。

那么,什么地方可以用Lambda Expression?答案是FunctionalInterface。什么是FunctionalInterface?官方的回答是:

Conceptually, a functional interface has exactly one abstract method.

举几个常见的FunctionalInterface的例子:

@FunctionalInterface
public interface Comparator<T> @FunctionalInterface
public interface Function<T,R> @FunctionalInterface
public interface Predicate<T> public Interface ActionListener

这正好对应了文中之前出现的例子。(说明:对于第1,2,3个,Java 8 API已经用Annotation标明了它是FunctionalInterface,对于第4个,虽然没有标,但是它符合FunctionalInterface的定义,所以也是。)

链接

浅析Java 8新特性Lambda Expression的更多相关文章

  1. Java 8 新特性 - Lambda表达式

    Lambda表达式 vs 匿名类既然lambda表达式即将正式取代Java代码中的匿名内部类,那么有必要对二者做一个比较分析.一个关键的不同点就是关键字 this.匿名类的 this 关键字指向匿名类 ...

  2. 浅析Java 8新特性Method Reference

    什么是方法引用 我们知道了什么是Lambda Expression以及如何使用,那么,Method References又是什么呢?Oracle Java Docs中这样说: They are com ...

  3. Java 8新特性----Lambda

    Lambda 一.如何辨别Lambda表达式 Runnable noArguments = () -> System.out.println("Hello World"); ...

  4. Java 8新特性--Lambda表达式作为返回值

    lambda表达式作为方法的返回值:

  5. Java 8 新特性--Lambda表达式作为方法参数

    Lambda表达式的使用场景: 当方法的参数是一个函数式接口时,可以使用Lambda表达式进行简化—— 首先,前提是Runnable接口是一个函数式接口,经过查看源码得知,确实如此: 将Runnabl ...

  6. Java 12 新特性介绍,快来补一补

    Java 12 早在 2019 年 3 月 19 日发布,它不是一个长久支持(LTS)版本.在这之前我们已经介绍过其他版本的新特性,如果需要可以点击下面的链接进行阅读. Java 11 新特性介绍 J ...

  7. Java 8 新特性:Lambda、Stream和日期处理

    1. Lambda 简介   Lambda表达式(Lambda Expression)是匿名函数,Lambda表达式基于数学中的λ演算得名,对应于其中的Lambda抽象(Lambda Abstract ...

  8. Java8新特性-Lambda表达式是什么?

    目录 前言 匿名内部类 函数式接口 和 Lambda表达式语法 实现函数式接口并使用Lambda表达式: 所以Lambda表达式是什么? 实战应用 总结 前言 Java8新特性-Lambda表达式,好 ...

  9. Java 8 新特性——检视阅读

    Java 8 新特性--检视阅读 参考 Java 8 新特性--菜鸟 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的 ...

随机推荐

  1. jQuery源码研究——怎么看源码

    废话 这几天有想看源码的想法,于是就开始了源码的研究,经过几天的摸索发现看源码还是有点技巧在里面的,想着把这些东东写下来作为一个小总结. 在一个多月前我对Vue源码进行了一次研究,那时看源码的方式基本 ...

  2. mysql 军规 (转载)

    导语 来自一线的实战经验 每一条军规背后都是血淋淋教训 不要华丽,只要实用 若有一条让你受益,慰矣 主要针对数据库开发人员 总是在灾难发生后,才想起容灾的重要性 总是在吃过亏后,才记得曾经有人提醒过 ...

  3. docker dead but pid file exists

    CentOS 6安装docker 报docker dead but pid file exists 执行 yum install epel-release yum install docker-io ...

  4. 图论算法-最小费用最大流模板【EK;Dinic】

    图论算法-最小费用最大流模板[EK;Dinic] EK模板 const int inf=1000000000; int n,m,s,t; struct node{int v,w,c;}; vector ...

  5. 从零开始学Python--数据类型之字符串

    一.Python中的数据类型 ·   整数, 如 1 -100 ·   长整数, 是比较大的整数,Python 2里面有long长整数:Python 3里面没有 ·   浮点数 如 1.23.3E-2 ...

  6. 802.1X和NAP整合实验手册

    实验描述 公司内部有多个部门,创建了域的架构,并搭建了DHCP服务器和Radius服务器,要求每个部门都独享一个网段,实现每位用户插上网线后,跳出窗体进行身份验证,如果用户通过验证,根据用户所在的部门 ...

  7. MySQL数据库基础(二)(约束以及修改数据表)

    一,约束以及修改数据表 约束的作用?1.约束保证数据的完整性.一致性:2.约束分为表级约束.列级约束:3.约束类型包括:NOT NULL(非空约束).PRIMARY KEY(主键约束).UNIQUE ...

  8. css实现多行多列的布局

    1.两列多行: HTML: <div class="box1"> box1:实现两列多行布局 <ul> <li>111</li> & ...

  9. Hibernate学习(五)lazy属性学习(true和extra区别)

    Lazy(懒加载)在hibernate何处使用:1.<class>标签上,可以取值:true/false,(默认值是:true)2.<property>标签上,可以取值:tru ...

  10. php 网络爬虫2种方法

    1,通过curl进行抓取再进行写入文件当中: $curlobj = curl_init(); // 初始化curl_setopt($curlobj, CURLOPT_URL, "https: ...