我正在玩Java 8中的流和lambdas,因为我之前从未使用过它们并试图将每个20到19岁的人的年龄转换成打印出他们的名字,但我收到以下错误< / p>
Cannot invoke map(Person::getName) on the primitive type void
这是我的代码
System.out.println(
people.stream()
.filter(person -> person.getAge() == 20)
.forEach(person -> person.setAge(19))
.map(Person::getName));
如果有人可以告诉我为什么会这样,或者让我知道如何改进或修改此代码,我们将不胜感激。
答案 0 :(得分:7)
forEach
是一个终端操作,不会返回它正在处理的流。
通常,您应该避免使用forEach
来修改流,即使是最终操作也是如此。相反,您应该使用map
修改信息流的项目。
以下是如何执行此操作的示例,其中包括合法使用forEach
:
people.stream()
.filter(person -> person.getAge() == 20)
.map(person -> new Person(person.getName(), person.getAge() -1 /*, ...*/))
.forEach(System.out::println);
关于该代码的一些注释:
map(...)
仅转换流,而不转换数据源(people
Collection
)。如果您想稍后使用转换后的结果,则需要.collect()
将Stream
改为新的Collection
,并使用适当的Collector
(例如Collectors.toList()
)< / p>
如果您遵循该道路,您的新终端操作为collect()
,您不能再使用.forEach()
了。一种解决方案是使用新.forEach()
的{{1}}方法(不需要Collection
,stream
自{1}}以来实施,另一个将forEach()
用于Iterable
作为非终端等效于.peek()
关于map()
的使用,请注意非终端操作由终端操作驱动:如果此操作仅返回流的单个元素(如.forEach()
),非终端操作只会对此元素执行,否则你不应该期望。
答案 1 :(得分:3)
您可以在forEach中编写多个语句:
public class Person
{
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return name + "(" + age + ")";
}
}
public class LambdaPeople
{
public static void main(String[] args) {
Person andy = new Person("Andy", 19);
Person bob = new Person("Bob", 21);
Person caroline = new Person("Caroline", 20);
List<Person> people = new ArrayList<>();
people.add(caroline);
people.add(andy);
people.add(bob);
people.stream()
.filter(person -> person.getAge() == 20)
.forEach(person -> {
person.setAge(19);
System.out.println(person);
});
}
}
它返回:
Caroline(19)
接下来的两种方法是出于文档目的。窥视和地图是中间操作。没有forEach,他们根本就不会被执行。
如果你想使用map:
people.stream()
.filter(person -> person.getAge() == 20)
.map(person -> {
person.setAge(19);
return person;
})
.forEach(System.out::println);
如果你想使用peek:
people.stream()
.filter(person -> person.getAge() == 20)
.peek(person -> person.setAge(19))
.forEach(System.out::println);