如何实现可比较同类型任意Number的泛型Lambda比较器
核心实现思路
所有Java数值包装类(Integer、Double、Long等)都实现了Comparable接口,你可以基于compareTo方法实现通用比较逻辑,不需要重复为每个类型编写实现,也可以完全规避额外运行时开销,同时保留lambda的高性能特性。
第一步:优化基础接口
调整Operator接口的泛型限定和返回值,更适配比较操作的场景:
// 泛型限定为实现了Comparable的类型,所有数值包装类都满足该要求 public interface Operator<T extends Comparable<T>> { boolean eval(T p1, T p2); }
第二步:实现通用比较运算符
不需要单独为每个数值类型编写静态方法,直接通过泛型方法生成对应类型的运算符即可:
public class ComparisonOperators { // 大于等于 public static <T extends Comparable<T>> Operator<T> greaterOrEqual() { return (v1, v2) -> v1.compareTo(v2) >= 0; } // 小于等于 public static <T extends Comparable<T>> Operator<T> lessOrEqual() { return (v1, v2) -> v1.compareTo(v2) <= 0; } // 等于 public static <T extends Comparable<T>> Operator<T> equal() { return (v1, v2) -> v1.compareTo(v2) == 0; } // 大于 public static <T extends Comparable<T>> Operator<T> greaterThan() { return (v1, v2) -> v1.compareTo(v2) > 0; } // 小于 public static <T extends Comparable<T>> Operator<T> lessThan() { return (v1, v2) -> v1.compareTo(v2) < 0; } }
第三步:消除冗余的instanceof判断
通过工厂类提前缓存常用数值类型的运算符实例,运行时直接根据值的类型获取对应运算符即可:
public class OperatorFactory { // 缓存常用类型的大于等于运算符实例,其他运算符可按相同逻辑扩展缓存 private static final Map<Class<?>, Operator<? extends Comparable<?>>> GE_CACHE = new HashMap<>(); static { GE_CACHE.put(Integer.class, ComparisonOperators.<Integer>greaterOrEqual()); GE_CACHE.put(Double.class, ComparisonOperators.<Double>greaterOrEqual()); GE_CACHE.put(Long.class, ComparisonOperators.<Long>greaterOrEqual()); GE_CACHE.put(Short.class, ComparisonOperators.<Short>greaterOrEqual()); GE_CACHE.put(Float.class, ComparisonOperators.<Float>greaterOrEqual()); GE_CACHE.put(Byte.class, ComparisonOperators.<Byte>greaterOrEqual()); } @SuppressWarnings("unchecked") public static <T extends Comparable<T>> Operator<T> getGreaterOrEqual(Class<T> type) { return (Operator<T>) GE_CACHE.get(type); } // 其他运算符的工厂方法可按相同逻辑扩展 }
原来GUI中的冗余判断代码可以直接简化为一行:
Expression.setOperator(OperatorFactory.getGreaterOrEqual(Param.value.getClass()));
性能说明
该实现完全基于lambda和Comparable的原生实现,无反射开销,和单独为每个类型编写的lambda性能完全一致。每个类型的Operator实例都是提前创建的,运行时直接调用compareTo方法会被JVM自动内联优化,性能和直接使用>=等运算符几乎无差异。
内容的提问来源于stack exchange,提问作者MicD
相关产品推荐
相关产品推荐

