The syntax of map method in java 8 is :

<R> Stream<R> map(Function<? super T,? extends R> mapper)

but i can use a lambda expression :

personList.stream().filter(p -> p.getPersonType().equals("student")).map(p -> new Student(p.getId(), p.getName())).collect(Collectors.toList());

How does the argument in map method equates to a Function datatype.Please help me understand this .

Thanks

5

Best Answer


The function Function<? super T,? extends R> mapper of the map method basically represents any function taking one parameter and returning a value so in this specific case the lambda p -> new Student(p.getId(), p.getName()) is a function taking a Person p and returning a Student hence fits into that perfectly.

To look at it another way, the lambda is equivalent to:

.map(new Function<Person, Student>() {@Overridepublic Student apply(Person p) {return new Student(p.getId(), p.getName());}})

You can write like this Function<Person,Student> function = p -> new Student(p.getId(), p.getName())

so as you see it is represent a function.

personList.stream().filter(p -> p.getPersonType().equals("student")).map(function::apply) // p -> function.apply(p).collect(Collectors.toList());

In the context of your Stream<Person> (assuming personList is a List<Person>), the lambda expression p -> new Student(p.getId(), p.getName()) implements a functional interface that accepts a Person instance (an element of your Stream) and returns a Student instance.

Hence it matches the Function<Person,Student> functional interface, which is the interface required by the map() method.

At runtime, the following lambda expression:

p -> new Student(p.getId(), p.getName())

will be represented by the class that implements Function<T, R> interface.

An instance of this functional interface can be passed as a parameter to Stream.map(...) method:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

In order to get a better understanding of how this works, one could replace a lambda with a good old anonymous class that implements the corresponding interface.

.map(p -> new Student(p.getId(), p.getName())) is equivalent to:

.map(new Function<Person, Student>() {@Overridepublic Student apply(Person p) {return new Student(p.getId(), p.getName());}})

Same as @Ousmane D. but instead of this:

.map(new Function<Person, Student>() {@Overridepublic Student apply(Person p) {return new Student(p.getId(), p.getName());}})

Try this:

Function<Person, Student> f = p -> new Student(p.getId(), p.getName());

and use it inside your stream with .map(f).