I can see that Collections.unmodifiableSet returns an unmodifiable view of the given set but I don't understand why we can't just use the final modifier to accomplish this.
In my understanding, final declares a constant: something that cannot be modified. So, if a set is declared as a constant then it cannot be modified: nothing can be removed from the set and nothing can be added.
Why do we need Collections.unmodifiableSet?
finaldeclares an object reference that can't be modified, e.g.creates a new
Fooand places the reference insomething. Thereafter, it's not possible to altersomethingto point to a different instance ofFoo.This does not prevent modification of the internal state of the object. I can still call whatever methods on
Foothere are accessible to the relevant scope. If one or more of those methods modifies the internal state of that object, thenfinalwon't prevent that.As such, the following:
does not create a
Setthat can't be added to or otherwise altered; it just means thatfixedwill only ever reference that instance.By contrast, doing:
creates an instance of a
Setwhich will throwUnsupportedOperationExceptionif one attempts to callfixed.add()orfixed.remove(), for example - the object itself will protect its internal state and prevent it from being modified.For completeness sake:
creates an instance of a
Setwhich won't allow its internal state to be changed, and also means thatfixedwill only ever point to an instance of that set.The reason that
finalcan be used to create constants of primitives is based on the fact that the value can't be changed. Remember thatfixedabove was just a reference - a variable containing an address that can't be changed. Well, for primitives, e.g.the value of
ANSWERis that 42. SinceANSWERcan't be changed, it will only ever have the value 42.An example that blurs all the lines would be this:
Per the rules above,
QUESTIONcontains the address of an instance ofStringwhich represents "The ultimate question", and that address can't be changed. The thing to remember here is thatStringitself is immutable - you can't do anything to an instance ofStringwhich changes it, and any operations which would otherwise do so (such asreplace,substring, etc.) return references to entirely different instances ofString.