5

Java 8 added lambda expressions. Using lambdas in a similar fashion to anonymous classes is pretty straight forward, but I'm wondering if the related functionality of using named functions as arguments to other functions exists. For example, is there a Java way to write the following Python code:

list1 = (1,2,3)
list2 = (4,5,6)

def add(a, b):
  return a+b

for e in map(add, list1, list2):
  print(e)

output

5
7
9
3
  • You mean YourClass::add? Commented Apr 30, 2015 at 21:29
  • I searched for information on Closures in Java 8, since closures involve functions as parameters. These might be helpful: Currying vs Closures and Closures Info Commented Apr 30, 2015 at 21:36
  • You can use flatMap/map to implement map on two lists like in this Scala example: github.com/robertberry/… (and as others noted Integer::sum can add them.) Commented May 1, 2015 at 11:22

4 Answers 4

4

Yes, you can use method references like Integer::sum where lambdas are allowed.

int six = IntStream.of(1, 2, 3)
    .reduce(0, Integer::sum);

This is equivalent to

int six = IntStream.of(1, 2, 3)
    .reduce(0, (a, b) -> Integer.sum(a, b));

Methods like Integer.sum and Double.max were added in Java 8 precisely so they could be used in lambdas like this.

There's no built-in way to "zip" together multiple lists the way Python does, though.

Sign up to request clarification or add additional context in comments.

7 Comments

follow-up: how do I define a function that takes a method as an agurment, i.e. like def func(a,b): return a(b)
Use a functional interface: an interface with one method, essentially. The ones from java.util.function cover most use cases.
Yep, like that. You could also simplify the last line: map(Arrays.asList(1,2,3), Arrays.asList(4,5,6), (a, b) -> a + b).
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
@John Kugelman: unless you really like repeating yourself three times, BinaryOperator<Integer> add=(a,b)->a+b; or IntBinaryOperator add=(a,b)->a+b; is the way to go… Note that BinaryOperator<T> is a sub-type of BiFunction<T,T,T>.
|
2

Well, there are no "functions" in Java, only methods, so you would not get the same exact thing.

The best way to achieve this is to use method references, and in this case a BiConsumer could be used:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.BiConsumer;

public class StackOverflow {

    public static void main(String[] args) throws InterruptedException {
        List<Integer> list1 = new ArrayList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);

        List<Integer> list2 = new ArrayList<>();
        list2.add(4);
        list2.add(5);
        list2.add(6);

        mapOver(StackOverflow::add, list1, list2);
    }

    public static void add(Integer a, Integer b) {
        System.out.println(a + b);
    }

    public static <T> void mapOver(BiConsumer<T, T> function,
                               Iterable<T> first,
                               Iterable<T> second) {
        final Iterator<T> firstIterator = first.iterator();
        final Iterator<T> secondIterator = second.iterator();
        while (firstIterator.hasNext() && secondIterator.hasNext()) {
            function.accept(firstIterator.next(), secondIterator.next());
        }
    }
}

Output:

5
7
9

Comments

0

Not sure what your question really is, but in Java, this would be something like..

List<Integer list1 = Arrays.asList(1,2,3);
List<Integer list2 = Arrays.asList(4,5,6);

IntStream.range(0, list1.size())
    .parallel()
    .forEach(i -> {
        System.out.println(list1.get(i) + list2.get(i));
    });

.. since you can't stream multiple collections in Java as you can in python.

Comments

0

It's certainly possible to declare variables whose types are functional interfaces and then assign lambdas to them. That's the conclusion of this answer and its comment thread. For example, one might have a declaration like this:

BiFunction<Integer,Integer,Integer> add = (a, b) -> a + b;

This isn't exactly what the OP asked for. The Python equivalent of this would be something like:

add = lambda a, b: a + b

This isn't a named function; it's a variable whose value is a (lambda) function. The original question was asking about using named function in Java. The way to do this is with a method reference.

Suppose you have method that takes a BiFunction<Integer,Integer,Integer> parameter. You could pass it the add variable as defined above. But you could also declare an ordinary method, and use it as the target of a method reference. The trick is to make sure that the "shape" (number and type of arguments, type of return value) matches whatever functional interface you're trying to use. In this case you have two parameters of type Integer and the return value is Integer, so your method would be

static Integer add(Integer a, Integer b) {
    return a + b;
}

Then you can refer to this using a method reference of the form MyClass::add.

Note that I've made this a static method. If it were an instance method, the receiver (this) is a hidden parameter that you have to take into account when matching it to a functional interface.

Note also that because of auto-boxing, one could also write:

static int add(int a, int b) {
    return a + b;
}

There's certainly a use for assigning lambdas to variables, such as if the choice of an algorithm is made at runtime. But if the lambdas are all being assigned to constant fields, it's often easier to use method references that target ordinary methods.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.