Search code examples
javafunctional-interface

Java: functional chaining of getters or zero args methods


I want to create Comparator based on Enum.name() which is inside a bean class:

List.of(new JobRsp(Job.MY), new JobRsp(Job.OUR), new JobRsp(Job.YOUR)).stream()
    .sorted(__ -> __.getJob().name());

If I only needed Enum.order() I could write sorted(Job::getJob).

Is it possible co compose zero args methods in functional style in Java? Something like:

FuncUtils.compose(Job::getJob, Enum::name)

Or probably even longer:

.sort(FuncUtils.chainGetters(ObjA::getB, ObjB::getC, ObjC::getD, ObjD::getE))

Imaginary chainGetters might check for nulls.

I understand that Java doesn't allow variadic generics so there should be chainGetters for each argument arity.


Solution

  • You have the default andThen method in Function interface that lets you chain functions.

    Unfortunately there is no "clean" way to achieve the result, because to call a default method on a method reference you need to assign it, or cast it.

    For example:

    import static java.util.Comparator.comparing;
    
    Function<Job, Enum> getJob = Job::getJob;
    ...
       .sorted(comparing(getJob.andThen(Enum::name)))
    

    Or:

       .sorted(comparing( ((Function<Job, Enum>) Job::getJob).andThen(Enum::name) ))
    

    So, it's cleaner to use a lambda expression using Comparator.comparing to create the comparator:

    ...
       .sorted(comparing(j -> j.getJob().name()))
    

    The compose utility method that you suggest could be also implemented with:

    public static <A, B, C>  Function<A, C> compose(Function<A, B> first, Function<B, C> second) {
        return first.andThen(second);
    }
    

    So you could use:

    .sorted(comparing( FuncUtils.compose(Job::getJob, Enum::name)))