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


77

我正在尝试在以下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表达式内联它,但是我无法提出一个可以编译的表达式。(我对lambda很陌生,所以这并不奇怪。)

谢谢。

->更新:

如已接受的答案中所述

Person::getLast

是我一直在寻找的东西,也是我尝试过的东西。但是,问题是夜间出现的Eclipse 4.3的BETA_8夜间构建-标记为错误。从命令行编译时(我应该在发布之前完成该工作)。因此,该到eclipse.org提交错误了。

谢谢。


1
还请注意,对Collectors.toMap进行静态导入将使表达式更短,但是NetBeans似乎并未为我导入这些内容。
Brett Ryan

刚刚偶然发现了这个问题。您的问题不仅是Eclipse 4.3,还是u112之前的JDK 8,它都有类似的问题。HTH。

Answers:


189

您可以使用lambda:

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

或者,更简洁,您可以使用方法参考使用::

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

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

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

如果您使用Netbeans,则每当匿名类可以被lambda替换时,您都将获得提示。


2
您可以通过删除括号来使表达式更短,因为单个参数不需要括号Collectors.toMap(Person::getLast, p -> p)
Brett Ryan

1
我也很确定,不需要identity函数的type参数,因为可以推断出来。Collectors.toMap(Person::getLast, Function.identity())
GuiSim 2014年

@GuiSim我觉得现在的情况的确-这是在早期版本的Java 8中的错误
assylias

2
呵呵,看来p-> p以某种方式进行了优化,没有建立新的编译匿名类。我猜它内部使用Function.identity(),而不是创建一个无用的类。
Vlasec

1
重要警告!如果您的列表包含空值,则即使在正常情况下可以接受具有空值的映射,也会由于Collectors.toMap的实现方式而在此处出现异常。当然,在这种情况下,访问Person :: getLast时仍然会得到NPE,但是在许多其他情况下,键的组成可能有所不同,但仍然会得到异常。参见stackoverflow.com/questions/24630963/…–
塞巴斯蒂安·范登·布鲁克

29
List<Person> roster = ...;

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

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


如果有重复项,是否有办法在List <Person>中合并相似的值,而不是将它们串联在一起?
Lovegiver

5

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

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

1
对不起,这是什么意思?(person1, person2) -> person1+";"+person2)
Thach Huynh

1
如果映射的键包含重复项(根据Object.equals(Object)),则将值映射函数应用于每个equal元素,然后使用提供的合并函数合并结果。请参考链接docs.oracle.com/javase/8/docs/api/java/util/stream/…–
KayV
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.