Passing Method References For Stream Order

Viewed 80

I have a processor class that accepts arbitrary predicates to be run on streams, plus a field for sorting on. My Processor class:

import com.example.vm.domain.Transaction;
import lombok.Builder;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Builder
public class Processor {

    private Collection<Predicate<Transaction>> predicates;

    public List<Transaction> process(List<Transaction> transactions) {

        return process(transactions, TransactionFields.CATEGORY.getExtractor());
    }

    public List<Transaction> process(List<Transaction> transactions, Function<Transaction, Object> order) {

        if (predicates == null) {
            return transactions;
        }

        if (order == null) {

            return transactions.stream()
                    .parallel()
                    .filter(predicates.stream().reduce(p -> true, Predicate::and))
                    .collect(Collectors.toList());
        } else {

            return transactions.stream()
                    .parallel()
                    .filter(predicates.stream().reduce(p -> true, Predicate::and))
                    .sorted(Comparator.comparing(Transaction::getCategory))
                    .collect(Collectors.toList());

        }
    }
}

This works fine, but I want the Comparator.comparing(Transaction::getCategory) to be a parameter so that

.sorted(Comparator.comparing(Transaction::getCategory)) 

becomes this

.sorted(Comparator.comparing(order))

The overloaded call:

process(transactions, TransactionFields.CATEGORY.getExtractor());

comes from an enum to return the extractor field:

import com.example.vm.domain.Transaction;
import java.util.function.Function;

public enum TransactionFields {

    CATEGORY("category", t -> t.getCategory());

    private String name;
    private Function<Transaction, Object> extractor;

    private TransactionFields(String name, Function<Transaction, Object> extractor) {
        this.name = name;
        this.extractor = extractor;
    }

    public Function<Transaction, Object> getExtractor() {
        return extractor;
    }
}

I can't get this to work and casting to a Comparator also fails. The solution doesn't have to be a Comparator, just so long as it sorts. Anyone know how to solve this?

1 Answers

The generic constraints of the Function parameter of the Comparator#comparing are <T,U extends Comparable<? super U>>, meaning the function has to return something that extends Comparable<…>. Change your function from Function<Transaction, Object> to Function<Transaction, Comparable<…>> and you should be able to do .sorted(Comparator.comparing(order)).

The only requirement is that your Transaction#getCategory method returns something which is Comparable (String, number, custom type which implements Comparable<YourType>).

Related