Streams in Java, can't figure this code out

2019-03-24 11:01发布

问题:

I've found the following code snippet:

Function<Integer, Predicate<Integer>> smallerThan = x -> y -> y < x;
List<Integer> l = Arrays.asList(5, 6, 7, 23, 4, 5645,
    6, 1223, 44453, 60182, 2836, 23993, 1);

List<Integer> list2 = l.stream()
    .filter(smallerThan.apply(l.get(0)))
    .collect(Collectors.toList());

System.out.println(list2);

As output I receive:

[4, 1]

How does the smallerThan function in this example work, considering that we only pass one parameter smallerThan.apply(l.get(0))?

回答1:

smallerThan is a Function that accepts a single Integer and returns a Predicate<Integer> (a Predicate<Integer> is a function that accepts a single Integer and returns a boolean).

smallerThan.apply(l.get(0)) returns a Predicate<Integer> that looks like this:

y -> y < l.get(0)

i.e. it returns true if the input passed to it is smaller than l.get(0).

When you pass that Predicate to filter, your Stream pipeline keeps only the elements smaller than l.get(0).

Your pipeline can be re-written as:

List<Integer> list2 = l.stream()
    .filter(y -> y < l.get(0))
    .collect(Collectors.toList());

Since l.get(0) is 5, your pipeline returns all the elements of the original list smaller than 5.



回答2:

That is called "currying" and it was possible before Java 8 too via anonymous classes for example, but it was much more verbose. Ultimately, it's a Function that returns a Function and while not that spread in Java (yet), in other functional languages it is used quite heavily.



回答3:

The function smallerThan accepts a number and returns a Predicate object, in which case we apply this predicate to every element of the stream.

So, l.get(0) will retrieve the first value of the list l which is (5), we then pass it to the smallerThan function and this function returns a predicate with the criteria y -> y < x; which reads as "given a number, return true if it is less than 5" hence output is [4, 1]