Dynamic predicates and functions and cost of functional approach

Viewed 111

I'm starting to get acquainted with Java and there are some features which I really like, e.g. using Predicate with .filter() and Function with .map(). This is a really nice functional approach. I have three questions about this code:

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

public class ProcessList {

    public static void main(String[] args) {

        List<Integer> numbers = Arrays.asList(1, 4, 3, 2, 14, 1, -1, 0, 1, 5, 9, 0, 1);
        Predicate<Integer> gt3 = (n) -> n > 3;
        Function<Integer, Integer> plus11 = (n) -> n + 11;

        List<Integer> numbersProcessed = numbers
                .stream()
                .filter(gt3)
                .map(plus11)
                .toList();
    }
}
  1. Regarding Predicate: at the moment the number 3 is hard-coded. Say I want a dynamic predicate which is created at runtime, e.g. (n) -> n > x, with x being some Integer. How could I create a dynamic Predicate object? I tried something using new Predicate(), but this didn't seem right.

  2. Same as 1. regarding Function: say I don't want plus 11, but (n) -> n + x, with x being some Integer supplied at runtime. How can I create a dynamic Function object?

  3. The .filter(), .map(), and .toList() operations make me think: Java is not a functional language by design. Since the essence of functional languages is to manipulate lists all the time, those languages are optimized to constantly produce new lists from existing lists, the more so as functional languages do not allow in-place manipulations on objects in principle. I was wondering: say there is a large list, containing millions of items. Will these kinds of list manipulations have a significant impact on Java's performance? In essence: what is the cost of using the functional approach in Java?

Thank you very much and have a nice day.

1 Answers

You can create a method like this:

Predicate<Integer> gt(Integer number) {
    return (n) -> n > number;
}

And use a Map<Integer, Predicate<Integer>> to store these values. You can implement a getter like this:

Predicate<Integer> getGt(Map<Integer, Predicate<Integer>> gtMap, Integer key) {
    if (!gtMap.containsKey(key)) gtMap.put(key, gt(key));
    return gtMap.get(key);
}

As about the third question, I recommend doing some experiments and reading some articles about it.

Related