Рассчитать hashCode для BigDecimal без учета scale

159
14 мая 2021, 05:50

Доброго времени суток.

Задача: имеется следующий класс

public class Products {
public final Product PRODUCT;
public final double AMOUNT;
public final BigDecimal PRICE;
public final BigDecimal CALORIES;
    public Products(Product product, 
                    double amount, 
                    BigDecimal price, 
                    BigDecimal calories) {
        PRODUCT = product;
        AMOUNT = amount;
        PRICE = price;
        CALORIES = calories;
    }
}

Необходимо переопределить для данного класса метод equals() и hashCode(). Все поля должны участвовать в переопределяемых методах. И самое главное - при сравнении полей PRICE и CALORIES необходимо сравнивать только значения без учета масштаба, т.е. при сравнении двух BigDecimal со значениями 12 и 12.000000 должно возвращаться true. Как я пытался решить задачу:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Products that = (Products) o;
    return Double.compare(that.AMOUNT, AMOUNT) == 0 &&
            Objects.equals(PRODUCT, that.PRODUCT) &&
            PRICE.compareTo(that.PRICE) == 0 &&
            CALORIES.compareTo(that.CALORIES) == 0;
}
@Override
public int hashCode() {
    int result = 17;
    result = result * 31 + PRODUCT.hashCode();
    result = result * 31 + Double.hashCode(AMOUNT);
    result = result * 31 + PRICE.hashCode();
    result = result * 31 + CALORIES.hashCode();
    return result;
}

В чем проблема: Метод equals() сравнивает BigDecimal без учета масштаба, а hashCode() использует BigDecimal::hashCode(), который вычисляет значения с учетом масштаба. Вопрос: как рассчитать hashCode для BigDecimal без учета масштаба?

Answer 1

Я бы пошел от обратного. В реальной жизни цена у вас не может быть с произвольным количеством знаков после запятой. То же самое с калорийностью и количеством (количество я бы тоже хранил в BigDecimal).

Можно в конструкторе принудительно устанавливать требуемый масштаб, после этого hashCode() у вас будет считаться одинаково для одинаково для одинаковой цены, калорийности, количества.

public class Products {
    public final Product PRODUCT;
    public final BigDecimal AMOUNT;
    public final BigDecimal PRICE;
    public final BigDecimal CALORIES;
    public Products(Product product, 
                    BigDecimal amount, 
                    BigDecimal price, 
                    BigDecimal calories) {
        PRODUCT = product;
        AMOUNT = amount.setScale(3, BigDecimal.ROUND_HALF_UP);  // до грамм
        PRICE = price.setScale(2, BigDecimal.ROUND_HALF_UP);  // до копеек
        CALORIES = calories.setScale(4, BigDecimal.ROUND_HALF_UP);  // до 1/10000
    }
}

Методы equals и hashCode не меняются.

Answer 2

можно взять doubleValue у BigDecimal и затем уже брать hash

@Override
public int hashCode() {
    int result = 17;
    result = result * 31 + PRODUCT.hashCode();
    result = result * 31 + Double.hashCode(AMOUNT);
    result = result * 31 + PRICE.hashCode();
    result = result * 31 + Double.hashCode(CALORIES.doubleValue())
    return result;
}
READ ALSO
Проблема с использованием цикла for

Проблема с использованием цикла for

Всем привет! Я только новичок и пытаюсь разобраться с циклом for в Java

76
Как перехватить исключения метода

Как перехватить исключения метода

Есть метод в кодеОн подключается к базе и заносит туда значения

103
this.ИМЯ_ФУНКЦИИ is not a function

this.ИМЯ_ФУНКЦИИ is not a function

Есть класс, в котором есть 3 функцииДве из них должны возвратить значение

299