Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 stream getting cannot invoke map on primitive type void

I am playing around with streams and lambdas in Java 8, as I have never used them before and was trying to convert the ages of everyone who is 20 to 19 and the printing out their names, but I get the following error

Cannot invoke map(Person::getName) on the primitive type void

Here is my code

            System.out.println(
                people.stream()
                .filter(person -> person.getAge() == 20)
                .forEach(person -> person.setAge(19))
                .map(Person::getName)); 

If someone could tell me why this is happening or let me know how to improve or amend this code, it would be greatly appreciated.

like image 344
user6248190 Avatar asked Dec 15 '22 02:12

user6248190


2 Answers

forEach is a terminal operation and will not return the stream it works on.

In general, you should avoid using forEach to modify the stream, even as a final operation. Instead, you should use map to modify the items of your stream.

Here is an example of how to do it, which includes a legitimate use of forEach :

people.stream()
      .filter(person -> person.getAge() == 20)
      .map(person -> new Person(person.getName(), person.getAge() -1 /*, ...*/))
      .forEach(System.out::println);

A few notes on that code :

  • map(...) only transforms the stream, not the datasource (the people Collection). If you want to use the transformed result later, you will want to .collect() the Stream into a new Collection with an appropriate Collector (e.g. Collectors.toList())

  • if you follow that road, your new terminal operation is collect(), and you can't use .forEach() anymore. One solution would be to use the .forEach() method of the new Collection (no need for a stream, forEach() is implemented on Iterable since 1.8), another would be to use .peek() on the stream where you map() as a non-terminal equivalent to .forEach()

  • About the use of peek(), note that the non-terminal operations are driven by the terminal operation : if this one only returns a single element of the stream (like .findFirst()), non-terminal operations will only be executed for this element, and you shouldn't expect otherwise.

like image 163
Aaron Avatar answered Dec 27 '22 01:12

Aaron


You can write multiple statements inside of 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);
                });
    }
}

It returns :

Caroline(19)

The two next methods are for documentation purpose. peek and map are intermediate operations. Without forEach at the end, they wouldn't be executed at all.

If you want to use map :

    people.stream()
            .filter(person -> person.getAge() == 20)
            .map(person -> {
                person.setAge(19);
                return person;
            })
            .forEach(System.out::println);

If you want to use peek :

    people.stream()
            .filter(person -> person.getAge() == 20)
            .peek(person -> person.setAge(19))
            .forEach(System.out::println);
like image 20
Eric Duminil Avatar answered Dec 27 '22 02:12

Eric Duminil