一个Java8比较器

最近在开发中,重构背包功能时,需要对物品进行多级排序。

用传统的Java语法很难实现,所以写了个函数式比较器,特点有

  1. 支持链式分级排序
  2. 支持正序、逆序排
  3. 支持按条件移动(前移后移)

下面给个简单例子

public static void main(String[] args) {
    List employeeList = Arrays.asList(
    Employee.builder().id(101).name("Matt").gender("male").salary(5000).office("New York").build(),
    Employee.builder().id(102).name("Sheila").gender("female").salary(6000).office("London").build(),
    Employee.builder().id(103).name("Carrie").gender("male").salary(20000).office("New York").build(),
    Employee.builder().id(104).name("Hannah").gender("female").salary(7000).office("New York").build(),
    Employee.builder().id(105).name("Pat").gender("male").salary(8000).office("London").build(),
    Employee.builder().id(106).name("Elin").gender("female").salary(29000).office("Shanghai").build()
    
    );

    Collections.sort(employeeList, 
            //男性移动到下面
        ComparatorPlus.moveBack( x -> "male".equals(x.getGender()))
            //"New York"的往前排
            .thenMoveForward(x -> "New York".equals(x.getOffice()))
            //再按 薪水倒排
            .thenReversedComparing(Employee::getSalary)
    );

    System.out.println("----");
    employeeList.forEach(System.out::println);
}

output:
Employee(id=104, name=Hannah, gender=female, salary=7000, office=New York)
Employee(id=106, name=Elin, gender=female, salary=29000, office=Shanghai)
Employee(id=102, name=Sheila, gender=female, salary=6000, office=London)
Employee(id=103, name=Carrie, gender=male, salary=20000, office=New York)
Employee(id=101, name=Matt, gender=male, salary=5000, office=New York)
Employee(id=105, name=Pat, gender=male, salary=8000, office=London)

最后,附上比较器源码


import java.io.Serializable;
import java.util.Comparator;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * 增强排序器,支持逆向排序和条件移动
 * Created by adam.zh on 2018/1/20
 */
@FunctionalInterface
public interface ComparatorPlus extends Comparator {
    @Override
    int compare(T o1, T o2);

    public static > ComparatorPlus comparing(
            Function keyExtractor) {
        Objects.requireNonNull(keyExtractor);
        return (ComparatorPlus & Serializable)
                (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    }

    public static > ComparatorPlus reversedComparing(
            Function keyExtractor) {
        return (ComparatorPlus & Serializable) comparing(keyExtractor).reversed();
    }


    public static  ComparatorPlus moveForward(
            Predicate predicate) {
        return moveBack(predicate.negate());
    }

    public static  ComparatorPlus moveForward(
            Predicate predicate,
            Comparator sub) {
        return (ComparatorPlus & Serializable) (c1, c2) ->
                predicate.test(c1) && predicate.test(c2) ? sub.compare(c1, c2)
                        : moveForward(predicate).compare(c1, c2);
    }

    public static  ComparatorPlus moveForward(
            Predicate predicate,
            Comparator sub1,
            Comparator sub2
    ) {
        return (ComparatorPlus & Serializable) (c1, c2) ->
                !predicate.test(c1) && !predicate.test(c2) ? sub2.compare(c1, c2)
                        : moveForward(predicate, sub1).compare(c1, c2);
    }

    public static  ComparatorPlus moveBack(
            Predicate predicate) {
        return (ComparatorPlus & Serializable) (c1, c2) ->
                Boolean.compare(predicate.test(c1), predicate.test(c2));
    }

    public static  ComparatorPlus moveBack(
            Predicate predicate,
            Comparator sub) {
        return (ComparatorPlus & Serializable) (c1, c2) ->
                predicate.test(c1) && predicate.test(c2) ? sub.compare(c1, c2)
                        : moveBack(predicate).compare(c1, c2);
    }

    public static  ComparatorPlus moveBack(
            Predicate predicate,
            Comparator sub1,
            Comparator sub2) {
        return (ComparatorPlus & Serializable) (c1, c2) ->
                !predicate.test(c1) && !predicate.test(c2) ? sub2.compare(c1, c2)
                        : moveBack(predicate, sub1).compare(c1, c2);
    }

    default ComparatorPlus thenComparing(Comparator other) {
        Objects.requireNonNull(other);
        return (ComparatorPlus & Serializable) (c1, c2) -> {
            int res = compare(c1, c2);
            return (res != 0) ? res : other.compare(c1, c2);
        };
    }

    default > ComparatorPlus thenComparing(
            Function keyExtractor) {
        return thenComparing(comparing(keyExtractor));
    }

    default ComparatorPlus thenReversedComparing(Comparator other) {
        return thenComparing(other.reversed());
    }

    default > ComparatorPlus thenReversedComparing(
            Function keyExtractor) {
        return thenReversedComparing(comparing(keyExtractor));
    }


    default ComparatorPlus thenMoveForward(Predicate predicate) {
        return thenComparing(moveForward(predicate));
    }

    default ComparatorPlus thenMoveForward(
            Predicate predicate,
            Comparator sub) {
        return thenComparing(moveForward(predicate, sub));
    }

    default ComparatorPlus thenMoveForward(
            Predicate predicate,
            Comparator sub1,
            Comparator sub2) {
        return thenComparing(moveForward(predicate, sub1, sub2));
    }

    default ComparatorPlus thenMoveBack(Predicate predicate) {
        return thenComparing(moveBack(predicate));
    }

    default ComparatorPlus thenMoveBack(
            Predicate predicate,
            Comparator sub) {
        return thenComparing(moveBack(predicate, sub));
    }

    default ComparatorPlus thenMoveBack(
            Predicate predicate,
            Comparator sub1,
            Comparator sub2) {
        return thenComparing(moveBack(predicate, sub1, sub2));
    }


    // flip!!
    default ComparatorPlus reversed() {
        return (ComparatorPlus & Serializable) (c1, c2) -> this.compare(c2, c1);
    }

}

函数式范式表达力真的强!!

( PS: 现在没学个Scala/Clojure好意思说自己会java ;) !! )

你可能感兴趣的:(一个Java8比较器)