try-with-resources:"use" Kotlin 中的扩展函数并不总是有效
try-with-resources: "use" extension function in Kotlin does not always work
我在用 Kotlin 表达 Java 的 try-with-resources 结构时遇到了一些问题。在我的理解中,每个作为 AutoClosable
实例的表达式都应该提供 use
扩展函数。
这是一个完整的例子:
import java.io.BufferedReader;
import java.io.FileReader;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.TupleQueryResult;
public class Test {
static String foo(String path) throws Throwable {
try (BufferedReader r =
new BufferedReader(new FileReader(path))) {
return "";
}
}
static String bar(TupleQuery query) throws Throwable {
try (TupleQueryResult r = query.evaluate()) {
return "";
}
}
}
Java-to-Kotlin 转换器创建此输出:
import java.io.BufferedReader
import java.io.FileReader
import org.openrdf.query.TupleQuery
import org.openrdf.query.TupleQueryResult
object Test {
@Throws(Throwable::class)
internal fun foo(path: String): String {
BufferedReader(FileReader(path)).use { r -> return "" }
}
@Throws(Throwable::class)
internal fun bar(query: TupleQuery): String {
query.evaluate().use { r -> return "" } // ERROR
}
}
foo
工作正常,但 bar
中的代码无法编译:
Error:(16, 26) Kotlin: Unresolved reference.
None of the following candidates is applicable
because of receiver type mismatch:
public inline fun <T : java.io.Closeable, R>
???.use(block: (???) -> ???): ??? defined in kotlin.io
query.evaluate()
来自 Sesame 并实现了 AutoClosable
。是 Kotlin 错误,还是它不起作用的原因?
我将 IDEA 15.0.3 与 Kotlin 1.0.0-beta-4584-IJ143-12 和以下 sasame-runtime
版本一起使用:
<groupId>org.openrdf.sesame</groupId>
<artifactId>sesame-runtime</artifactId>
<version>4.0.2</version>
Kotlin 目前的目标是 Java 6,所以它的标准库不使用 AutoCloseable
接口。 use
函数只支持Java6Closeable
接口。请参阅 the issue tracker 以供参考。
您可以在项目中创建 use
函数的副本并修改它以将 Closeable
替换为 AutoCloseable
:
public inline fun <T : AutoCloseable, R> T.use(block: (T) -> R): R {
var closed = false
try {
return block(this)
} catch (e: Exception) {
closed = true
try {
close()
} catch (closeException: Exception) {
e.addSuppressed(closeException)
}
throw e
} finally {
if (!closed) {
close()
}
}
}
对于不支持"use"功能的类,我做了下自制的try-with-resources:
inline fun <T:AutoCloseable,R> trywr(closeable: T, block: (T) -> R): R {
try {
return block(closeable);
} finally {
closeable.close()
}
}
那你就可以用下面的方法了:
fun countEvents(sc: EventSearchCriteria?): Long {
return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
var rs = it.executeQuery()
rs.next()
rs.getLong(1)
}
}
Kotlin 1.1+ 有一个标准库,目标是 Java 8 以支持 Closeable resource
模式 - kotlin-stdlib-jre8
Gradle
compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.1"
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:1.1.1"
Maven
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jre8</artifactId>
<version>1.1.1</version>
</dependency>
示例
val resource: AutoCloseable = getCloseableResource()
resource.use { r -> //play with r }
只需确保类路径中有kotlin-stdlib-jdk7.jar,默认不添加
我在用 Kotlin 表达 Java 的 try-with-resources 结构时遇到了一些问题。在我的理解中,每个作为 AutoClosable
实例的表达式都应该提供 use
扩展函数。
这是一个完整的例子:
import java.io.BufferedReader;
import java.io.FileReader;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.TupleQueryResult;
public class Test {
static String foo(String path) throws Throwable {
try (BufferedReader r =
new BufferedReader(new FileReader(path))) {
return "";
}
}
static String bar(TupleQuery query) throws Throwable {
try (TupleQueryResult r = query.evaluate()) {
return "";
}
}
}
Java-to-Kotlin 转换器创建此输出:
import java.io.BufferedReader
import java.io.FileReader
import org.openrdf.query.TupleQuery
import org.openrdf.query.TupleQueryResult
object Test {
@Throws(Throwable::class)
internal fun foo(path: String): String {
BufferedReader(FileReader(path)).use { r -> return "" }
}
@Throws(Throwable::class)
internal fun bar(query: TupleQuery): String {
query.evaluate().use { r -> return "" } // ERROR
}
}
foo
工作正常,但 bar
中的代码无法编译:
Error:(16, 26) Kotlin: Unresolved reference.
None of the following candidates is applicable
because of receiver type mismatch:
public inline fun <T : java.io.Closeable, R>
???.use(block: (???) -> ???): ??? defined in kotlin.io
query.evaluate()
来自 Sesame 并实现了 AutoClosable
。是 Kotlin 错误,还是它不起作用的原因?
我将 IDEA 15.0.3 与 Kotlin 1.0.0-beta-4584-IJ143-12 和以下 sasame-runtime
版本一起使用:
<groupId>org.openrdf.sesame</groupId>
<artifactId>sesame-runtime</artifactId>
<version>4.0.2</version>
Kotlin 目前的目标是 Java 6,所以它的标准库不使用 AutoCloseable
接口。 use
函数只支持Java6Closeable
接口。请参阅 the issue tracker 以供参考。
您可以在项目中创建 use
函数的副本并修改它以将 Closeable
替换为 AutoCloseable
:
public inline fun <T : AutoCloseable, R> T.use(block: (T) -> R): R {
var closed = false
try {
return block(this)
} catch (e: Exception) {
closed = true
try {
close()
} catch (closeException: Exception) {
e.addSuppressed(closeException)
}
throw e
} finally {
if (!closed) {
close()
}
}
}
对于不支持"use"功能的类,我做了下自制的try-with-resources:
inline fun <T:AutoCloseable,R> trywr(closeable: T, block: (T) -> R): R {
try {
return block(closeable);
} finally {
closeable.close()
}
}
那你就可以用下面的方法了:
fun countEvents(sc: EventSearchCriteria?): Long {
return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
var rs = it.executeQuery()
rs.next()
rs.getLong(1)
}
}
Kotlin 1.1+ 有一个标准库,目标是 Java 8 以支持 Closeable resource
模式 - kotlin-stdlib-jre8
Gradle
compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.1"
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:1.1.1"
Maven
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jre8</artifactId>
<version>1.1.1</version>
</dependency>
示例
val resource: AutoCloseable = getCloseableResource()
resource.use { r -> //play with r }
只需确保类路径中有kotlin-stdlib-jdk7.jar,默认不添加