Comparator.compareBoolean() 和 Comparator.compare() 一样吗?
Comparator.compareBoolean() the same as Comparator.compare()?
这个怎么写
Comparator <Item> sort = (i1, i2) -> Boolean.compare(i2.isOpen(), i1.isOpen());
像这样(代码不起作用):
Comparator<Item> sort = Comparator.comparing(Item::isOpen).reversed();
比较方法没有 Comparator.comparingBool() 之类的东西。 Comparator.comparing returns int 而不是 "Item".
为什么不能这样写?
Comparator<Item> sort = Comparator.comparing(Item::isOpen);
下面调用了Boolean.compareTo
,这又和Boolean.compare
一样
public static int compare(boolean x, boolean y) {
return (x == y) ? 0 : (x ? 1 : -1);
}
而这个:Comparator.comparing returns int and not "Item".
毫无意义,Comparator.comparing
必须return一个Comparator<T>
;在你的情况下它正确 returns a Comparator<Item>
.
使用键提取器参数进行比较:
Comparator<Item> comparator =
Comparator.comparing(Item::isOpen, Boolean::compare).reversed();
重载 comparingInt
、comparingLong
和 comparingDouble
仅出于性能原因而存在。它们在语义上与未专门化的 comparing
方法相同,因此使用 comparing
而不是 comparingXXX
具有相同的结果,但可能有装箱开销,但实际影响取决于特定的执行环境。
在 boolean
值的情况下,我们可以预测开销可以忽略不计,因为方法 Boolean.valueOf
将始终 return Boolean.TRUE
或 Boolean.FALSE
并且从不创建新实例,因此即使特定的 JVM 无法内联整个代码,它也不依赖于优化器中是否存在 Escape Analysis。
如您所知,反转比较器是通过在内部交换参数来实现的,就像您在 lambda 表达式中手动执行的那样。
请注意,仍然可以创建一个融合反转和未装箱比较的比较器,而无需重复 isOpen()
表达式:
Comparator<Item> sort = Comparator.comparingInt(i -> i.isOpen()? 0: 1);
但是,如前所述,它不太可能比 Comparator.comparing(Item::isOpen).reversed()
方法具有更高的性能。
但请注意,如果您有 boolean
排序标准并关心最高性能,您可以考虑用桶排序变体替换通用排序算法。例如
如果你有流,替换
List<Item> result = /* stream of Item */
.sorted(Comparator.comparing(Item::isOpen).reversed())
.collect(Collectors.toList());
和
Map<Boolean,List<Item>> map = /* stream of Item */
.collect(Collectors.partitioningBy(Item::isOpen,
Collectors.toCollection(ArrayList::new)));
List<Item> result = map.get(true);
result.addAll(map.get(false));
或者,如果您有 List
,请替换
list.sort(Comparator.comparing(Item::isOpen).reversed());
和
ArrayList<Item> temp = new ArrayList<>(list.size());
list.removeIf(item -> !item.isOpen() && temp.add(item));
list.addAll(temp);
等等
这个怎么写
Comparator <Item> sort = (i1, i2) -> Boolean.compare(i2.isOpen(), i1.isOpen());
像这样(代码不起作用):
Comparator<Item> sort = Comparator.comparing(Item::isOpen).reversed();
比较方法没有 Comparator.comparingBool() 之类的东西。 Comparator.comparing returns int 而不是 "Item".
为什么不能这样写?
Comparator<Item> sort = Comparator.comparing(Item::isOpen);
下面调用了Boolean.compareTo
,这又和Boolean.compare
public static int compare(boolean x, boolean y) {
return (x == y) ? 0 : (x ? 1 : -1);
}
而这个:Comparator.comparing returns int and not "Item".
毫无意义,Comparator.comparing
必须return一个Comparator<T>
;在你的情况下它正确 returns a Comparator<Item>
.
使用键提取器参数进行比较:
Comparator<Item> comparator =
Comparator.comparing(Item::isOpen, Boolean::compare).reversed();
重载 comparingInt
、comparingLong
和 comparingDouble
仅出于性能原因而存在。它们在语义上与未专门化的 comparing
方法相同,因此使用 comparing
而不是 comparingXXX
具有相同的结果,但可能有装箱开销,但实际影响取决于特定的执行环境。
在 boolean
值的情况下,我们可以预测开销可以忽略不计,因为方法 Boolean.valueOf
将始终 return Boolean.TRUE
或 Boolean.FALSE
并且从不创建新实例,因此即使特定的 JVM 无法内联整个代码,它也不依赖于优化器中是否存在 Escape Analysis。
如您所知,反转比较器是通过在内部交换参数来实现的,就像您在 lambda 表达式中手动执行的那样。
请注意,仍然可以创建一个融合反转和未装箱比较的比较器,而无需重复 isOpen()
表达式:
Comparator<Item> sort = Comparator.comparingInt(i -> i.isOpen()? 0: 1);
但是,如前所述,它不太可能比 Comparator.comparing(Item::isOpen).reversed()
方法具有更高的性能。
但请注意,如果您有 boolean
排序标准并关心最高性能,您可以考虑用桶排序变体替换通用排序算法。例如
如果你有流,替换
List<Item> result = /* stream of Item */
.sorted(Comparator.comparing(Item::isOpen).reversed())
.collect(Collectors.toList());
和
Map<Boolean,List<Item>> map = /* stream of Item */
.collect(Collectors.partitioningBy(Item::isOpen,
Collectors.toCollection(ArrayList::new)));
List<Item> result = map.get(true);
result.addAll(map.get(false));
或者,如果您有 List
,请替换
list.sort(Comparator.comparing(Item::isOpen).reversed());
和
ArrayList<Item> temp = new ArrayList<>(list.size());
list.removeIf(item -> !item.isOpen() && temp.add(item));
list.addAll(temp);
等等