如何制作一个比较任意数量的相同类型的通用 lambda
Posted
技术标签:
【中文标题】如何制作一个比较任意数量的相同类型的通用 lambda【英文标题】:How to make a generic lambda that compares any Number of identical type 【发布时间】:2021-11-22 23:52:37 【问题描述】:我需要在运行时替换比较运算符,其中两个数字将被比较 GreaterThanOrEquals、LessThanOrEquals、Equals 等,但理想情况下,我不会为整数、双精度、长整数、短整数、浮点数和字节复制我的代码.我的部分要求是尽可能将操作保持在 lambdas 中以提高性能。
注意:这两个值总是相同的类型。我无意进行混合类型的比较。
这是我的粗略代码。我试图用 Java.lang.Number 参数化最后一个静态方法,但 >= 对 Number 不起作用:
public class Expression
public Param p1;
public Operator o;
public Param p2;
public Object eval()
return o.eval(p1.getValue(),p2.getValue());
public interface Operator<T>
Object eval(T p1,T p2);
public interface GreaterOrEqual extends Operator<Number>
static Operator<Integer> Integers()
return (v1, v2) -> v1 >= v2;
static Operator<Double> Doubles()
return (v1, v2) -> v1 >= v2;
static Operator<Long> Longs()
return (v1, v2) -> v1 >= v2;
static Operator<Number> generic()
// this one won't compile as ">= can't be applied to Java.lang.Number"
return (v1, v2) -> v1 >= v2;
编辑:此代码重复也意味着我的 GUI 代码将需要使用 if (Param.value instanceof Integer) Expression.setOperator(GreaterOrEqual.Integers);
,这是更多的代码重复。
【问题讨论】:
你可以做v1.doubleValue() >= v2.doubleValue()
这不是性能慢吗?将每个值转换为双精度值?要求之一是高性能......可能在几微秒内反复运行......取决于当前负载。
Operator
的意图是什么?从eval
返回Object
背后的想法是什么?
Operator 是一个接口,它的 children 赋予它的 lambda 功能,就像一个策略模式。 GUI 或文本解析器都将构建 Expression 对象。返回对象,因为根据操作,它可能需要是布尔值或整数/双精度(例如乘法运算符)。
【参考方案1】:
首先你必须明白,写Operator<Integer>
并没有给你带来任何好处。 Java 使用自动装箱将int
转换为Integer
包装对象。然后在您的代码 ((v1, v2) -> v1 >= v2
) 中,Integer
对象被转换回 int
。
更通用的解决方案是使用Comparable
接口。 Number
没有实现该接口,但所有重要的 Number 实现如 Double
都支持它。
Operator<Comparable<?>> gt = (v1, v2) -> v1.compareTo(v2) > 0;
Operator<Comparable<?>> ge = (v1, v2) -> v1.compareTo(v2) >= 0;
Operator<Comparable<?>> ge = (v1, v2) -> v1.compareTo(v2) = 0;
Operator<Comparable<?>> le = (v1, v2) -> v1.compareTo(v2) <= 0;
Operator<Comparable<?>> lt = (v1, v2) -> v1.compareTo(v2) < 0;
compareTo
参数较小时返回 1,相同大小时返回 0,较大时返回 -1。
【讨论】:
哦,很高兴了解 Autoboxing。我用它来强制两个值属于同一类型……但我可以用其他方式强制它。所以 Comparable 不适用于 Integer,但适用于 Double、Long、Float?您认为我应该将 Int 转换为 Double 进行比较(如提到的@QBrute)吗? 它适用于所有包装类,包括Integer
。 int
和 Integer
不一样。一个是对象,另一个是原始类型。【参考方案2】:
可比接口的使用
public static <T extends Comparable<? super T>> int compare(T x, T y)
return x != null ? x.compareTo(y) : -y.compareTo(x);
可能的结果
-1
,当x
小于y
0
,当x
等于y
1
,当x
大于y
可能的用途
compare(x, y) < 0
- x
小于 y
compare(x, y) <= 0
- x
小于或等于 y
compare(x, y) == 0
- x
等于 y
compare(x, y) >= 0
- x
大于或等于 y
compare(x, y) > 0
- x
大于 y
如果有错误或问题,请通知我!
【讨论】:
以上是关于如何制作一个比较任意数量的相同类型的通用 lambda的主要内容,如果未能解决你的问题,请参考以下文章
打字稿:如何制作接受对象的类型,其键匹配通用但所有值都是值参数的映射函数
如何在 TypeScript 3+ 中正确键入通用元组剩余参数?