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 );
我正在尝试转换这个
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 );