Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 mapToInt and toIntFunction examples

I am testing the new major update from Java (Java 8) and it is very interesting. I am using streams; in particular I am using this simple code.

private void getAvg()
{
    final ArrayList<MyPerson>persons = new ArrayList<>
    (Arrays.asList(new MyPerson("Ringo","Starr"),new MyPerson("John","Lennon"),new MyPerson("Paul","Mccartney"),new MyPerson("George","Harrison")));                
    final OptionalDouble average = persons.stream().filter(p->p.age>=40).mapToInt(p->p.age).average();
    average.ifPresent(System.out::println);        
    return;
}            
private class MyPerson
{
    private final Random random = new Random();
    private final String name,lastName;
    private int age;
    public MyPerson(String name,String lastName){this.name = name;this.lastName = lastName;this.age=random.nextInt(100);}    
    public MyPerson(String name,String lastName,final int age){this(name,lastName);this.age=age;}    
    public String getName(){return name;}
    public String getLastName(){return lastName;}                   
    public int getAge(){return age;}        
}            

In this example I understand very clear but later I have seen also can accomplish it in this way:

final OptionalDouble average = persons.stream().filter(p->p.age>=40)
.mapToInt(MyPerson::getAge).average();
average.ifPresent(System.out::println);        

I have checked the method toIntFunction and in fact have the following signature:

@FunctionalInterface
public interface ToIntFunction<T> {

/**
 * Applies this function to the given argument.
 *
 * @param value the function argument
 * @return the function result
 */
int applyAsInt(T value);
}

As I can see the applyAsInt have a input and returns an int as long as I understand.

This code:

MyPerson::getAge

calls:

public int getAge(){return age;}//please correct me at this point        

My question is: the method getAge have not parameters and returns a int but the toIntFunction receive a parameter - this is the part I don't understand.

The parameter from toIntFunction is inferred or something.

like image 611
chiperortiz Avatar asked Mar 16 '14 23:03

chiperortiz


2 Answers

Remember a method reference is just a shortcut for a lambda. So an instance method reference is a lambda that calls that method on the argument. The type of the argument is the class given in the method reference. It helps to "unwrap" it.

MyPerson::getAge

Unwrap to a lambda:

(MyPerson p) -> p.getAge()

Unwrap to an anonymous class:

new ToIntFunction<MyPerson>() {
    @Override
    public int applyAsInt(MyPerson p) {
        return p.getAge();
    }
}

With a static method reference, the signature must match exactly, that is, the static method takes a T and returns an int. With an instance method reference, the parameter T of the lambda is the object the method gets called on.

like image 181
Radiodef Avatar answered Sep 20 '22 07:09

Radiodef


As far as I know MyPerson::getAge is like a pointer to MyPersons getAge() method, which returns an int. So value.getAge() gets invoked in int applyAsInt(MyPerson value);. In other words: You just tell the stream, that it should use getAge()s return value from it's current MyPerson iteration variable to construct another collection an IntStream.

like image 27
Zhedar Avatar answered Sep 20 '22 07:09

Zhedar