Java 8 mapToInt and toIntFunction examples

11.9k views Asked by At

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.

2

There are 2 answers

0
Radiodef On BEST ANSWER

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.

4
Zhedar On

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.