kotlin是Java最好的语法糖

高阶函数

函数是对过程的抽象,普通函数有一个限定条件是函数的参数和返回值必须是具体的类型,而高阶函数则去处了这个限定条件,允许函数的参数和返回值是函数类型。

fun build(test: ()-> String){
    test()
  }

上述kotlin代码中build方法允许传入一个()->String的函数类型,那么kotlin是怎么实现该功能的呢?反编译为Java方法如下

public final void build(@NotNull Function0 test) {
      Intrinsics.checkParameterIsNotNull(test, "test");
      test.invoke();
   }

该Function0接口如下

/** A function that takes 0 arguments. */
public interface Function0<out R> : Function<R> {
    /** Invokes the function. */
    public operator fun invoke(): R
}

可以发现,实际上对应的java方法是通过传递一个Function0的接口,并在方法中调用接口invoke方法来实现的。

扩展函数

在Java中,扩展某个类或者对象的能力,一般会使用继承或者代理或者装饰器等方式来实现,而kotlin在语法层面就实现了。比如给String类扩展一个test方法,

fun String.test():String{
    return "test"
  }

在使用时可以直接调用"aa".test(),那么kotlin是怎么实现的呢?反编译代码可以看到起对应的Java代码如下

@NotNull
   public final String test(@NotNull String $this$test) {
      Intrinsics.checkParameterIsNotNull($this$test, "$this$test");
      return "test";
   }

因为我是直接将扩展函数放在具体的kotlin类中,所以其在该类生成了第一个参数为String的public final方法,可以看到,kotlin的扩展函数实际上时通过语法糖的形式自动生成方法,而没有修改字节码,也不会造成性能开销。

Lambda表达式

Lambda表达式也是一种语法糖,而且和高阶函数还不太好区分,一般而言,高阶函数必须用->来隔离函数参数和参数返回值,而Lambda表达式必须用{}包裹,如下我们在kotlin文件中申明了如下Lambda表达式

val bds = { x: Int ->
  val y = x + 1
  y
}

上述我们定义了一个Lambda表达式,作用是给每个参数的值加1并返回,调用的方式如下:

fun String.test():String{
  return "adad" + bds(1)
}

上述我们定义了一个扩展函数,在扩展函数中调用了bds这个lambda表达式,那么Lambda表达式这个语法糖是如何工作的呢?我们来看一下反编译成Java的代码

@NotNull
   private static final Function1 bds;

   @NotNull
   public static final String test(@NotNull String $this$test) {
      Intrinsics.checkParameterIsNotNull($this$test, "$this$test");
      return "adad" + ((Number)bds.invoke(1)).intValue();
   }

   @NotNull
   public static final Function1 getBds() {
      return bds;
   }

   static {
      bds = (Function1)null.INSTANCE;
   }

可以从代码中看到,bds变量被申明为Function1接口,在static块中初始化,而test高阶函数中是通过调用bds的invoke方法来获取返回值的。看上去,Lambda表达式和扩展函数有类似的实现原理,都是基于FunctionN(N表示数字)接口来实现。如果了解Java中Lambda的实现,你会发现其实很相似。