【问题标题】:Finding Max with Lambda Expression in Java在 Java 中使用 Lambda 表达式查找 Max
【发布时间】:2014-06-24 05:01:18
【问题描述】:

这是我的代码

    List<Integer> ints = Stream.of(1,2,4,3,5).collect(Collectors.toList());
    Integer maxInt = ints.stream()
                              .max(Comparator.comparing(i -> i))
                              .get();

    System.out.println("Maximum number in the set is " + maxInt);

输出:

Maximum number in the set is 5

我无法区分代码下方的两个 i

Comparator.comparing(i -> i)

谁能好心解释一下两个i之间的区别?

【问题讨论】:

    标签: java lambda max java-8


    【解决方案1】:

    Comparator.comparing(…) 方法旨在创建一个Comparator,它使用基于要比较的对象属性的顺序。当使用 lambda 表达式 i -&gt; i(这里是 (int i) -&gt; { return i; } 的简写)作为属性提供程序函数时,生成的 Comparator 将比较值本身。当要比较的对象具有像Integer 一样的自然顺序时,此方法有效。

    所以

    Stream.of(1,2,4,3,5).max(Comparator.comparing(i -> i))
    .ifPresent(maxInt->System.out.println("Maximum number in the set is " + maxInt));
    

    做同样的事情

    Stream.of(1,2,4,3,5).max(Comparator.naturalOrder())
    .ifPresent(maxInt->System.out.println("Maximum number in the set is " + maxInt));
    

    虽然后者效率更高,因为它对所有具有自然顺序的类型都实现为单例(并实现Comparable)。

    max 完全需要Comparator 的原因是因为您使用的泛型类Stream 可能包含任意对象。

    这允许,例如像streamOfPoints.max(Comparator.comparing(p-&gt;p.x)) 一样使用它来找到x 值最大的点,而Point 本身没有自然顺序。或者做类似streamOfPersons.sorted(Comparator.comparing(Person::getAge))的事情。

    当使用专门的IntStream 时,您可以直接使用自然顺序,这样可能更有效:

    IntStream.of(1,2,4,3,5).max()
    .ifPresent(maxInt->System.out.println("Maximum number in the set is " + maxInt));
    

    为了说明“自然顺序”和基于属性的顺序之间的区别:

    Stream.of("a","bb","aaa","z","b").max(Comparator.naturalOrder())
    .ifPresent(max->System.out.println("Maximum string in the set is " + max));
    

    这将打印出来

    集合中的最大字符串是z

    因为Strings 的自然顺序是z 大于b 大于a 的字典顺序

    另一方面

    Stream.of("a","bb","aaa","z","b").max(Comparator.comparing(s->s.length()))
    .ifPresent(max->System.out.println("Maximum string in the set is " + max));
    

    将打印

    集合中的最大字符串是aaa

    因为aaa 具有流中所有Strings 的最大长度。这是 Comparator.comparing 的预期用例,在使用方法引用时可以使其更具可读性,即 Comparator.comparing(String::length) 几乎不言自明……

    【讨论】:

    • 什么是自然秩序?你能用一个样本把它分解吗?你是什么意思它把价值与自己进行比较?你能用样本分解一下吗?
    • 所以在这种情况下 i -> i 有点多余?
    • 是的,如前所述,它与Comparator.naturalOrder() 的作用相同。所以对于IntStream,您甚至可以省略Comparator 并实现相同的效果。
    • 我把我的答案作为一个问题发布了,你能看看它并与我分享你的想法吗? stackoverflow.com/questions/24399181/…
    【解决方案2】:

    此函数(注意-&gt; 用于闭包,不要与用于比较的=&gt; 混淆)

    i -> i
    

    只是意味着您需要按原样比较整个对象。即如果我有一个i,你需要比较i

    一个不那么琐碎的例子可能是

    max(Comparator.comparing(i -> -i))
    

    这将为您提供最小值或

    max(Comparator.comparing(i -> Math.abs(100-i))
    

    给你一个离 100 最远的值。

    max(Comparator.comparing(i -> i.toString()))
    

    这将为您提供作为字符串的最大比较,即“9”>“10”作为字符串。

    【讨论】:

    • =&gt; 是比较,-&gt; 是闭包。
    • @KickButtowski 你的意思是我链接到几个 cmets 的关于 Lambdas 的 Oracle 教程吗? ;) 说这些话“-&gt; 不是比较”。我已经说过两次了。
    • 请记住i -&gt; i(int i) -&gt; { return i; } 的短文。通过查看较长的表格,应该清楚会发生什么……
    • @Kick Buttowski:i 没有任何反应。指定的函数仅用于确定Comparator排序属性。如果指定的函数只返回值本身,则意味着使用了值的自然顺序。这已经过时了,因为Comparator.naturalOrder() 也会这样做。但是,如果您返回 -i,它会颠倒顺序。如果您使用i -&gt; Integer.bitCount(i),它会按位数对int 数字进行排序。
    【解决方案3】:

    Comparator.comparing 需要一个函数,它将源对象映射到实际比较的值 - 在您的情况下,由于您不想预处理要比较的值,i 只是映射到自身.

    【讨论】:

    • 你能否解释更多或提供一个来源以便我阅读它?
    • 我回答的哪一部分你不明白?
    • Comparator.comparing 需要一个函数,它将源对象映射到实际比较的值 -
    • 能不能加个图显示两个i的关系->i
    • 这两个 i 是相同的 - Comparator.comparing 期望对每个输入元素应用一个函数,正如函数 i -&gt; i 描述的那样,您接受每个输入并将自身作为输出返回,要比较的值转换。
    猜你喜欢
    • 2013-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多