如何使Lombok的EqualsAndHashCode与BigDecimal一起工作

时间:2016-04-14 13:56:31

标签: java equals hashcode bigdecimal lombok

我确实遇到了here所描述的问题。也就是说,当BigDecimal等于被打破时,在类中使用这样的字段会阻止使用@EqualsAndHashCode。我提出的唯一解决方案是exclude这样的字段,但当然这不是最佳的。

有什么解决方案吗?有没有为字段/类型注入我自己的比较器?

2 个答案:

答案 0 :(得分:0)

好吧,这不是龙目岛的错,因为目前尚不清楚如何比较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));
    }

}

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

答案 1 :(得分:0)

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

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

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);
  }
}