• Lambda表达式 语法 示例 MD


    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱
    MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

    目录

    Lambda 表达式

    Lambda 表达式也称为闭包,是匿名内部类的简短形式。

    Lambda 表达式简化了单一方法声明接口的使用,因此 lambda 表达式也称为功能接口(只有一个抽象方法的接口)。

    使用 lambda 表达式实现功能接口时,无需创建类或匿名类。

    Lambda 表达式具有以下优点:

    • 简明的语法
    • 方法引用和构造函数引用
    • 相比于匿名类,减少了运行时开销

    基本语法

    (formal parameter list) -> {
        expression or statements
    }

    参数列表

    • 参数列表是一个逗号分隔的形式参数列表,这些参数与功能接口中单一方法的形式参数相对应。
    • 参数列表中的参数类型是可选项,如果未指定参数类型,将从上下文推断。
    • 参数列表必须用小括号括起来,但如果只有一个参数且不带参数类型时小括号可以省略
    • 参数列表如果为空(即:功能接口方法没有形式参数),则必须指定空括号

    Lambda 主体根据以下选项之一返回结果:

    • 如果 lambda 主体是单一表达式,则返回表达式的值(如果有的话)。
    • 如果功能接口方法的结果是 void,可以提供一个 return 语句,但这不是必需的。
    • 如果功能接口方法具有返回类型,且 lambda 主体不是单一表达式,则 lambda 主体必须使用 return 语句返回匹配的值。

    语句块必须包含在大括号内,除非语句块是一个方法调用语句,且功能接口方法的返回结果是void。

    Lambda 表达式实际上是一种匿名方法实现,指定形式参数,并使用 return 语句返回值。匿名方法必须按照以下规则所规定的与其实现的功能接口方法兼容。

    • Lambda 表达式返回的结果必须与功能接口方法的结果兼容。返回值的类型可以是功能接口方法声明中返回类型的子类型。
    • Lambda 表达式签名必须与功能接口方法的签名相同。
    • Lambda 表达式只能抛出那些在功能接口方法的 throws 子句中声明了异常类型或异常超类型的异常。

    Lambda 表达式中的局部变量

    Lambda 表达式不会定义新的作用域,lambda 表达式的作用域与封闭作用域相同。

    Lambda 主体中的 this 和 super 引用与封闭上下文中一样,因为 lambda 表达式不会引入新的作用域,这与匿名类不同。

    如果 Lambda 主体声明的局部变量与封闭作用域内的变量重名,将产生编译器错误

    Lambda expression's local variable i cannot re-declare another local variable defined in an enclosing scope

    局部变量无论是在 lambda 表达式主体中声明,还是在封闭作用域中声明,使用之前都必须先初始化,否则将产生编译器错误

    The local variable i may not have been initialized

    lambda 表达式中使用的变量必须处于终态或等效终态,否则将产生编译器错误

    Variable i is required to be final or effectively final

    启用 Lambda 表达式

    在AS中使用 Lambda 表达式

    File -> Project Structure -> SDK location -> JDK location -> JDK版本选择1.8

    android {
        compileOptions {
            targetCompatibility JavaVersion.VERSION_1_8
            sourceCompatibility JavaVersion.VERSION_1_8
        }
    }

    在Eclipse中使用 Lambda 表达式

    前提条件

    • 1、安装了 JDK 8 的 JRE
    • 2、所使用的 Eclipse 要支持 Java8 的编译

    步骤

    • 在 Eclipse 中,选择 Windows > Preferences > Java > Installed JREs,勾选JDK 8 的 JRE
    • 选择 Windows > Preferences > Java > Compiler,然后将 Compiler compliance level 设为 1.8。如果没有 1.8 的选项,说明此eclipse版本不支持。
    • 单击 Apply,然后单击 OK。

    Eclipse Luna SR2已经添加了对Java8的支持,可直接到官网下载

    使用示例

    没有参数

    new Thread(() -> {
        System.out.println("包青天");
    }).start();

    只有一行语句时,可以进一步简化为:

    new Thread(() -> System.out.println("包青天")).start();
    new Thread(() -> runOnUiThread(() -> System.out.println("包青天"))).start();

    但是如果有多行语句,就没法简化了

    单一参数

    imageView.setOnClickListener(v -> {
        Toast.makeText(this, "包青天", Toast.LENGTH_SHORT).show();
    });

    同样,只有一行语句时,可以进一步简化为:

    imageView.setOnClickListener((View v) -> System.out.println("包青天")); //带类型
    imageView.setOnClickListener((v) -> System.out.println("包青天")); //带小括号
    imageView.setOnClickListener(v -> System.out.println("包青天")); //省略小括号
    imageView.setOnClickListener(v -> System.out.println(v));

    如果只有一行方法引用的语句,且此方法没有返回值,且此方法仅有一个参数,且此方法的此参数就是 Lambda 表达式中参数列表中的那个参数,可以进一步简化为方法引用(method reference)

    imageView.setOnClickListener(v -> test(v));
    
    imageView.setOnClickListener(this::test); //普通方法
    imageView.setOnClickListener(System.out::println); //静态方法
    imageView.setOnClickListener(SplashActivity::test); //静态方法

    多个参数

    listView.setOnItemClickListener((AdapterView<?> parent, View view, int position, long id) -> {
        Toast.makeText(this, "position=" + position, Toast.LENGTH_SHORT).show();
    });

    同样,只有一行语句时,可以进一步简化为:

    listView.setOnItemClickListener((AdapterView<?> parent, View view, int position, long id) -> System.out.println(position));
    listView.setOnItemClickListener((parent, view, position, id) -> System.out.println(position));

    使用局限性

    1、只适用于单一方法的接口,如果接口有多个需要实现的方法,则不能使用,如:

    listView.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
        }
    
        @Override
        public void onScroll(AbsListView view, int first, int count, int total) {
        }
    });

    这是 Lambda 表达式最大的局限性

    2、如果需要在匿名内部类中定义成员变量,则不能使用,如:

    listView.setOnClickListener(new View.OnClickListener() {
        private boolean b;
    
        @Override
        public void onClick(View v) {
        }
    });

    其实这里的成员变量没有任何意义,和定义成局部变量没什么区别

    3、如果需要在匿名内部类中使用到匿名内部类的this、super,而非如外部类的this、super,则不能使用,如:

    view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            //这里的this代表的是匿名内部类OnGlobalLayoutListener
            view.getViewTreeObserver().removeOnGlobalLayoutListener(this);//使用到了this
        }
    });

    Lambda 主体中的 this、super 引用与封闭上下文中一样,因为 lambda 表达式不会引入新的作用域,这与匿名类不同。
    Lambda 表达式中使用的this、super是指外部类,其实往往这是 Lambda 的优点而非缺点,因为我们往往需要的就是外部类的this、super

    2017-07-17

  • 相关阅读:
    python面试题总结(1)
    python数据结构与算法之算法和算法分析
    python数据结构与算法之问题求解实例
    python数据结构与算法之问题求解
    导航栏挡住View
    coredata
    SVN
    mac 上用到的数据库软件
    开博感言
    九 、循环队列的java实现
  • 原文地址:https://www.cnblogs.com/baiqiantao/p/7195853.html
Copyright © 2020-2023  润新知