前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >第6章 扩展函数与属性第6章 扩展函数与属性

第6章 扩展函数与属性第6章 扩展函数与属性

作者头像
一个会写诗的程序员
发布2018-08-17 14:26:18
4180
发布2018-08-17 14:26:18
举报

第6章 扩展函数与属性

在使用Java的时候,我们经常使用诸如StringUtil, DateUtil等等一堆工具类,代码写起来也比较冗长。举个例子,获取一个字符串的第一个字符值、最后一个字符值。如果我们用Java代码来写,通常是要先声明一个StringUtil类,然后在里面写相应的工具方法,代码可以是下面的这个样子

代码语言:javascript
复制
package com.easy.kotlin;

import static java.lang.System.out;

public class StringUtil {

    /**
     * 获取str的第一个字符值
     *
     * @param str
     * @return
     */
    public static String firstChar(String str) {
        if (str != null && str.length() > 0) {
            return str.charAt(0) + "";
        }
        return "";
    }

    /**
     * 获取str的最后一个字符值
     *
     * @param str
     * @return
     */
    public static String lastChar(String str) {
        if (str != null && str.length() > 0) {
            return str.charAt(str.length() - 1) + "";
        }
        return "";
    }

    public static void main(String[] args) {
        String str = "abc";
        out.println(StringUtil.firstChar(str)); // a
        out.println(StringUtil.lastChar(str)); // c
    }
}

我们可以看到 StringUtil.firstChar(str) 这样的调用方式不够简单直接。能不能直接这样调用

代码语言:javascript
复制
"abc".firstChar()
"abc".lastChar()

非常遗憾的是,在Java中我们无法给String类添加一个自定义方法。因为String类是JDK中内置的基础类,而且为final,不能修改。所以,Java程序员通常使用这样的一个变通的方法:开发一个StringUtil类,在里面封装所需要的String操作的方法。而不是修改或继承String类。

而情况到了Kotlin里面,就完全不一样了——我们完全可以自由扩展任何类的方法和属性。在不修改原类的情况下, Kotlin能给一个类扩展新功能而无需继承该类。

本章我们介绍Kotlin的扩展函数和属性。

6.1 扩展函数

Kotlin中提供了非常简单使用的扩展函数功能。我们可以为现有的类自由添加自定义的函数 。

6.1.1 给String类扩展两个函数

例如,我们现在给String类扩展两个函数:lastChar() 和 firstChar() , 实现代码如下

代码语言:javascript
复制
package com.easy.kotlin

fun String.lastChar(): String {
    if (this.length == 0) {
        return ""
    }
    return this[this.length - 1].toString()
}

fun String.firstChar(): String {
    if (this.length == 0) {
        return ""
    }
    return this[0].toString()
}

扩展函数的语法,我们用下图来简单说明

扩展函数的语法

然后,我们就可以在代码中直接调用了

代码语言:javascript
复制
fun main(args: Array<String>) {
    val str = "abc"
    println(str.firstChar()) // a
    println(str.lastChar()) // c
}

如果在其他package路径下面,需要 import 导入扩展函数

代码语言:javascript
复制
package com.easy.kotlin.tutorial // 跟扩展函数不在同一个包路径下面

import com.easy.kotlin.firstChar // 导入扩展函数 firstChar
import com.easy.kotlin.lastChar// 导入扩展函数 lastChar

fun main(args: Array<String>) {
    val str = "abc"
    str.firstChar() // 这样的调用方式要比 StringUtil.firstChar(str) 简单优雅许多
    str.lastChar() 
}

6.1.2 给 List 类扩展一个过滤函数

在上一章中我们介绍过List的filter函数。那么这个 filter 函数是怎样实现的呢? 如果我们自己来给List类扩展一个过滤函数,应该怎样去做呢?下面我们就来介绍。

为了更加深刻体会到 Kotlin 扩展功能的简单优雅性,我们先来看看在Java中是怎样实现的吧!首先,我们会去声明一个ListUtil 类,里面实现一个 List<T> filter(List<T> list, Predicate<T> p) 方法,代码如下

