Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAVA 8 Extract predicates as fields or methods?

What is the cleaner way of extracting predicates which will have multiple uses. Methods or Class fields?

The two examples:

1.Class Field

void someMethod() {
    IntStream.range(1, 100)
        .filter(isOverFifty)
        .forEach(System.out::println);
}

private IntPredicate isOverFifty = number -> number > 50;

2.Method

void someMethod() {
    IntStream.range(1, 100)
        .filter(isOverFifty())
        .forEach(System.out::println);
} 

private IntPredicate isOverFifty() {
    return number -> number > 50;
}

For me, the field way looks a little bit nicer, but is this the right way? I have my doubts.

like image 597
ZeDonDino Avatar asked Mar 09 '23 09:03

ZeDonDino


1 Answers

Generally you cache things that are expensive to create and these stateless lambdas are not. A stateless lambda will have a single instance created for the entire pipeline (under the current implementation). The first invocation is the most expensive one - the underlying Predicate implementation class will be created and linked; but this happens only once for both stateless and stateful lambdas.

A stateful lambda will use a different instance for each element and it might make sense to cache those, but your example is stateless, so I would not.

If you still want that (for reading purposes I assume), I would do it in a class Predicates let's assume. It would be re-usable across different classes as well, something like this:

 public final class Predicates {
     private Predicates(){
     }

     public static IntPredicate isOverFifty() {
          return number -> number > 50;
     }
 } 

You should also notice that the usage of Predicates.isOverFifty inside a Stream and x -> x > 50 while semantically the same, will have different memory usages.

In the first case, only a single instance (and class) will be created and served to all clients; while the second (x -> x > 50) will create not only a different instance, but also a different class for each of it's clients (think the same expression used in different places inside your application). This happens because the linkage happens per CallSite - and in the second case the CallSite is always different.

But that is something you should not rely on (and probably even consider) - these Objects and classes are fast to build and fast to remove by the GC - whatever fits your needs - use that.

like image 53
Eugene Avatar answered Mar 16 '23 11:03

Eugene