06月10, 2017

Lambda表达式

在很多高级语言中都是有lambda 表达式的,比如:Python、Javascript、C#、Objective-C......

Lambda表达式在Java 8中被引入,被称为Java 8的最大特征。Lambda表达式有助于函数式编程,并且简化了开发工作。(关于函数式编程可以看一下阮一峰的函数式编程初探)。

lambda表达式简介

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中),使用 Lambda 表达式可以使代码变的更加简洁紧凑。但是Java中的lambda无法单独出现,它需要一个函数式接口来盛放,lambda表达式方法体其实就是函数接口的实现。

函数式接口functional interface

我们把只拥有一个方法的接口称为 函数式接口。(之前它们被称为 SAM类型,即 单抽象方法类型(Single Abstract Method))。

例如:android中android.view.View.OnClickListener其实就是一个函数式接口

/**
 * Interface definition for a callback to be invoked when a view is clicked.
 */
public interface OnClickListener {
    /**
     * Called when a view has been clicked.
     *
     * @param v The view that was clicked.
     */
    void onClick(View v);
}

lambda表达式实际场景

例如:在android中我给一个ImageView设置了一个点击事件,代码如下:

mIvLogo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                System.out.println("Hello");
            }
        });

那么我们用lambda表达式的代码如下:

mIvLogo.setOnClickListener(v -> System.out.println("Hello"));

匿名类型最大的问题就在于其冗余的语法。有人戏称匿名类型导致了“高度问题”(height problem):在 OnClickListener这个例子里的五行代码中仅有一行在做实际工作,但是我们不得不写5行代码。

lambda语法

lambda表达式由三部分组成:

Argument List Arrow Token Body
(int x, int y) -> x + y

lambda 表达式的语法格式如下:

(parameters) -> expression 或 (parameters) ->{ statements; }

以下是lambda表达式的重要特征:

  • 可选类型声明:无需声明参数的类型。编译器可以跟参数的值推断出参数的类型。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数必须定义圆括号。
  • 可选的大括号:如果Body只包含一个语句,可以不使用大括号。
  • 可选的返回关键字:如果Body只有一个表达式返回值则编译器会自动返回值(无需写return关键字),需要花括号表示表达式返回值。

lambda语法范例

public class Java8Tester {
    public static void main(String[] args) {
        Java8Tester tester = new Java8Tester();

        //含类型声明
        MathOperation addition = (int a, int b) -> a + b;

        //无类型声明
        MathOperation subtraction = (a, b) -> a - b;

        //带有大括号的返回语句
        MathOperation multiplication = (int a, int b) -> { return a * b; };

        //不带大括号和return语句
        MathOperation division = (int a, int b) -> a / b;

        System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
        System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
        System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
        System.out.println("10 / 5 = " + tester.operate(10, 5, division));

        //参数不带圆括号
        GreetingService greetService1 = message ->
                System.out.println("Hello " + message);

        //参数带圆括号
        GreetingService greetService2 = (message) ->
                System.out.println("Hello " + message);

        greetService1.sayMessage("Mahesh");
        greetService2.sayMessage("Suresh");
    }

    interface MathOperation {
        int operation(int a, int b);
    }

    interface GreetingService {
        void sayMessage(String message);
    }

    private int operate(int a, int b, MathOperation mathOperation){
        return mathOperation.operation(a, b);
    }
}

lambda表达式在android中使用

android studio配置

下面介绍一下官方和三方的支持:

android官方支持

在Android Studio 3.0之后

Android Studio 3.0预览1及更高版本支持对Java 8语言进行了支持,要想使用java8的功能,请确保你的Android Plugin for Gradle版本为3.0.0-alpha1(或更高)。然后在你模块级别的 build.gradle 文件中添加以下内容:

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

在Android Studio 3.0之前

要为您的项目启用 Java 8 语言功能和 Jack,请在主model的 build.gradle 文件中输入以下内容:

android {
  ...
  defaultConfig {
    ...
    jackOptions {
      enabled true
    }
  }
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

注意:

  • Jack 仅在 Android Studio 2.1 和更高版本上才受支持。
  • 使用Jack的话将会导致Instant Run不可用

三方支持库

retrolambda插件

下面介绍一下如何使用:

step1 在project级别的 build.gradle文件中添加如下代码:

buildscript {
   repositories {
     // Required because retrolambda is on maven central
      mavenCentral()
   }

   dependencies {
      classpath 'me.tatarka:gradle-retrolambda:3.6.1'
   }
}

step2 在主model的 build.gradle文件中添加如下代码:

apply plugin: 'me.tatarka.retrolambda'
android {
  ...
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

在android中的使用场景

new Handler().postDelayed(() -> {
    Toast.makeText(this, "2s后执行", Toast.LENGTH_SHORT).show();
}, 2000);
mIvLogo.setOnLongClickListener(v -> {
    System.out.println("onLongClick");
    return false;
});
mIvLogo.setOnTouchListener((v, event) -> {
    if(event.getAction() == MotionEvent.ACTION_DOWN){
        System.out.println("ACTION_DOWN");
    }
    return false;
});

注意:必须是函数式接口才可以使用lambda表达式。

参考文档

oracle官网文档 Lambda Quick Start

oracle官网文档 Lambda Expressions

android官方文档 使用 Java 8 语言功能

android studio 3.0预览版功能介绍 [Use Java 8 language features](

本文链接:http://www.itzhouyang.com/post/lambda-expressions.html

-- EOF --

Comments