【发布时间】:2018-09-23 19:43:06
【问题描述】:
我想编写一个方便的扩展来从 Map 中提取值,同时解析它们。如果解析失败,该函数应该返回一个默认值。这一切都很好,但我想告诉 Kotlin 编译器,当默认值不为 null 时,结果也不会为 null。我可以通过 @Contract 注释在 Java 中实现这一点,但它似乎在 Kotlin 中不起作用。这可以做到吗?合同不适用于扩展功能吗?这是 kotlin 的尝试:
import org.jetbrains.annotations.Contract
private const val TAG = "ParseExtensions"
@Contract("_, !null -> !null")
fun Map<String, String>.optLong(key: String, default: Long?): Long? {
val value = get(key)
value ?: return default
return try {
java.lang.Long.valueOf(value)
} catch (e: NumberFormatException) {
Log.e(TAG, e)
Log.d(TAG, "Couldn't convert $value to long for key $key")
default
}
}
fun test() {
val a = HashMap<String, String>()
val something: Long = a.optLong("somekey", 1)
}
在上面的代码中,IDE 将突出显示分配给something 的错误,尽管调用 optLong 时使用了非空默认值 1。作为比较,这里有类似的代码,通过注释和合约测试可空性在 Java 中:
public class StackoverflowQuestion
{
@Contract("_, !null -> !null")
static @Nullable Long getLong(@NonNull String key, @Nullable Long def)
{
// Just for testing, no real code here.
return 0L;
}
static void testNull(@NonNull Long value) {
}
static void test()
{
final Long something = getLong("somekey", 1L);
testNull(something);
}
}
上面的代码没有显示任何错误。只有当 @Contract 注释被删除时,IDE 才会警告对 testNull() 的调用可能为空值。
【问题讨论】:
-
为什么还要有默认值?只需让方法调用者以与您相同的方式处理它。如果
value为空,则返回空。map.optLong("key") ?: 6L -
另外,考虑使用
string.toLongOrNull()而不是Long.valueOf(string)它会自动处理错误格式。 -
@killjoy 使用 null 作为默认值可能意味着几件事,而不仅仅是找不到值。如果他认为使用空默认值对这个用例有好处,那么可以添加使
default参数默认为null
标签: android kotlin nullable static-analysis