Home > Enterprise >  Understanding Java Stream with Function as Parameter
Understanding Java Stream with Function as Parameter

Time:11-27

I am using Java in my project. I see code like below and not able to understand the flow.

public static void main(String[] args) {
    Person p1 = new Person("test1");
    Person p2 = new Person("test2");

    List<Person> l = List.of(p1, p2);
    var count = l.stream().filter(checkMethod(Person::getName)).count();
    System.out.println(count);
  }

  public static final <T> Predicate<T> checkMethod(Function<? super T, ?> keyExtractor) {
    Objects.requireNonNull(keyExtractor);
    final var seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
  }

Person.java
 public class Person {

  Person(String name) {
    this.name = name;
  }

  private String name;
   //getters and setters for name
  }
}

It identifies the count of unique name from list of person objects. I see check method is called only once. But usually filter method will be executed for each items in list.

Is it like entire list of persons is sent to check method and called only once?

CodePudding user response:

Let's take a look what .filter(checkMethod(Person::getName)) actually does and how it works:

  • At first checkMethod(Person::getName) is executed and returns a Predicate, which is the argument required for the filter(..) method
  • then, filter(t -> seen.add(t.getName())) is executed for every item on the stream
  • As Collection.add(..) returns a boolean indicating whether the element as added, every item is removed whose name was already seen

CodePudding user response:

checkMethod() generates a stateful predicate.

While executing checkMethod() JVM evaluates the lambda expression (lambdas are always evaluated at Runtime) and creates an instance of a Functional interface (Predicate) which captures the reference to the Set seen. I.e. local variable seen in the method would vanish when the method terminates, but the Predicate would hold the reference to this object to it, so the Set alive until the predicate is alive.

But usually filter method will be executed for each items in list.

And it would be called only once. Each stream element would be checked against the instance of Predicate returned by checkMethod() using Predicate.test().

In other words, method test() would be invoked on the predicate for every element in the stream, but invocation of checkMethod() would occur only one and each element would be checked against the same predicate.

So, you're confusing the creation of a Predicate via checkMethod(), and validation of elements via Predicate.test().

  • Related