如何使Lombok的EqualsAndHashCode与BigDecimal一起使用

use*_*908 5 java equals hashcode bigdecimal lombok

我有这里描述的问题。这是因为BigDecimalare等于被破坏,所以在类中具有这样的字段会阻止使用@EqualsAndHashCode。我想出的唯一解决方案就是针对exclude此类领域,但这当然不是最佳选择。

有什么解决办法吗?有什么办法为字段/类型注入自己的比较器?

Leo*_*hko 6

我最近遇到了同样的问题。

基本上,您会看到以下行为:

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
Run Code Online (Sandbox Code Playgroud)

没有开箱即用的好解决方案,但您可以重新定义 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);
  }
}
Run Code Online (Sandbox Code Playgroud)


Mic*_*fel 0

BigDecimal好吧,它 \xe2\x80\x99s 不是 Lombok\xe2\x80\x99s 的错误,因为一般情况下还不清楚如何比较。无论如何,下面的示例代码提供了一个解决方案:

\n\n
import lombok.AccessLevel;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.Getter;\nimport lombok.Setter;\nimport lombok.ToString;\n\nimport java.math.BigDecimal;\n\n@Data\n@AllArgsConstructor\npublic class WithBigDecimals {\n\n    private int i;\n\n    private String s;\n\n    @EqualsAndHashCode.Exclude\n    private BigDecimal d;\n\n    @Getter(AccessLevel.NONE)\n    @Setter(AccessLevel.NONE)\n    @ToString.Exclude\n    private final BigDecimalComparer _bdc = new BigDecimalComparer();\n\n    private class BigDecimalComparer {\n        public WithBigDecimals getOuter() {\n            return WithBigDecimals.this;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (!(obj instanceof BigDecimalComparer))\n                return false;\n            BigDecimalComparer other = (BigDecimalComparer) obj;\n            double epsilon = d.doubleValue() / 1000d;\n            return d.doubleValue() - epsilon < other.getOuter().d.doubleValue() &&\n                    other.getOuter().d.doubleValue() < d.doubleValue() + epsilon;\n        }\n    }\n\n    public static void main(String[] args) {\n        var a = new WithBigDecimals(42, "2.4", new BigDecimal("2.4"));\n        var b = new WithBigDecimals(42, "2.4", new BigDecimal("2.40"));\n        var c = new WithBigDecimals(42, "2.4", new BigDecimal(2.4));\n\n        System.out.printf("%s == %s  ??  %b%n", a, b, a.equals(b));\n        System.out.printf("%s == %s  ??  %b%n", b, c, b.equals(c));\n        System.out.printf("%s == %s  ??  %b%n", a, c, a.equals(c));\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

如您所见, 被BigDecimal排除在外@EqualsAndHashCode。为了重新注入它,我创建了另一个只能私人访问的字段。用于自动生成的equals()方法,可以随意提供比较。我在这里使用了一个简单版本的几乎相等。

\n

  • 您不需要将“BigDecimals”转换为“doubles”来比较它们。为了避免值相等但比例不同的任何问题,您必须使用“BigDecimal.compare()”,当它们表示相同的值时,它返回 0。 (2认同)