最终定义一个不可变的参数,将该参数绑定到另一个局部变量并变异该局部变量是否合法?

时间:2019-05-12 17:19:33

标签: java clone immutability final

请注意:同一问题适用于其他不可变类型,例如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。我将同一对象分配给不同的变量。我found on SO克隆BigDecimal的简单方法是:

示例3

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

问题是:由于BigDecimal是不可变的,这真的必要吗?我不能像示例2那样简单吗?我认为final关键字不能以这种方式无效。

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

您似乎不了解引用的概念。

拥有此功能时:

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

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

情况是:该方法结束后incoming仍然是 2

add()调用创建一个 new BigDecimal对象,然后变量bigDecimal指向该新对象。

但是引用incoming仍然指向旧对象!

长话短说:方法参数的关键字final根本没有实现您认为的那样。其唯一目的是防止您重新分配该参数/值。因此,您真的想了解objects and references之间的区别。然后是pass by reference

答案 2 :(得分:0)

好吧,我承认我对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);

    [...]
}

是的,在大学里,我了解到,如果我创建一个新变量,而不是覆盖旧变量,程序的速度就会提高(我不太记得,在我看来,CPU和寄存器都在其中某种方式...)。无论如何,这都是微优化,对于执行数值计算的C或Fortran库很有用。

恕我直言,我编写上述方法的方式更具可读性,对final感到抱歉。

因此,在这些情况下,我找不到final的实用程序。而且,我根本没有发现它的用处。我想我将在问题中采用Example#1,并且我只会禁用Eclipse的警告,并且不会以有用的方式添加此关键字。