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()
是坏的,我无法提出任何据称没有坏的实现。