• Java 8——Lambda表达式


    本篇文章不介绍Lambda的前世今生,这里只对Lambda表达的应用做详细了解。以及与内部类的差异点。

    Lambda表达式

    Lambda表达式是Java SE 8版本中引入的新的语法糖。将功能看做方法参数,将代码看做数据。

    Lambda表达式语法:

    LambdaParameters -> LambdaBody

    Lambda表达式分为三部分:

    • 参数列表
    • ->符号
    • 函数体

    如:

    () -> {} // 无参,返回结果为空
    (x) -> System.out.println(x); // 带有一个参数
    (Thread t) -> { t.start(); }  // 带有一个申明参数
    (int x, int y) -> x + y; // 带有两个申明参数,一个方法参数;
    (int x, int y) -> return x +y; // 带有两个申明参数,一个方法参数;
    (x, y) -> return x +y; // 带有两个申明参数,一个方法参数;
    

    总体上表现如上形式,是Java中一种新的风格的表达式,和普通的表达的确有很大风格上的差异性。

    这种风格的语法优势:

    • 语法特点决定了语句的简洁紧凑,通过减少申明类型、return、单行语句去括号等等从而变得更精简;

    • 具有更强的表达能力,减少冗余的代码,从而更关注真正的功能语句,语义更精确清晰;

    函数式接口

    已经对lambda表达式定义好了,但是如何在兼容面向对象的Java体系中使用。在面向对象体系中,一切皆是对象,怎样将这种表达式作为对象去使用,从而引入函数使接口:只有一个抽象方法的接口,代表着单功能的契约

    为了区分函数式接口和只包含一个抽象方法的普通接口,需要使用@FunctionalInterface注解标注接口,这样编译器就能将其作为函数式接口处理。

    注:无论是本身具有还是继承都可以。如果继承父接口的抽象方法,也算入函数式接口一个抽象方法的统计中;如果覆盖Object类的方法,不会算入统计中,因为任何对象都继承自Object

    有了函数式接口就可以很方便的使用lambda表达式,使用Java来进行函数式编程。

    Function<String, String> f = (String x) -> x.toUpperCase();
    f.apply("msg");
    

    lambda表达式可以赋值给函数式接口,这里涉及到目标类型上下文,编译器根据lambda表达式所在的上下文推导其目标类型为Function。

    List<String> list = new ArrayList<>();
    list.forEach((x) -> System.out.println(x));
    

    lambda表达式作为方法参数,其实是list.forEach方法中的方法参数是函数式接口,编译器推导lambda表达式类型为forEach中的函数式接口类型作为lambda表达式的目标类型。

    从以上可以看出:

    • lambda表达式的目标类型必须是函数式接口,但是函数式接口和lambda表达式是两部分,函数式接口并不属于lambda表达式一部分,只是作为其目标类型;

    • 函数式接口的抽象方法参数必须与lambda表达式的相一致:数量和个数;

    • 函数式接口抽象方法返回参数与lambda表达式返回值一致:类型;

    • lambda表达式中抛出的受检异常与函数式接口抽象方法上的throws保持一致;

    函数式接口使得lambda表达式能够更好的使用。Java是面向对象,如果在此基础上引入lambda,势必需要向前兼容:

    • 如果引入新的类型,势必要与旧的api形成两套体系,这样就无法在历史版本中使用lambda表达式;

    • 如果引入新的类型,Java类库需要对于同一功能就需要维护两份:过去历史版本/lambda版本;

    如果使用已有的接口表示:

    • 接口是 Java 类型系统的一部分

    • 接口天然就拥有其运行时表示(Runtime representation);

    基于这些原因,选择已有的接口类型作为函数式接口,然后引入lambda表达式是最折中平衡的方式。

    Lambda表达式与匿名内部类

    1. lambda表达式的简洁、紧凑的语法结构是匿名内部类所不能比拟的;

    2. lambda表达式具有更明确的语义——因为只关注有效的代码;

    3. lambda表达式的作用域比匿名内部类更加有友好(词法作用域/新的内部作用域):this在lambda表达式中表示外部内,而在内部类中表示当前内部类实例;变量名在lambda表达式中就是表示外部的,而在内部类中要防止继承自超类———lambda的词法作用域;(Shadowing问题,如果对Shadowing不熟悉,赶紧戮Shadowing)

    4. lambda是函数式编程的体现,内部类任然是在面向对象层面;

    参考

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

    The Java® Language Specification

    Lambda Expressions

  • 相关阅读:
    Lodop客户端本地角色注册号常见误区
    Spring中加载xml配置文件的六种方式
    源程序出现各种奇怪的符号P
    MyEclipse项目中的java文件的图标变成空心的问题
    servlet中的相对路径和绝对路径 及/, ./, ../的区别
    Thread 与 Runnable
    Class.forName()用法详解
    chain.doFilter(request,response)含义
    jsp简单标签开发(一)
    createStatement()的用法
  • 原文地址:https://www.cnblogs.com/lxyit/p/9434226.html
Copyright © 2020-2023  润新知