Java 如何制作龙眼';s等式和哈希代码与BigDecimal一起工作
我已经准确地描述了这个问题。这就是说,Java 如何制作龙眼';s等式和哈希代码与BigDecimal一起工作,java,equals,hashcode,bigdecimal,lombok,Java,Equals,Hashcode,Bigdecimal,Lombok,我已经准确地描述了这个问题。这就是说,BigDecimal等于被破坏,在类中有这样一个字段可以防止使用@EqualsAndHashCode。我提出的唯一解决方案是排除这样的字段,但这当然不是最优的 有什么解决办法吗?有没有办法为字段/类型注入我自己的比较器?好吧,这不是Lombok的错,因为一般来说,如何比较BigDecimal,还不清楚。无论如何,下面的示例代码提供了一个解决方案: import lombok.AccessLevel; import lombok.AllArgsConstruc
BigDecimal
等于被破坏,在类中有这样一个字段可以防止使用@EqualsAndHashCode
。我提出的唯一解决方案是排除
这样的字段,但这当然不是最优的
有什么解决办法吗?有没有办法为字段/类型注入我自己的比较器?好吧,这不是Lombok的错,因为一般来说,如何比较
BigDecimal
,还不清楚。无论如何,下面的示例代码提供了一个解决方案:
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.math.BigDecimal;
@Data
@AllArgsConstructor
public class WithBigDecimals {
private int i;
private String s;
@EqualsAndHashCode.Exclude
private BigDecimal d;
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
@ToString.Exclude
private final BigDecimalComparer _bdc = new BigDecimalComparer();
private class BigDecimalComparer {
public WithBigDecimals getOuter() {
return WithBigDecimals.this;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof BigDecimalComparer))
return false;
BigDecimalComparer other = (BigDecimalComparer) obj;
double epsilon = d.doubleValue() / 1000d;
return d.doubleValue() - epsilon < other.getOuter().d.doubleValue() &&
other.getOuter().d.doubleValue() < d.doubleValue() + epsilon;
}
}
public static void main(String[] args) {
var a = new WithBigDecimals(42, "2.4", new BigDecimal("2.4"));
var b = new WithBigDecimals(42, "2.4", new BigDecimal("2.40"));
var c = new WithBigDecimals(42, "2.4", new BigDecimal(2.4));
System.out.printf("%s == %s ?? %b%n", a, b, a.equals(b));
System.out.printf("%s == %s ?? %b%n", b, c, b.equals(c));
System.out.printf("%s == %s ?? %b%n", a, c, a.equals(c));
}
}
导入lombok.AccessLevel;
导入lombok.allargsconstuctor;
导入龙目数据;
导入lombok.EqualsAndHashCode;
进口龙目吸气剂;
进口龙目织机;
进口龙目草;
导入java.math.BigDecimal;
@资料
@AllArgsConstructor
具有大小数的公共类{
私人互联网i;
私有字符串;
@EqualsAndHashCode.Exclude
私有bigd;
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
@ToString.Exclude
私有最终BigDecimalComparer _bdc=新的BigDecimalComparer();
私有类大小数比较器{
public with bigdecimals getOuter(){
以大小数返回。这是;
}
@凌驾
公共布尔等于(对象obj){
if(!(大小数比较器的obj实例))
返回false;
BigDecimalComparer other=(BigDecimalComparer)obj;
双ε=d.doubleValue()/1000d;
返回d.doubleValue()-epsilon
如您所见,
BigDecimal
被排除在@EqualsAndHashCode
之外。为了重新注入它,我创建了另一个只能私下访问的字段。它用于自动生成的equals()
方法,可以随意提供比较。我在这里使用了一个简单的几乎平等的版本。我最近也遇到了同样的问题
基本上,您可以看到这种行为:
BigDecimal x = new BigDecimal("2");
BigDecimal y = new BigDecimal("2.00");
System.out.println(x.equals(y)); // False
System.out.println(x.compareTo(y) == 0 ? "true": "false"); // True
没有现成的解决方案,但您可以重新定义hashCode&equals中使用的BigDecimal字段值:
@EqualsAndHashCode
class Test Class {
@EqualsAndHashCode.Exclude
private BigDecimal amount;
...
@EqualsAndHashCode.Include
private BigDecimal getAmountForEquals() {
return ofNullable(amount).map(BigDecimal::stripTrailingZeros).orElse(null);
}
}
在将
BigDecimal
存储到字段中之前,请始终调用stripTrailingZeroes
?Uf,我不希望为了比较而将代码弄乱。您也可以始终设置BigDecimal的比例。请参见示例:那么您可能必须自己重写Equals…报告为,并以结束。警告:在epsilon的某个值内将Equals
编码为equal可能会导致a等于b和b等于c,但a绝对不等于c。然而,OP声称BigDecimal
的equals()
是坏的,我无法提出任何据称没有坏的实现。