Java 8流获取无法在原始类型void上调用map

时间:2016-10-27 09:06:53

标签: java lambda java-8 java-stream

我正在玩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)); 

如果有人可以告诉我为什么会这样,或者让我知道如何改进或修改此代码,我们将不胜感激。

2 个答案:

答案 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}}方法(不需要Collectionstream自{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);