代码语言:javascript
复制
public class ListUtil<T> {
  /**
   * 根据谓词p 过滤 list 中的元素
   *
   * @param list
   * @param p
   * @return
   */
  public List<T> filter(List<T> list, Predicate<T> p) {
      List<T> result = new ArrayList<>();
      for (T t : list) {
          if (p.predicate(t)) {
              result.add(t);
          }
      }
      return result;
  }
}

其中,Predicate 接口声明如下

代码语言:javascript
复制
interface Predicate<T> {
    Boolean predicate(T t);
}

然后,我们在代码中这样使用这个 filter 方法

代码语言:javascript
复制
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(new Integer[] {1, 2, 3, 4, 5, 6, 7});
        ListUtil<Integer> listUtil = new ListUtil(); // 声明ListUtil对象
        List<Integer> result = listUtil.filter(list, (it) -> it % 2 == 1); // lambda 表达式
        out.println(result); // [1, 3, 5, 7]
    }

为了调用 filter 方法,我们还要声明一个ListUtil对象,费事。能不能直接像下面这样调用?

代码语言:javascript
复制
list.filter { it % 2 == 1 }

答案是肯定的,只不过是在Kotlin中,而不是在Java中。

我们就来使用Kotlin的扩展函数为List扩展一个filter函数,代码如下

代码语言:javascript
复制
fun <T> List<T>.filter(predicate: (T) -> Boolean): MutableList<T> {
    val result = ArrayList<T>()
    this.forEach {
        if (predicate(it)) {
            result.add(it)
        }
    }
    return result
}

这个函数的签名稍微有点复杂,我们用下图来形象化地简单说明

给List扩展的filter函数签名

然后,我们在代码中只需要这样调用即可

代码语言:javascript
复制
    val list = mutableListOf(1, 2, 3, 4, 5, 6, 7)
    val result = list.filter {
        it % 2 == 1
    }
    println(result) // [1, 3, 5, 7]

Kotlin的标准库API中使用扩展的功能,通过扩展Java的API,提供了大量的实用简单的函数。我们将在后面的关于文件IO、正则表达式、多线程等相关主题中介绍。

6.2 扩展属性

除了扩展一个类的函数,我们还可以扩展类属性。例如,我们给 MutableList 扩展两个属性:firstElement 和 lastElement , 实现代码如下

代码语言:javascript
复制
var <T> MutableList<T>.firstElement: T
    get() {
        return this[0]
    }
    set(value) {
        this[0] = value
    }

var <T> MutableList<T>.lastElement: T
    get() {
        return this[this.size - 1]
    }
    set(value) {
        this[this.size - 1] = value
    }

上面的代码中的扩展属性的语法说明如下图所示

扩展属性的语法

然后,我们就可以在代码中直接使用扩展的属性了

代码语言:javascript
复制
    val list = mutableListOf(1, 2, 3, 4, 5, 6, 7)

    println("list = ${list}") // list = [1, 2, 3, 4, 5, 6, 7]
    println(list.firstElement) // 调用getter 函数 , 值是 1
    println(list.lastElement) // 7

    list.firstElement = -1 // 调用 setter 函数
    list.lastElement = -7

    println("list = ${list}") // list = [-1, 2, 3, 4, 5, 6, -7]
    println(list.firstElement) // -1
    println(list.lastElement) // -7

扩展属性允许定义在类或者kotlin文件中,不允许定义在函数中。

6.3 扩展中的this关键字

我们有注意到,在上面的List的扩展函数filter的实现中,我们有用到一个this关键字

代码语言:javascript
复制
    this.forEach {
        if (predicate(it)) {
            result.add(it)
        }
    }

这里的 this 指的是 接收者对象(receiver object), 也就是调用扩展函数时, 在点号( . )之前指定的对象实例。

本章小结

扩展函数是Kotin非常方便实用的功能,使用扩展函数,我们的代码写起来也更加简单优雅。同时也正是通过这个特性,Kotlin 在Java API的基础上扩展了丰富实用的函数,我们将在后面的章节中看到。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.10.12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第6章 扩展函数与属性
    • 6.1 扩展函数
      • 6.1.1 给String类扩展两个函数
      • 6.1.2 给 List 类扩展一个过滤函数
    • 6.2 扩展属性
      • 6.3 扩展中的this关键字
        • 本章小结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档