Java Functional Programing

Table of Contents

1. Java Functional Programing

1.1. Overview

x.stream().filter(v -> v > 100).collect(Collectors.toList());

java 语法上最大的修改是针对 `v -> v > 100` 这种语法, 即 lambda.

Java 1.8 中大部分修改都是为了把下面的概念与 lambda 整合:

  1. 成员函数
  2. 静态函数
  3. 构造函数
  4. 匿名类

1.2. Functional interface

void foo(WhatType x) {
    x();
}

foo(v -> System.out.println(v));

lambda 类型应该是什么?

这里 WhatType 应该是一个函数类型:

  1. 接受一个 String 参数
  2. 返回 void

但函数并不是 java 的 first-class object, 所以 java 提供了一个 functional interface 的概念, 用 interface 类型来表示这里的 `void ()String` 函数类型

interface TakeStringAndReturnVoid {
    void accept(String x);
    // 只有 Object 中的函数可以被 functional interface 重写
    String toString();
}

public class playground {
    static void foo(TakeStringAndReturnVoid c) {
        c.accept("hello");
    }

    public static void main(String[] args) {
        foo(v -> System.out::println(v));
    }
}

functional interface 是指只包含了一个抽象函数的 interface (除了 Object 中的函数).

上面的 TakeStringAndReturnVoid 就是一个 functional interface, 但看起来有些啰嗦, 因为有可能我们还需要 TakeIntAndReturnVoid, TakeTwoIntAndReturnInt 这类的函数, 因为 java 在 java.util.function 包中提供了一些现成的 functional interface, 例如上面的 TakeStringAndReturnVoid 可以使用 `Consumer<String>` 来代替

static void foo(Consumer<String> c) {
    c.accept("hello");
}

1.3. Function Reference

// 静态函数
foo(v -> System.out.println(v));
// 非静态函数
Foo foo = new Foo();
foo(v -> foo.call(v));
// 成员函数
foo(v -> v.toString())
// 构造函数
foo(v -> new Foo(v));

上面的 lambda 看起来有点啰嗦, java 提供了一个新的 "::" 符号, 来直接引用函数, 简化 lambda 的写法:

// 静态函数
foo(System.out::println)
// 非表态函数
Foo foo = new Foo();
foo(Foo::call);
// 成员函数
foo(V::toString)
// 构造函数
foo(Foo::new);

1.4. Lambda

1.4.1. Overview

// 无参数
foo(() -> {});
// 有参数
foo((v1, v2) -> {} );
// function reference
foo(System.out::println);
// ...

1.4.2. 内部实现

android dx (d8) 的作法:

// --------------------
class:playground:

.method main

sget-object p0, L-$$Lambda$playground$hCiJTi8HgZjcT-orvsXBFmciT9I;->INSTANCE:L-$$Lambda$playground$hCiJTi8HgZjcT-orvsXBFmciT9I;

invoke-static {p0}, Lplayground;->foo(Ljava/util/function/Consumer;)V


.method static synthetic lambda$main$0(Ljava/lang/String;)V

sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;

invoke-virtual {v0, p0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

// --------------------
class:-$$Lambda$playground$hCiJTi8HgZjcT-orvsXBFmciT9I:

.method public final accept(Ljava/lang/Object;)V

invoke-static {p1}, Lplayground;->lambda$main$0(Ljava/lang/String;)V

翻译成 java 代码:

import java.util.function.Consumer;
import java.util.ArrayList;

class LambdaConsumer implements Consumer {
    @Override
    void accept(String v) {
        playground.callPrintln(v);
    }
}

public class playground {
    static void foo(Consumer<String> c) {
        c.accept("hello");
    }

    public static void callPrintln(String v) {
        System.out.println(v);
    }

    public static void main(String[] args) {
        // foo(v -> System.out.println(v));
        Consumer c = new LambdaConsumer();
        foo(c);
    }
}

所以 lambda 在 d8 (android dexer 8) 里是作为 "匿名类的语法糖" 来实现.

在 Java 8 中, lambda 使用 实现

1.5. Stream API

Stream API 是最主要的使用 lambda 的地方, 例如:

x.stream().filter(<lambda>).map(<lambda>).filter(<lambda>).collect(<lambda>)

1.5.1. source

1.5.1.1. Collection.stream()
1.5.1.2. Arrays.stream()
1.5.1.3. Stream.of(x..)
1.5.1.4. Stream.Builder

1.5.2. adapter

1.5.2.1. filter
1.5.2.2. map/flatMap
1.5.2.3. limit/skip
1.5.2.4. sorted

1.5.3. consumer

1.5.3.1. collect
1.5.3.2. forEach
1.5.3.3. reduce
1.5.3.4. allMatch/anyMatch
1.5.3.5. count
1.5.3.6. max/min
1.5.3.7. mapToXXX
1.5.3.8. toArray

1.5.4. Collectors

1.5.4.1. toList
1.5.4.2. toSet
1.5.4.3. joining

1.6. Misc

1.6.1. forEach

1.6.2. IntStream

IntStream (以及 LongStream, …) 还额外提供了一些和 int (long,…) 相关的操作, 例如 sum, average 等.

可以通过 mapToXXX 获得 XXXStream.

Author: [email protected]
Date: 2019-08-19 Mon 00:00
Last updated: 2022-02-26 Sat 00:02

知识共享许可协议