Kotlin use函数的魔法

原文地址:https://blog.qjm253.cn/?p=391

魔法预览

  • 实现了Closeable接口的对象可调用use函数
  • use函数会自动关闭调用者(无论中间是否出现异常)
  • Kotlin的File对象和IO流操作变得行云流水

use函数的原型

/**
 * Executes the given [block] function on this resource and then closes it down correctly whether an exception
 * is thrown or not.
 *
 * @param block a function to process this [Closeable] resource.
 * @return the result of [block] function invoked on this resource.
 */
@InlineOnly
@RequireKotlin("1.2", versionKind = RequireKotlinVersionKind.COMPILER_VERSION, message = "Requires newer compiler version to be inlined correctly.")
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
    var exception: Throwable? = null
    try {
        return block(this)
    } catch (e: Throwable) {
        exception = e
        throw e
    } finally {
        when {
            apiVersionIsAtLeast(1, 1, 0) -> this.closeFinally(exception)
            this == null -> {}
            exception == null -> close()
            else ->
                try {
                    close()
                } catch (closeException: Throwable) {
                    // cause.addSuppressed(closeException) // ignored here
                }
        }
    }
}
  • 可以看出,use函数内部实现也是通过try-catch-finally块捕捉的方式,所以不用担心会有异常抛出导致程序退出
  • close操作在finally里面执行,所以无论是正常结束还是出现异常,都能正确关闭调用者

来一波对比

  • 实现读取一个文件内每一行的功能

    • java实现
      FileInputStream fis = null;
      DataInputStream dis = null;
      try {
          fis = new FileInputStream("/home/test.txt");
          dis = new DataInputStream(new BufferedInputStream(fis));
          String lines = "";
          while((lines = dis.readLine()) != null){
              System.out.println(lines);
          }
      } catch (IOException e){
          e.printStackTrace();
      } finally {
          try {
              if(dis != null)
                  dis.close();
          } catch (IOException e) {
              e.printStackTrace();
          }
          try {
              if(fis != null)
                  fis.close();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
      
    • Kotlin实现
      File("/home/test.txt").readLines()
              .forEach { println(it) }
      
    • 对Kotlin就是可以两行实现。
    • 仔细翻阅readLines这个扩展函数的实现你会发现,它也是间接调用了use,这样就省去了捕捉异常和关闭的烦恼
    • 同样的,经过包装以后你只需要关注读出来的数据本身而不需要care各种异常情况
  • File的一些其它有用的扩展函数

    /**
    * 将文件里的所有数据以字节数组的形式读出
    * Tip:显然这不适用于大文件,文件过大,会导致创建一个超大数组
    */
    public fun File.readBytes(): ByteArray
    
    /**
    * 与上一个函数类似,不过这个是写(如果文件存在,则覆盖)
    */
    public fun File.writeBytes(array: ByteArray): Unit
    
    /**
    * 将array数组中的数据添加到文件里(如果文件存在则在文件尾部添加)
    */
    public fun File.appendBytes(array: ByteArray): Unit
    
    
    /**
    * 将文件以指定buffer大小,分块读出(适用于大文件,也是最常用的方法)
    */
    public fun File.forEachBlock(action: (buffer: ByteArray, bytesRead: Int) -> Unit): Unit
    
    /**
     * Gets the entire content of this file as a String using UTF-8 or specified [charset].
     *
     * This method is not recommended on huge files. It has an internal limitation of 2 GB file size.
     *
     * @param charset character set to use.
     * @return the entire content of this file as a String.
     */
    public fun File.readText(charset: Charset = Charsets.UTF_8): String
    
    /**
     * Sets the content of this file as [text] encoded using UTF-8 or specified [charset].
     * If this file exists, it becomes overwritten.
     *
     * @param text text to write into file.
     * @param charset character set to use.
     */
    public fun File.writeText(text: String, charset: Charset = Charsets.UTF_8): Unit
    
    /**
     * Appends [text] to the content of this file using UTF-8 or the specified [charset].
     *
     * @param text text to append to file.
     * @param charset character set to use.
     */
    public fun File.appendText(text: String, charset: Charset = Charsets.UTF_8): Unit
    
    /**
     * Reads this file line by line using the specified [charset] and calls [action] for each line.
     * Default charset is UTF-8.
     *
     * You may use this function on huge files.
     *
     * @param charset character set to use.
     * @param action function to process file lines.
     */
    public fun File.forEachLine(charset: Charset = Charsets.UTF_8, action: (line: String) -> Unit): Unit
    
    
    /**
     * Reads the file content as a list of lines.
     *
     * Do not use this function for huge files.
     *
     * @param charset character set to use. By default uses UTF-8 charset.
     * @return list of file lines.
     */
    public fun File.readLines(charset: Charset = Charsets.UTF_8): List<String>
    
    
    /**
     * Calls the [block] callback giving it a sequence of all the lines in this file and closes the reader once
     * the processing is complete.
    
     * @param charset character set to use. By default uses UTF-8 charset.
     * @return the value returned by [block].
     */
    @RequireKotlin("1.2", versionKind = RequireKotlinVersionKind.COMPILER_VERSION, message = "Requires newer compiler version to be inlined correctly.")
    public inline fun <T> File.useLines(charset: Charset = Charsets.UTF_8, block: (Sequence<String>) -> T): T
    
    • 上面的函数都是基于use实现的,可以放心使用,而不用担心异常的发生,并且会自动关闭IO流
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,907评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,546评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,705评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,624评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,940评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,371评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,672评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,396评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,069评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,350评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,876评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,243评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,847评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,004评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,755评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,378评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,266评论 2 259

推荐阅读更多精彩内容