Lambda表达式是Java 8一个非常重要的新特性。它像方法一样,利用很简单的语法来定义参数列表和方法体。目前Lambda表达式已经成为高级编程语言的标配,像Python,Swift等都已经支持Lambda表达式。

在Java 8的实现中,Lambda表达式其本质只是一个“语法糖”,经过编译器推断和处理,将其转换包装为常规的Java代码,因此就像题目所写的那样,可以让你的代码更为简洁。

Lambda表达式的基本语法:(parameters) -> expression 或 (parameters) -> { statements; }

Lambda表达式并不是一个方法,它可以用来定义了一个代码块,形式上很像是Java的匿名内部类。Lambda表达式通常会赋值给一个函数式接口,函数式接口是指只有一个抽象方法的接口。Lambda表达式可以通过上下文环境来推断变量类型, 因此在使用时尽量不人为明确的指定变量类型。

举例来看,假设我们有一个List<String>类型的列表list,如果要遍历并打印列表内容,Java 7以前的代码如下:

  1. for (String s : list) {
  2. System.out.println(s);
  3. }

Java 8来实现的话:

  1. list.forEach((s) -> System.out.println(s));

或者

  1. list.forEach(System.out::println);

再看一个例子,假设我们要对list进行排序,Java 7的代码如下:

  1. Collections.sort(list, new Comparator<String>() {
  2. @Override
  3. public int compare(String p1, String p2) {
  4. return p1.compareTo(p2);
  5. }
  6. });

Java 8来实现的话:

  1. Collections.sort(list, (String p1, String p2) -> p1.compareTo(p2));

需要注意的是,Lambda表达式可以做参数类型推断,这里我们可以充分利用这一点,p1和p2参数前面的String是不需要的,因此可以简化一步如下:

  1. Collections.sort(list, (p1,p2) -> p1.compareTo(p2));

更进一步:

  1. list.sort((p1,p2) -> p1.compareTo(p2));

是不是简洁了很多:)

Lambda表达式也可以用来代替匿名类。例如我们要实现Runnable接口,Java 7的代码如下:

  1. new Thread(new Runnable() {
  2. @Override
  3. public void run() {
  4. System.out.println("Hello world !");
  5. }
  6. }).start();

Java 8来实现的话:

  1. new Thread(() -> System.out.println("Hello world !")).start();

用Lambda表达式来实现Runnable,将五行代码转换成一行语句。

合理使用Lambda表达式,不仅能简化几行代码,还能做到合理的代码抽象。当我们在实现的两个很大的方法时,如果大部分的代码都是相同的,只有一小点代码不一样时,我们可以通过将Lambda表达式作为参数传入,以达到不同表意的目的。

前面提到的函数式接口(Functional Interfaces),它表示只有一个抽象方法的接口,可以用来指向Lambda表达式。例如:

  1. 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注解,例如:

  1. @FunctionalInterface
  2. public interface funcInterface {
  3. public abstract B op(A a);
  4. }

在将函数式接口作为参数时,需要注意尽量避免方法重载。由于Lambda表达式根据所在环境的目标类型来决定Lambda表达式的类型(也就是Target Typing), 因此方法重载有时会导致编译器犯晕。我们可以使用不同的方法名来解决这个问题。

在这里,我们还需要澄清几点:

  • Lambda表达式并不是函数式接口。它能赋值给函数式接口,是因为编译器将它包装成了对应的函数式接口;

  • 更进一步,Lambda表达式也不是匿名类:

    • 它并没有定义新的作用域,外面定义的局部变量在Lambda表达式内部是可见的;

    • 它不能改变外部变量的值,只能读取final或者effectively final的变量;

    • 它不能前向读取外部变量,也就是只有在外部变量申明之后才能读取,而在匿名内部类是可以的;

Java 8 还增强了对集合数据的批量操作Stream,通常会和Lambda表达式一起使用。Lambda表达式和 Stream 可以说是Java语言从添加泛型(Generics)和注解(annotation)以来最大的变化了。下一篇文章将重点介绍Stream。

