Collectors.toMap() keyMapper——更简洁的表达方式?

Posted

技术标签:

【中文标题】Collectors.toMap() keyMapper——更简洁的表达方式?【英文标题】:Collectors.toMap() keyMapper -- more succinct expression? 【发布时间】:2013-10-15 19:11:56 【问题描述】:

我正在尝试为以下Collectors.toMap() 调用中的“keyMapper”函数参数提出一个更简洁的表达式:

List<Person> roster = ...;

Map<String, Person> map = 
    roster
        .stream()
        .collect(
            Collectors.toMap(
                new Function<Person, String>()  
                    public String apply(Person p)  return p.getLast();  
                ,
                Function.<Person>identity()));

似乎我应该能够使用 lambda 表达式内联它,但我想不出一个可以编译的。 (我对 lambdas 很陌生,所以这不足为奇。)

谢谢。

--> 更新:

如已接受的答案中所述

Person::getLast

是我一直在寻找的,也是我尝试过的。然而,Eclipse 4.3 的 BETA_8 nightly build 是个问题——它标记为错误。从命令行编译时(我应该在发布之前完成),它起作用了。因此,是时候向 eclipse.org 提交错误了。

谢谢。

【问题讨论】:

请注意,静态导入 Collectors.toMap 会使表达式更短,不过 NetBeans 似乎并没有为我导入这些。 刚刚偶然发现了这个问题。你的问题不仅是Eclipse 4.3,还有u112之前的JDK 8,也有类似的问题。 HTH。 【参考方案1】:

我们也可以使用可选的合并功能以防相同的键冲突。 例如,如果两个或多个人具有相同的 getLast() 值,我们可以指定如何合并这些值。如果我们不这样做,我们可能会得到 IllegalStateException。 这是实现此目的的示例...

Map<String, Person> map = 
roster
    .stream()
    .collect(
        Collectors.toMap(p -> p.getLast(),
                         p -> p,
                         (person1, person2) -> person1+";"+person2)
    );

【讨论】:

对不起,这是什么意思? (person1, person2) -&gt; person1+";"+person2) 如果映射的键包含重复项(根据 Object.equals(Object)),则将值映射函数应用于每个相等的元素,并使用提供的合并函数合并结果。请参考链接docs.oracle.com/javase/8/docs/api/java/util/stream/…【参考方案2】:

您可以使用 lambda:

Collectors.toMap(p -> p.getLast(), Function.identity())

或者,更简洁地说,您可以使用 method reference 和 ::

Collectors.toMap(Person::getLast, Function.identity())

您可以简单地使用等效的 lambda,而不是 Function.identity

Collectors.toMap(Person::getLast, p -> p)

如果您使用 Netbeans,只要匿名类可以被 lambda 替换,您就会得到提示。

【讨论】:

您可以通过删除括号来使表达式更短,因为单个参数不需要括号,即Collectors.toMap(Person::getLast, p -&gt; p) 我也很确定身份函数的类型参数不是必需的,因为它可以被推断出来。 Collectors.toMap(Person::getLast, Function.identity()) @GuiSim 我认为现在确实如此 - 这是 Java 8 早期版本中的一个错误。 呵呵,好像 p -> p 被优化了,没有新建编译匿名类。我猜它在内部使用 Function.identity(),而不是创建一个无用的类。 重要的警告!如果您的 List 包含空值,您将在此处遇到异常,因为 Collectors.toMap 是如何实现的,即使具有空值的映射通常是完全可以接受的。当然,在这种情况下,您在访问 Person::getLast 时无论如何都会得到 NPE,但在许多其他情况下,您的密钥可能组合方式不同,但您仍然会遇到异常。见***.com/questions/24630963/…【参考方案3】:
List<Person> roster = ...;

Map<String, Person> map = 
    roster
        .stream()
        .collect(
            Collectors.toMap(p -> p.getLast(), p -> p)
        );

这将是翻译,但我没有运行它或使用 API。您很可能可以将 p -> p 替换为 Function.identity()。并静态导入 toMap(...)

【讨论】:

有没有办法在 List 中合并相似的值以防出现重复而不是连接它们?

以上是关于Collectors.toMap() keyMapper——更简洁的表达方式?的主要内容,如果未能解决你的问题,请参考以下文章

List 转 Map 之 Collectors.toMap()

java8的stream中Collectors.toMap空指针问题

Collectors.toMap使用详解

Collectors.toMap空指针异常

Java中Collectors.toMap()的基本使用方法和使用场景

collectors.tomap和HeaderEelement的getValue和getNmae的问题。