Законно ли определить final неизменный параметр, связать параметр с другой локальной переменной и изменить локальную переменную? - PullRequest
0 голосов
/ 12 мая 2019

Обратите внимание: тот же вопрос применим к другим неизменным типам, таким как String и Boolean.


У меня есть такой метод (это простой пример более сложного метода):

Пример 1

public BigDecimal addTwo(BigDecimal bigDecimal) {
    bigDecimal = bigDecimal.add(new BigDecimal(2));
    return bigDecimal;
}

Я знаю, я мог бы просто вернуть bigDecimal.add(new BigDecimal(2)).Но это только пример.

Проблема с этим кодом заключается в том, что я не могу добавить final к параметру метода, и Eclipse беспокоит меня.Поэтому я бы написал:

Пример 2

public BigDecimal addTwo(final BigDecimal bigDecimal) {
    BigDecimal bigDecimalLocal = bigDecimal;
    bigDecimalLocal = bigDecimalLocal.add(new BigDecimal(2));
    return bigDecimalLocal;
}

Я знаю, я могу сделать напрямую BigDecimal bigDecimalLocal = bigDecimal.add(new BigDecimal(2)).Но я повторяю, это только пример.

Вопрос в следующем: когда я делаю:

BigDecimal bigDecimalLocal = bigDecimal;

Я не создаюновый BigDecimal.Я назначаю один и тот же объект другой переменной.Я обнаружил на SO , что простой способ клонирования BigDecimal:

Пример 3

BigDecimal bigDecimalLocal = new BigDecimal(bigDecimal.toString());

Вопрос в том, что BigDecimal является неизменным,это действительно необходимо?Разве я не могу просто сделать, как в примере № 2?Я думаю, что ключевое слово final не может быть аннулировано таким образом.

Ответы [ 3 ]

1 голос
/ 12 мая 2019

Пример 2 подойдет, но вам совсем не нужны локальные переменные, и я думаю, что они снижают читабельность метода. Я бы просто сделал

public BigDecimal addTwo(final BigDecimal bigDecimal) {
    return bigDecimal.add(BigDecimal.valueOf(2));
}

Что, если я хочу добавить еще один BigDecimal "? Я должен вернуть bigDecimal.add(BigDecimal.valueOf(2).add(BigDecimal.valueOf(3))? Я думаю, что это не так читабельно.

Если вы собираетесь добавить два-много раз (или несколько констант), то имеет смысл извлечь константы как константы. Как,

private static final BigDecimal TWO = BigDecimal.valueOf(2);
private static final BigDecimal THREE = BigDecimal.valueOf(3);

public static BigDecimal addTwoAndThree(final BigDecimal bigDecimal) {
    return TWO.add(THREE).add(bigDecimal);
}
0 голосов
/ 12 мая 2019

Хорошо, я признаю, что не знаю о ключевом слове final.Должен сказать, что я не понимаю его полезности:

  • Если вы переназначаете параметр внутри метода, final или нет, объект остается неизменным, конечно же

  • Если вместо этого вы изменяете неизменный объект, final или нет, объект изменяется и вне метода.

  • Кажется, единственное, что параметрс final сделать так, что он не может быть переназначен только внутри метода.

Я должен сказать, что я делаю что-то подобное много раз:

public List<MyBean> findByNation(String nation) {
    if (nation != null) {
        nation = nation.toUpperCase();
    } else {
        nation = "";
    }

    [...]
}

или

public List<Date> findConfirmedDates(Date start, Date end) {
    if (end == null) {
        end = new Date();
    }
}

или

public String findFilteredSql(String queryFilter, SearchBean searchBean) {
    if (searchBean.getSupplierId() != null) {
        queryFilter += " JOIN SUPPLIER_COMMODITY sc ON sc.SUPPLIERID = v.SUPPLIERID ";
    }

    [...]
}

или

public static String format(BigDecimal val, Locale locale, int scale) {
    if (val == null) {
        return "-";
    }

    val = valLocal.subtract(BigDecimal.ONE);
    val = val.multiply(NumberUtility.BigDecimal100);

    [...]
}

Да, в университете я узнал, что если я создаю новую переменную вместо перезаписистарый, скорость программы улучшена (я не очень хорошо помню, мне кажется, что процессор и регистры каким-то образом задействованы ...).В любом случае, это микрооптимизация, полезная для библиотек C или Fortran, которые выполняют числовые вычисления.

ИМХО, это намного более читабельно, как я написал методы выше, и извините за final.

Поэтому я не нахожу полезность final в этих случаях.Более того, я не считаю это полезным.Я думаю, что я приму пример № 1 в вопросе, и я просто отключу предупреждение об Eclipse и не добавлю это ключевое слово с возможной полезностью.

0 голосов
/ 12 мая 2019

Кажется, вы не понимаете концепцию ссылок.

Когда у вас есть это:

BigDecimal incoming = new BigDecimal(2);
addTwo(incoming);
...

public BigDecimal addTwo(BigDecimal bigDecimal) {
  bigDecimal = bigDecimal.add(new BigDecimal(2));
}

Дело в том, что incoming по-прежнему 2 после завершения этого метода!

При вызове add() создается новый объект BigDecimal, а переменная bigDecimal указывает на этот новый объект.

Но ссылка incoming все еще указывает на старый объект!

Короче говоря: это ключевое слово final для параметра метода не делает совсем того, что вы думаете. Его единственная цель - не дать вам переназначить этот параметр / значение. Итак, вы действительно хотите узнать о разнице между объектами и ссылками . А потом о передать по ссылке .

...