Java 8 Lambda表达式,让你的代码更简洁的更多相关文章

  1. 死磕Lambda表达式(三):更简洁的Lambda

    我们都是阴沟里的虫子,但总还是得有人仰望星空.--<三体> 在之前的文章中介绍了Lambda表达式的基本语法和正确使用姿势,这次我来介绍一些Lambda更简洁的用法. 欢迎关注微信公众号: ...

  2. Java 8 Lambda 表达式详解

    一.Java 8 Lambda 表达式了解 参考:Java 8 Lambda 表达式 | 菜鸟教程 1.1 介绍: Lambda 表达式,也可称为闭包,是推动 Java 8 发布的最重要新特性. La ...

  3. Java 8 Lambda表达式探险

    为什么?    我们为什么需要Lambda表达式    主要有三个原因:    > 更加紧凑的代码      比如Java中现有的匿名内部类以及监听器(listeners)和事件处理器(hand ...

  4. 深入探索Java 8 Lambda表达式

    2014年3月,Java 8发布,Lambda表达式作为一项重要的特性随之而来.或许现在你已经在使用Lambda表达式来书写简洁灵活的代码.比如,你可以使用Lambda表达式和新增的流相关的API,完 ...

  5. Java 8 Lambda表达式

    Java 8 Lambda表达式探险 http://www.cnblogs.com/feichexia/archive/2012/11/15/Java8_LambdaExpression.html 为 ...

  6. 深入浅出 Java 8 Lambda 表达式

    摘要:此篇文章主要介绍 Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同等.本文系 OneAPM 工程师编译整理. Java 是一流的面向对象语言,除了部分简 ...

  7. Java 8 Lambda表达式10个示例【存】

    PS:不能完全参考文章的代码,请参考这个文件http://files.cnblogs.com/files/AIThink/Test01.zip 在Java 8之前,如果想将行为传入函数,仅有的选择就是 ...

  8. 掌握 Java 8 Lambda 表达式

    Lambda 表达式 是 Java8 中最重要的功能之一.使用 Lambda 表达式 可以替代只有一个函数的接口实现,告别匿名内部类,代码看起来更简洁易懂.Lambda 表达式 同时还提升了对 集合 ...

  9. Java中Lambda表达式的使用

    简介(译者注:虽然看着很先进,其实Lambda表达式的本质只是一个"语法糖",由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能.本人建议不要乱用,因 ...

  10. Java 8 Lambda 表达式

    Lambda 是啥玩意 简单来说,Lambda 就是一个匿名的方法,就这样,没啥特别的.它采用一种非常简洁的方式来定义方法.当你想传递可复用的方法片段时,匿名方法非常有用.例如,将一个方法传递给另外一 ...

随机推荐

  1. APP 测试 与 WEB 测试的本质区别

    单纯从功能测试的层面上来讲的话,APP 测试.web 测试 在流程和功能测试上是没有区别的 根据两者载体不一样,则区别如下: 1.系统结构方面 web项目,b/s架构,基于浏览器的:web测试只要更新 ...

  2. C++模式学习------原型模式

    原型模式: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.意思就是从A的实例得到一份与A内容相同,但是又互不干扰的实例B. class base { public : base(co ...

  3. BZOJ5006 THUWC2017随机二分图(概率期望+状压dp)

    下称0类为单边,1类为互生边,2类为互斥边.对于一种匹配方案,考虑其出现的概率*2n后对答案的贡献,初始为1,如果有互斥边显然变为0,否则每有一对互生边其贡献*2.于是有一个显然的dp,即设f[S1] ...

  4. Pku1149 PIGS 卖猪

    题目链接:ヾ(≧∇≦*)ゝ Description Emmy在一个养猪场工作.这个养猪场有M个锁着的猪圈,但Emmy并没有钥匙. 顾客会到养猪场来买猪,一个接着一个.每一位顾客都会有一些猪圈的钥匙,他 ...

  5. C#线程篇---你所不知道的线程池(4)

    线程的创建和销毁都要耗费大量的时间,有什么更好的办法?用线程池! 太多的线程浪费内存资源,有什么更好的办法?用线程池! 太多线程有损性能,有什么更好的办法?用线程池!(⊙_⊙)? 线程池是什么?继前三 ...

  6. 添加jar包需注意

    对于纯java项目使用的是本地自己的JRE,通过build path导入的JAR包的配置信息会出现在应用的”.classpath”文件中,ClassLoader会智能地去加载这些JAR. 而Web项目 ...

  7. postgresql 数据库无法启动

    在数据库无法启动时,一般可以根据报错信息,采取对应措施即可,下面列出一些在数据库启动时报出错误比较严重而解决方式又不那么明显的处理方法. 模拟错误,查到pg_class系统表中一个索引在磁盘中的位置, ...

  8. HDU--4705

    题目: Y 原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4705 分析:树形dp的思想,枚举中间点. #include<iostream> ...

  9. sidecar学习

    1.SideCar的出现 微服务的结构是细粒度的,由多个服务构成,支持不同的服务用不同的语言来编写,比如a服务用python,b服务用java,C服务用php等,我们称为异构语言,那么在利用zuul来 ...

  10. HDU1532最大流 Edmonds-Karp,Dinic算法 模板

    Drainage Ditches Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) To ...