try-with-resources / use / multiple resources

前端 未结 4 1789
臣服心动
臣服心动 2021-02-20 01:07

I\'m using a Java-API which heavily uses the Autoclosable-Interface and thus in Java try-with-resources. However in Java you can specify



        
4条回答
  •  借酒劲吻你
    2021-02-20 01:48

    • Method 1: For two resources and using native java resource manager:

      1. Define jUsing() in Kotlin:

        // crossinline version:
        inline fun 
                jUsing(a: A, b: B, crossinline block: (A, B) -> R): R = 
            J.jUsing(a, b) { c, d -> block(c, d) }
        
      2. And also Util.jUsing() in Util.java:

        Note: Below code is compatible with Java 9+. You can implement it with try-catch-finally to make it compatible with previous versions. See here for an example.

        public static  R 
        jUsing(A a, B b, Function2 block) throws Exception {
            try (a; b) {
                return block.invoke(a, b);
            }
        }
        

        (Function2 is kotlin.jvm.functions.Function2.)

      3. Then use like below:

        // Download url to destFile and close streams correctly:
        jUsing(URL(url).openStream(), FileOutputStream(destFile), InputStream::transferTo)
        

        Note: Above code used Java 9+ InputStream.transferTo() method. See here for a transferTo() Kotlin alternative that is compatible with previous versions.


      Note: You can write Kotlin jUsing() method more simple using noinline keyword instead of crossinline. But I think crossinline version has more performance:

      // noinline version:
      inline fun 
              jUsing(a: A, b: B, noinline block: (A, B) -> R): R =
              Util.jUsing(a, b, block)
      

    • Method 2: For two resources (and with similar usage to method 1):

      Thank @zsmb13's answer for the link

      /**
       * Based on https://github.com/FelixEngl/KotlinUsings/blob/master/Usings.kt
       * and with some changes
       */
      inline fun  using(a: A, b: B, block: (A, B) -> R): R {
          var exception: Throwable? = null
      
          try {
              return block(a, b)
          } catch (e: Throwable) {
              exception = e
              throw e
          } finally {
              if (exception == null) {
                  a.close()
                  b.close()
              } else {
                  try {
                      a.close()
                  } catch (closeException: Throwable) {
                      exception.addSuppressed(closeException)
                  }
                  try {
                      b.close()
                  } catch (closeException: Throwable) {
                      exception.addSuppressed(closeException)
                  }
              }
          }
      }
      

    • Method 3: For any number of resources (arrayOf(stream1, stream2, ...).use {...}):

      /**
       * Based on https://medium.com/@appmattus/effective-kotlin-item-9-prefer-try-with-resources-to-try-finally-aec8c202c30a
       * and with a few changes
       */
      inline fun  Array.use(block: (Array) -> R): R {
          var exception: Throwable? = null
      
          try {
              return block(this)
          } catch (e: Throwable) {
              exception = e
              throw e
          } finally {
              when (exception) {
                  null -> forEach { it?.close() }
                  else -> forEach {
                      try {
                          it?.close()
                      } catch (closeException: Throwable) {
                          exception.addSuppressed(closeException)
                      }
                  }
              }
          }
      }
      

      See referenced link for more details.

提交回复
热议问题