比较Kotlin中的两个选项

考虑一个id字段的类,它可能是空的,直到存储在数据库中:

class IdableK<T : IdableK<T>> : Comparable<T> { private var id : Long? = null } 

我想实现一个compareTo方法,如下所示:

  override fun compareTo(other: T): Int { if (id == null) { return -1; } if (other.id == null) { return 1; } return id!!.compareTo(other.id!!) } 

这是做这件事的正确方法吗? 会不会有一个简单的方法呢?

看看kotlin.comparisons包 。 例如你可以使用compareValues

 class IdableK<T : IdableK<T>> : Comparable<T> { private var id: Long? = null override fun compareTo(other: T) = compareValues(id, other.id) } 

这是不正确的。 如果你有两个ids被设置为null实例,那么当你调用compareTo(other)时,两个实例都会返回-1 ,而如果返回-1 ,另一个实例将返回-1 。 我不确定是否有情况下可以根据可空属性来实现compareTo ,但是我无法想象。 也许还有更好的办法吗?

此外,你应该避免非空断言( !! )。 既然你使用了var s,其他的线程可能会把这个值改为null,所以即使你之前做了一个空的检查,值现在也是空的!! 抛出。 相反,您应该将两个ID存储在局部变量中,并检查这些值是否为null值。

如果你绝对必须使用compareTo ,我会这样做:

 override fun compareTo(other: T): Int { val thisId = id val otherId = other.id if (thisId == null && otherId == null) return 0 if (thisId == null && otherId != null) return -1 if (thisId != null && otherId == null) return 1 // thisId and otherId are now smart cast to Long return thisId.compareTo(otherId) } 

这是一个简单的方法:

 override fun compareTo(other: T) :Int { return id?.compareTo(other.id ?: return 1) ?: -1 } 

然而这段代码对新手kotlin程序员来说是非常不友好的。 它涉及太多的魔法,使它看起来像scala。 这三个问号让人感到困惑,至少他们在思考一两分钟之前,才能意识到这个简单的一行内容正在发生什么。 我仍然喜欢你的版本。 这更详细,但清楚。

我真的很担心对称性问题。 这很重要,而不仅仅是一个设计问题。 如果你不比较可为空的属性,就不会有这个编程难题。 它将只是override fun compareTo(other: T) = id.compareTo(other.id) 。 简单,清晰,没有误导。

我宁愿扔掉所有的空检查代码,只是住这些空断言。 因为大多数情况下,只有在完全初始化之前,您才会比较这些东西。 如果这些断言失败,就意味着发生了一件非常糟糕的事情。

哦,顺便说一下,我不知道你的项目,如果遇到罕见的情况,你必须比较可空属性,我想你可以写一个特殊版本的Comparator ,认为是空值,而不是抛出NPE。 不要乱用自然秩序。