Why BigInteger in java is designed to be immutable

2020-08-17 05:51发布

问题:

In java , BigInteger is immutable but I want to understand why because a lot of times it is used to do a lot of calculations which can produce a lot of objects. So , it feels kind of intuitive to not make it immutable. The situation which comes to my mind is something like of string operations and then the option of StringBuilder. Should there be non-immutable counterpart of BigInteger ? I think it might be beneficial in a lot of situations.

Edit: I know the benefits of immutability and how it's beneficial in many cases. I just wanted to understand the benefits w.r.t BigInteger. I have used BigInteger to calculate factorial of large numbers. So , I would have preferred a mutable BigInteger. Similarly , BigInteger will be used for calculations where the result is much larger than int. For other cases there is BigDecimal.

回答1:

Effective Java by Josh Bloch explains the benefits of immutable classes, in "Item 15: Minimize Mutability":

Immutable classes are easier to design, implement, and use than mutable classes. They are less prone to error and are more secure.

An immutable object is simple, because the object can only exist in one state -- the state it was created in. Simple code tends to have fewer bugs. Because the object cannot be modified, it is also thread-safe without external synchronization.

Bloch addresses the performance problem with immutable classes, using BigInteger as an example:

The only real disadvantage of immutable classes is that they require a separate object for each distinct value. Creating these objects can be costly, especially if they are large. [...]

Internally, the immutable class can be arbitrarily clever. For example, BigInteger has a package-private mutable “companion class” that it uses to speed up multistep operations such as modular exponentiation. It is much harder to use the mutable companion class than to use BigInteger for all of the reasons outlined earlier, but luckily you don’t have to: the implementors of BigInteger did the hard work for you.

So internally, BigInteger already does some optimization for you. If you really want a mutable BigInteger, you can use a BitSet, but note that this probably makes your code more complex -- and more error-prone. You should use the simplest possible solution (BigInteger) unless you are confident that using a mutable version will give you a noticeable performance gain (see also "Item 55: Optimize judiciously" from the same book).