Java 收集 lambda 表达式示例

Java collect with lambda expression example

我正在尝试转换这个

 String r = "";
 for ( Persona p : list ) {
    r += p.lastName;
 }

stream().filter.collect() 形式,但我想知道如何使用 lambda 表达式(不是方法引用)编写 collect。我找不到很好的例子。

这就是我的

class B {
    public static void main( String ... args ) {
        List<Person> p = Arrays.asList(
                new Person("John", "Wilson"),
                new Person("Scott", "Anderson"),
                new Person("Bruce", "Kent"));

        String r;
        String s = p.stream()
            .filter( p -> p.lastName.equals("kent"))
            .collect((r, p) -> r += p.lastName);/// ?????
    }
}
class Person {
    String name;
    String lastName;
    public Person( String name, String lastName ) {
        this.name = name;
        this.lastName = lastName;
    }
}

我找到的所有示例都使用方法引用,而我 认为 应该有一种简单的方法来代替编写 lambda 表达式。

假设您不想使用任何现成的收集器,例如 Collectors.joining(),您确实可以创建自己的收集器。

但是,正如 javadoc 所指出的,collect() 需要 3 个功能接口实例作为参数,或者一个 Collector。所以你不能只将单个 lambda 表达式传递给 collect()。

假设你想使用第一个版本,使用 3 个 lambda 表达式,你会注意到,通过阅读 javadoc,结果必须是一个可变对象,而 String 不是可变的。所以你应该改用 StringBuilder。例如:

StringBuilder s = 
    p.stream()
     .filter( p -> p.lastName.equals("kent"))
     .map(p -> p.lastName)
     .collect(StringBuilder::new,
              StringBuilder::append,
              StringBuilder::append);

这里使用了方法引用,但是所有的方法引用都可以写成lambda表达式。以上相当于

StringBuilder s = 
    p.stream()
     .filter( p -> p.lastName.equals("kent"))
     .map(p -> p.lastName)
     .collect(() -> new StringBuilder(),
              (stringBuilder, string) -> stringBuilder.append(string),
              (stringBuilder1, stringBuilder2) -> stringBuilder1.append(stringBuilder2));

你也可以使用.reduce()函数,它比收集更容易阅读。

    String s = p.stream()
        .filter( p -> p.lastName.equals("kent"))
        .reduce("", (acc, p) -> acc + p.lastName(), String::concat);

版本StringBuilder

    StringBuilder s = p.stream()
        .filter( p -> p.lastName.equals("kent"))
        .reduce(new StringBuilder(), (acc, p) -> acc.append(p.lastName()), StringBuilder::append);

也许您设想的是 reduce 操作而不是收集,这将允许您像您设想的那样使用 lambda 表达式。例如,

String s = persons.stream()
        .map( (s1, str) -> s1.concat(str) )
        .reduce("", String::concat);

当然,这是一个练习。字符串连接效率低下,因此最好使用 collect(Collectors.joining()),它使用 StringBuffer 作为其累加器。

您可以使用此解决方案省略映射:

Collector<Person, StringBuilder, String> collector = Collector.of(  
    StringBuilder::new,
    (buf, person) -> buf.append( person.lastName ),
    (buf1, buf2) -> {
      buf1.append( buf2 );
      return( buf1 );
    },
    buf -> buf.toString() 
  );

list.stream()
  .filter( p -> p.lastName.equals( "Kent" ) )
  .collect( collector );