第六章 函数进阶

  1. 高阶函数

    函数参数包含函数类型或者返回值包含函数类型

    public inline fun IntArray.forEach(action: (Int) -> Unit): Unit {
        for (element in this) action(element)
    }
    复制代码
    // 示例代码
    intArrayOf(1, 1).map{"value = $it"}.forEach(::print)
    
    // 具体实现
    // transform 函数类型:(Int)-> String
    public inline fun <R> IntArray.map(transform: (Int) -> R): List<R> {
        return mapTo(ArrayList<R>(size), transform)
    }
    
    // mapTo 函数 是将原Int数组转换成String数组
    public inline fun <R, C : MutableCollection<in R>> IntArray.mapTo(destination: C, transform: (Int) -> R): C {
        for (item in this)
            destination.add(transform(item))
        return destination
    }
    复制代码
  2. 内联函数

    需要使用inline关键字,一般是高阶函数使用,作用是将lambda表达式替换为实际的代码,避免创建对象

    intArrayOf(1, 1).map{"value = $it"}.forEach(::print)
    复制代码

    反编译看源码,Tools->Kotlin->Show Kotlin ByteCode ->Decompile

    // 实际代码
    int[] $this$map$iv = new int[]{1, 1};
    int $i$f$forEach = false;
    Collection destination$iv$iv = (Collection)(new ArrayList($this$map$iv.length));
    int $i$f$mapTo = false;
    int[] var5 = $this$map$iv;
    int var6 = $this$map$iv.length;
    
    // 重新创建集合
    for(int var7 = 0; var7 < var6; ++var7) {
       int item$iv$iv = var5[var7];
       int var10 = false;
       String var12 = "value = " + item$iv$iv;
       destination$iv$iv.add(var12);
    }
    
    Iterable $this$forEach$iv = (Iterable)((List)destination$iv$iv);
    $i$f$forEach = false;
    Iterator var2 = $this$forEach$iv.iterator();
    
    // 遍历集合并打印
    while(var2.hasNext()) {
       Object element$iv = var2.next();
       int var15 = false;
       boolean var16 = false;
       System.out.print(element$iv);
    }
    复制代码
    1. local return

      intArrayOf(1, 2, 3).forEach {
          if (it == 1)
          	// 当元素==1时,结束本次的forEach
              return@forEach
          println(it)
      }
      
      // 上述等价写法:
      val intArrayOf = intArrayOf(1, 2, 3)
      for (element in intArrayOf) {
          if (element == 1) continue
          print(element)
      }
      复制代码
    2. non-local return

      inlineTest {
          println("")
          // 此处直接return main方法
          return
      }
      println("main end")
      
      inline fun inlineTest(block1: () -> Unit) {
          block1()
      }
      复制代码
    3. noinline

      内联函数的有多个函数参数,并且某一个函数参数不需要内联时可以使用noinline

    4. crossinline

      因为inline会存在local return 和 non-local return的情况,在下面情况会存在误解

      fun main() {
          inlineTest {
              println("")
              return
          }
          println("main end")
      }
      
      inline fun inlineTest(block1: () -> Unit) {
          thread {
          	// 编译报错
              block1()
          }
      }
      复制代码

      处理方法

      fun main() {
          inlineTest {
              println("")
              // local return
              return@inlineTest
          }
          println("main end")
      }
      
      // 添加crossinline关键字
      inline fun inlineTest(crossinline block1: () -> Unit) {
          thread {
              block1()
          }
      }
      复制代码
  3. let run also apply use

    1. let run

      最后一行非赋值代码是闭包的返回值,否则返回Unit。

    2. also apply

      返回值为当前对象

    3. use 自动关闭资源

      File("ktpractice.iml").inputStream().reader().buffered()
          .use {
              var line: String
              while (it.readLine().also { line = it } != null) {
                  println(line)
              }
          }
      复制代码
  4. 集合变换与序列

    1. filter 过滤

    2. map 映射

    3. flatMap 变换

      元素映射为集合,将集合拼接为新集合

    4. sum

    5. reduce

      fun main() {
          val list = arrayListOf(1, 2, 3, 4)
          val reduce = list.reduce { acc, i ->
              acc + i
          }
          println(reduce)
      }
      
      // 输出 10
      复制代码
    6. fold 初始值和拼接操作

      fun main() {
          val list = arrayListOf(1, 2, 3, 4)
          val fold = list.foldRight(StringBuilder()) { i, acc ->
              acc.append(i)
          }
          println(fold)
      }
      
      // 输出 4321
      复制代码
    7. 懒序列

      val list = arrayListOf(1, 2, 3, 4)
      val map = list.filter {
          print("$it    ")
          it % 2 == 0
      }.map {
          print("$it    ")
          it + 1
      }
      println("result: $map")
      
      // 输出 
      filter: 1    
      filter: 2    
      filter: 3    
      filter: 4    
      map: 2    
      map: 4    
      result: [3, 5]
      复制代码

      相比于上面,懒序列多了asSequence()

      fun main() {
          val list = arrayListOf(1, 2, 3, 4)
          val map = list.asSequence().filter {
              print("$it    ")
              it % 2 == 0
          }.map {
              print("$it    ")
              it + 1
          }
          println("result: $map")
      }
      
      // 输出map的地址,
      复制代码

      遇到terminal operator 才会生成结果

      fun main() {
          val list = arrayListOf(1, 2, 3, 4)
          list.asSequence().filter {
              println("filter: $it    ")
              it % 2 == 0
          }.map {
              println("map: $it    ")
              it + 1
          }.forEach(::println)
      }
      
      // 输出:
      filter: 1    
      filter: 2    
      map: 2    
      3
      filter: 3    
      filter: 4    
      map: 4    
      5
      复制代码
  5. SAM(single abstract method)转换

    Kotlin与java8的SAM转换对比

  6. 案例

    1. 统计字符个数

      File("ktpractice.iml").readText().toCharArray()
          .filterNot(Char::isWhitespace)
          .groupBy { it }
          .map { it.key to it.value.size }
          .sortedByDescending { it.second }
          .forEach(::println)
      复制代码
    2. HTML DSL

      public class WeekQuery  {
      
          private static final String TIME_TEMPLATE = "(day between '%s' and '%s')";
      
          private int mYear;
          private int mWeek;
      
          public WeekQuery(int year, int week) {
              mYear = year;
              mWeek = week;
          }
      
          public String getWhereClause() {
              LocalDate firstMondayOfYear = Stream.iterate(LocalDate.of(mYear, 1, 1), date -> date.plusDays(1))
                      .limit(7)
                      .filter(date -> date.getDayOfWeek() == DayOfWeek.MONDAY)
                      .collect(Collectors.toList())
                      .get(0);
              LocalDate destMondayOfYear = firstMondayOfYear.plusWeeks(mWeek - 1);
              return String.format(TIME_TEMPLATE, destMondayOfYear, destMondayOfYear.plusDays(6));
          }
      
          public static void main(String[] args) {
              for (int i = 1; i < 55; i++) {
                  WeekQuery weekQuery = new WeekQuery(2018, i);
                  System.out.println(i + "周  " + weekQuery.getWhereClause());
              }
              showWeeks(1, 55);
          }
      
          public static void showWeeks(int initWeek, int weeks) {
              LocalDate initData = LocalDate.of(2018, 1, 1).plusWeeks(initWeek - 1);
              Stream.iterate(initData, date -> date.plusDays(7))
                      .limit(weeks)
                      .map(day -> day + "~" + day.plusDays(6)).forEach(System.out::println);
          }
      }
      复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享