我是Kotlin的新手,如何使用Collections
比较对象
Collections.sort(list,myCustomComparator)
我们如何在Kotlin中编写MyCustomComparator
方法?
private final Comparator<CustomObject> myCustomComparator = (a, b) -> {
if (a == null && b == null) {
return 0;
} else if (a == null) {
return -1;
} else if (b == null) {
return 1;
}
};
答案 0 :(得分:1)
这几乎可以与Java中的方法相同:
private val myCustomComparator = Comparator<CustomObject> { a, b ->
when {
(a == null && b == null) -> 0
(a == null) -> -1
else -> 1
}
}
if else if else ...
被单个Kotlin when
取代,以使代码更易读。
在Kotlin中,使用Comparator
对列表进行排序也可以这样写:
val customObjects = listOf(CustomObject(), CustomObject())
customObjects.sortedWith(myCustomComparator)
答案 1 :(得分:0)
您可以将SAM conversion与lambda一起使用(因为Comparator
是Java接口,而Kotlin允许您这样做)或匿名类对象。
使用lambda时,它将如下所示:
val customComparator = Comparator<CustomObject> { a, b ->
if (a == null && b == null) {
return 0;
} else if (a == null) {
return -1;
} else if (b == null) {
return 1;
}
}
和匿名类版本:
val customComparator = object: Comparator<CustomObject> {
override fun compare(a: CustomObject, b: CustomObject): Int {
if (a == null && b == null) {
return 0;
} else if (a == null) {
return -1;
} else if (b == null) {
return 1;
}
}
}
答案 2 :(得分:0)
在Kotlin中有更好的方法来对集合进行排序-您可以像这样使用扩展功能sortedWith
:
list.sortedWith(Comparator { s1, s2 ->
when {
s1 == null && s2 == null -> 0
s1 == null -> -1
else -> 1
}
})
但是请记住,这将返回列表的副本。
答案 3 :(得分:0)
根据其他答案,相当直接的翻译使您可以使用以下方式对列表进行排序:
fun myCustomComparator() = Comparator<CustomObject>{ a, b ->
when {
(a == null && b == null) -> 0
(a == null) -> -1
else -> 1
}
}
现在,这里没有任何内容取决于您的CustomObject
。因此,使其具有通用性很简单,因此它可以处理任何类型:
fun <T> nullsFirstComparator() = Comparator<T>{ a, b ->
when {
(a == null && b == null) -> 0
(a == null) -> -1
else -> 1
}
}
但是,这里存在一些潜在的问题。
主要问题是不一致。 Java docs中详细说明了Comparator
的一般合同:
实施者必须确保所有x和y的
sgn(compare(x, y)) == -sgn(compare(y, x))
(不幸的是,Kotlin docs没有提到任何这些。真是可惜他们没有达到Java的标准。)
但是,上面的比较器没有这样做;如果a和b不为空,则compare(a, b)
和compare(b, a)
均为1!
这可能会导致问题;例如,根据sort()方法的编码方式,它可能会使列表未排序,或者永远无法完成。或者,如果将其用于排序的地图,则该地图可能无法返回其某些值,或者永远无法完成。
这可以通过添加第四种情况来解决:
fun <T> nullsFirstComparator() = Comparator<T>{ a, b ->
when {
(a == null && b == null) -> 0
(a == null) -> -1
(b == null) -> -1
else -> 0
}
}
现在比较器是一致的;空值总是先于非空值。
但是它仍然具有不受欢迎的功能:所有非空值现在都被视为等效值,并且无法在其内部进行排序。由于Kotlin不知道如何比较两个任意对象的顺序,因此通常无法解决此问题。但是,您可以通过两种方式告诉它如何操作。
一种方法是将其限制为具有自然顺序的对象,即实现Comparable
接口的对象。 (再一次,Java docs对此进行了更好的解释。)
fun <T : Comparable<T>> nullsFirstComparator() = Comparator<T>{ a, b ->
when {
(a == null && b == null) -> 0
(a == null) -> -1
(b == null) -> 1
else -> a.compareTo(b)
}
}
但是,您可以使用标准库kotlin.comparisons.compareValues()
函数来简化此操作:
fun <T : Comparable<T>> nullsFirstComparator()
= Comparator<T>{ a, b -> compareValues(a, b) }
另一种方法是自己提供订单-您可以通过提供另一个 Comparator
来处理非空比较:
fun <T> nullsFirstComparator(comparator: Comparator<T>) = Comparator<T>{ a, b ->
when {
(a == null && b == null) -> 0
(a == null) -> -1
(b == null) -> 1
else -> c.compare(a, b)
}
}
但是您不需要自己编写,因为它已经在Kotlin标准库中,为kotlin.comparisons.nullsFirst()
!
答案 4 :(得分:0)
考虑@Alexander答案后,代码可以写为
private val MyCustomComparator = Comparator<MyObject> { a, b ->
when {
a == null && b == null -> return@Comparator 0
a == null -> return@Comparator -1
b == null -> return@Comparator 1
else -> return@Comparator 0
}
}