我有java函数(取自here):
/**
* Checks to see if a specific port is available.
*
* @param port the port to check for availability
*/
public static boolean available(int port) {
if (port < MIN_PORT_NUMBER || port > MAX_PORT_NUMBER) {
throw new IllegalArgumentException("Invalid start port: " + port);
}
ServerSocket ss = null;
DatagramSocket ds = null;
try {
ss = new ServerSocket(port);
ss.setReuseAddress(true);
ds = new DatagramSocket(port);
ds.setReuseAddress(true);
return true;
} catch (IOException e) {
} finally {
if (ds != null) {
ds.close();
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
/* should not be thrown */
}
}
}
return false;
}
我想用 Kotlin 重写它,而不需要丑陋的结构。
所以我找到了这个主题:
据我所知,我必须首先创建对象,并在
use
lambda 内部创建对象,我必须调用可能抛出异常的方法,但在的情况下
ServerSocket(port)
DatagramSocket(port)
构造函数中会抛出异常。所以看起来它不符合我的需求。
那么我怎样才能用 Kotlin 重写这段代码呢?
如果在构造函数中抛出异常,您将无法引用 close...我认为这可以用惯用的 kotlin 编写,如下所示:
return runCatching {
ServerSocket(port).use { ss ->
ss.reuseAddress = true
DatagramSocket(port).use { ds ->
ds.reuseAddress = true
}
}
}.isSuccess
如果构造函数抛出异常,则没有对象可以“关闭”。
您发现的 Java 代码看起来像是在将 try-with-resources 语句添加到该语言之前编写的。在现代 Java 中,它看起来更像是这样的:
public static boolean available(int port) {
if (port < MIN_PORT_NUMBER || port > MAX_PORT_NUMBER) {
throw new IllegalArgumentException("Invalid start port: " + port);
}
try (var ss = ServerSocket(port)) {
ss.setReuseAddress(true);
try (var ds = new DatagramSocket(port)) {
ds.setReuseAddress(true);
return true;
}
} catch (IOException e) {
return false;
}
}
将其转换为 Kotlin 可能看起来像这样:
fun available(port: Int): Boolean {
require(port in MIN_PORT_NUMBER..MAX_PORT_NUMBER) { "Invalid start port: $port" }
return try {
ServerSocket(port).use { ss ->
ss.setReuseAddress(true)
DatagramSocket(port).use { ds ->
ds.setReuseAddress(true)
true
}
}
} catch (_: IOException) {
false
}
}
kotlin 中的代码将如下所示
import java.io.IOException
import java.net.DatagramSocket
import java.net.ServerSocket
fun available(port: Int): Boolean {
if (port < MIN_PORT_NUMBER || port > MAX_PORT_NUMBER) {
throw IllegalArgumentException("Invalid start port: $port")
}
return try {
createAndConfigureServerSocket(port)
createAndConfigureDatagramSocket(port)
true
} catch (e: IOException) {
false
}
}
private fun createAndConfigureServerSocket(port: Int) {
ServerSocket(port).use { ss ->
ss.reuseAddress = true
ss.close()
}
}
private fun createAndConfigureDatagramSocket(port: Int) {
DatagramSocket(port).use { ds ->
ds.reuseAddress = true
}
}
const val MIN_PORT_NUMBER = 0
const val MAX_PORT_NUMBER = 65535