Java Stream.max(整数::max):意外结果

Java Stream.max(整数::max):意外结果,java,java-8,compare,max,java-stream,Java,Java 8,Compare,Max,Java Stream,我正在学习使用Enthuware的模拟测试 遇到这个问题 我尝试使用peek对其进行调试,但这无助于我理解 我尝试使用Integer::max和Integer::compare对ls进行排序 ls.sort(Integer::max); // [3, 4, 6, 9, 2, 5, 7] ls.sort(Integer::compare); // [2, 3, 4, 5, 6, 7, 9] 当然,我得到的事实是,Integer::max不是一个比较器,因此它有一个相同的签名。 对我来说

我正在学习使用Enthuware的模拟测试

遇到这个问题


我尝试使用
peek
对其进行调试,但这无助于我理解

我尝试使用
Integer::max
Integer::compare
ls
进行排序

ls.sort(Integer::max);     // [3, 4, 6, 9, 2, 5, 7]
ls.sort(Integer::compare); // [2, 3, 4, 5, 6, 7, 9]
当然,我得到的事实是,
Integer::max
不是一个比较器,因此它有一个相同的签名。 对我来说,在第一种情况下,
max
应该是
7
,因为它是最后一个元素,就像我用
Integer::compare排序时一样

ls.sort(Integer::max);     // [3, 4, 6, 9, 2, 5, 7]
ls.sort(Integer::compare); // [2, 3, 4, 5, 6, 7, 9]

有人能把它分解成一些简单的东西吗?

比较器方法的契约(在参数
第一个
第二个
)是:

  • 如果
    first
    等于
    second
  • 如果
    first
  • 如果
    first>second
只有正值的
max
方法将始终返回正值。根据比较器契约解释返回值时,正值表示
first>second
。因此,项目的顺序不会改变,它们看起来是“有序的”。max(a,b)
将返回给定
a
b
的较大值。如果以某种方式将该结果用作比较器,则返回的正值将被视为意味着
a>b
因此
a
将被保留


前两个元素是3和4。两者都是积极的<代码>整数。最大值(3,4)=4>0
。所以你实际上是说,有了这样一个比较器,
3>4
,就保留了3。然后,剩下的也一样:
Integer.max(3,6)=6>0,所以3被认为是最大值,等等。

这令人难以置信地困惑

我们正在尝试使用
Integer::max
作为比较器。因为问题中的所有数字都是正数,所以答案总是被解释为
compare(a,b)
的第一个参数比第二个参数“大”

Collections.sort
的一个怪癖是,当您有一个列表
[a,b]
时,该方法的编程方式是调用
比较(b,a)
,而不是
比较(a,b)
(这似乎更合理)。因此,如果
compare
返回一个正数,它看起来像
b>a
,因此列表不需要排序

这就是为什么
list.sort
什么都不做的原因

然而,恰好
Stream.max
是以另一种方式编程的,即第一个比较是
compare(3,4)
,因此看起来
3
是最大值。

您需要替换

.max(Integer::max)


这里的问题是,抽象方法
compare
被声明为返回一个
int
值,并且
Integer.max
的签名以及
Integer
类中的方法
Integer.compare
,因此,表示法
Integer::max
被推断为有效的
比较器
。尽管预计将实现比较方法,例如:

返回负整数、零或正整数作为第一个 参数小于、等于或大于第二个参数


在您当前的场景中,代码总是返回一个正值(给定输入),因此比较中的第一个元素总是被认为更大,因此相应地返回。

虽然这并不能回答问题,但您的问题的可能解决方案是:

try{
    int i = map.values().stream().mapToInt(e -> e).max().getAsInt();
}catch(NoSuchElementException e)
    e.printStackTrace();
}
mapToInt(e->e)
方法使用lambda表达式将流中的每个元素转换为整数值,并返回一个
IntStream
,其中可以调用
max()
方法。 请注意,
max()
返回一个
OptionalInteger
,因此需要
getAsInt()
orElse(0)
方法调用


您可以查看文档以获得更深入的答案:,

非常感谢,这正是我需要的!因此,它在内存中保留上一个的最大值,并继续下一个,直到结束。实际上,这个案例的结果是未知的。您正在向
.max
输入损坏的比较器,因此可以得到任何结果。没有具体说明
.max
将如何比较输入。@TagirValeev不可能预测输出吗?@YassinHajaj,可以研究具体的实现。但是您不能保证下一次java更新(即使是很小的更新)不会改变实现,这与问题完全无关。比较是一种定性操作,而不是定量操作。如果我将234与2进行比较,比较结果可能是232、199392或98;没关系。调用参数的顺序也不重要。@fge这很重要,因为
max
不符合
compare
的约定。想象一下你试图对[a,b]进行排序。如果你比较(a,b)并得到肯定的答案,这意味着a>b,所以你需要交换。如果你比较(b,a)并得到肯定的答案,这意味着b>a,所以你不需要交换。“我可以向你保证我是正确的。”保尔·伯丁顿谢谢你的回答!这确实令人困惑。我只是对结果感到好奇:)。我不知道
stream.max在使用
比较器时是如何工作的。这有点不一样有什么不同吗?只要比较者遵守合同…@fge这个人不遵守合同。这就是为什么它令人困惑。检查Tunaki的答案。但你自己也说过:
Integer::max
不是比较器。那么问题是什么呢?注意,运行时机制只检查签名是否匹配;它不会检查“行为的正确性”(它真的不能)。@fge首先,存在n
.max(Integer::compare)
try{
    int i = map.values().stream().mapToInt(e -> e).max().getAsInt();
}catch(NoSuchElementException e)
    e.printStackTrace();
}