Kotlin

Kotlin:高阶函数和Lambda表达式到底是什么?

2020-06-02  本文已影响0人  512DIDIDI

kotlin中函数作为一等公民,成为独有的函数类型,在高阶函数中,既可作为参数传递,也可作为函数返回值。那么实际上,高阶函数到底是什么呢?
为了介绍高阶函数和Lambda表达式是什么,首先先简单引入下高阶函数:

高阶函数是将函数用作参数或返回值的函数。

简明扼要,简单写一个高阶函数:

/**
 * 参数类型包含函数类型
 */
fun lambdaParam(block: (Int) -> Unit) {
  block(2)
}

/**
 * 返回值为函数类型
 */
fun lambdaReturn(): (Int) -> Int {
  return {
    it * 2
  }
}

上面解释了高阶函数的简单用法,那么为什么kotlin能这么用,而java不行呢?使用JD-GUI反编译成java代码看一下:

public static final void lambdaParam(@NotNull Function1 block) {
  Intrinsics.checkParameterIsNotNull(block, "block");
  block.invoke(Integer.valueOf(2));
}

@NotNull
public static final Function1<Integer, Integer> lambdaReturn() {
  return LambdaKt$lambdaReturn$1.INSTANCE;
}

@Metadata(mv = {1, 1, 16}, bv = {1, 0, 3}, k = 3, d1 = {"\000\n\n\000\n\002\020\b\n\002\b\002\020\000\032\0020\0012\006\020\002\032\0020\001H\n\006\002\b\003"}, d2 = {"<anonymous>", "", "it", "invoke"})
static final class LambdaKt$lambdaReturn$1 extends Lambda implements Function1<Integer, Integer> {
  public static final LambdaKt$lambdaReturn$1 INSTANCE = new LambdaKt$lambdaReturn$1();

  public final int invoke(int it) {
    return it * 2;
  }

  LambdaKt$lambdaReturn$1() {
    super(1);
  }
}

是不是恍然大悟,哦,这就是Java的接口嘛。所谓的lambda表达式,实际上是继承自Lambda类,实现了一个Function1接口,而且其内部的invoke方法,默认有个it传参,所以使用时不需要写出参数名和类型,实质上,就跟Java实现匿名内部类的做法一样。
那么Function1接口是什么?跟踪下:

package kotlin.jvm.functions

/** A function that takes 0 arguments. */
public interface Function0<out R> : Function<R> {
  /** Invokes the function. */
  public operator fun invoke(): R
}
/** A function that takes 1 argument. */
public interface Function1<in P1, out R> : Function<R> {
  /** Invokes the function with the specified argument. */
  public operator fun invoke(p1: P1): R
}
/** A function that takes 2 arguments. */
public interface Function2<in P1, in P2, out R> : Function<R> {
  /** Invokes the function with the specified arguments. */
  public operator fun invoke(p1: P1, p2: P2): R
}
/** A function that takes 3 arguments. */
public interface Function3<in P1, in P2, in P3, out R> : Function<R> {
  /** Invokes the function with the specified arguments. */
  public operator fun invoke(p1: P1, p2: P2, p3: P3): R
}
.... ...

kotlin定义了一堆的FunctionX接口,

  1. <in P1...,out R>其中前面的P1 P2用来适配不同个数参数的函数,R代表函数的返回值,
    例如刚才上例中用的(Int) ->UnitFuncion1,也就是接收一个参数Int,返回值为Unit的函数
  2. 在每个FunctionX接口中还添加了一个invoke操作符重载方法,重载的也就是()这个操作符,因此我们在例子中才可以使用block(Int),实际上就是使用Function1().invoke(p1:P1)方法。
    所有的FunctionX接口都实现了Function<R>接口,其实也就是函数返回值。

那么lambda表达式继承的Lambda类又是什么呢?继续跟踪:

package kotlin.jvm.internal
import java.io.Serializable
abstract class Lambda<out R>(override val arity: Int) : FunctionBase<R>, Serializable {
  override fun toString(): String = Reflection.renderLambdaToString(this)
}

... ...

interface FunctionBase<out R> : Function<R> {
  val arity: Int
}

原来也是实现了Function接口的一个抽象类。

Java调用kotlin高阶函数

java8之前:通过实现匿名接口类来调用kotlin的高阶函数:

LambdaKt.lambdaParam(new Function1<Integer, Unit>() {
  @Override
  public Unit invoke(Integer integer) {
    return null;
  }
});

java8之后:由于java8支持了SAM的lambda表达式,而由于kotlin中的lambda表达式本身实现的Function接口也是只有一个方法,因此同kotlin中调用相同:

LambdaKt.lambdaParam(i-> null);

总结

上一篇 下一篇

猜你喜欢

热点阅读