Unmodifiable sets are “read-only” wrappers over other collections. They do not support any modification operations such as add, remove, and clear, but their underlying collection can be changed. Sets that additionally guarantee that no change in the Collection object will ever be visible are referred to as immutable.
Java Collections unmodifiableList() MethodThe unmodifiableList() method of Java Collections class is used to get an unmodifiable view of the specified list. If any attempt occurs to modify the returned list whether direct or via its iterator, results in an UnsupportedOperationException.
Java Collections frequency() Method The frequency() method of Java Collections class is used to get the number of elements in the specified collection equal to the specified object.
unmodifiableSet( new HashSet<String>() ); creates an instance of a Set which will throw UnsupportedOperationException if one attempts to call fixed. add() or fixed. remove() , for example - the object itself will protect its internal state and prevent it from being modified.
final
declares an object reference that can't be modified, e.g.
private final Foo something = new Foo();
creates a new Foo
and places the reference in something
. Thereafter, it's not possible to alter something
to point to a different instance of Foo
.
This does not prevent modification of the internal state of the object. I can still call whatever methods on Foo
there are accessible to the relevant scope. If one or more of those methods modifies the internal state of that object, then final
won't prevent that.
As such, the following:
private final Set<String> fixed = new HashSet<String>();
does not create a Set
that can't be added to or otherwise altered; it just means that fixed
will only ever reference that instance.
By contrast, doing:
private Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );
creates an instance of a Set
which will throw UnsupportedOperationException
if one attempts to call fixed.add()
or fixed.remove()
, for example - the object itself will protect its internal state and prevent it from being modified.
For completeness sake:
private final Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );
creates an instance of a Set
which won't allow its internal state to be changed, and also means that fixed
will only ever point to an instance of that set.
The reason that final
can be used to create constants of primitives is based on the fact that the value can't be changed. Remember that fixed
above was just a reference - a variable containing an address that can't be changed. Well, for primitives, e.g.
private final int ANSWER = 42;
the value of ANSWER
is that 42. Since ANSWER
can't be changed, it will only ever have the value 42.
An example that blurs all the lines would be this:
private final String QUESTION = "The ultimate question";
Per the rules above, QUESTION
contains the address of an instance of String
which represents "The ultimate question", and that address can't be changed. The thing to remember here is that String
itself is immutable - you can't do anything to an instance of String
which changes it, and any operations which would otherwise do so (such as replace
, substring
, etc.) return references to entirely different instances of String
.
final
only guarantees that the reference to the object the variable represents can't be changed it doesn't do anything for the instance of the object and its mutability.
final Set s = new Set();
just guarantees you can't do s = new Set();
again. It doesn't make the set unmodifiable, it if did you couldn't add anything to it to begin with. So to make it really clear, final
only affects the variable reference not the object the reference points to.
I can do the following:
final List<String> l = new ArrayList<String>();
l.add("hello");
l.add("world");
l.remove(0);
but I can't do this.
l = new ArrayList<String>();
again because of the final
I can't modify what the variable l points to.
you have to do one of the following three things to make a Collection container thread safe.
java.util.Collections.syncronizedXXX();
or
java.util.Collections.unmodifiableXXX();
or
use one of the appropriate containers from java.util.concurrency.* package
.
if I had a Person
object and did final Person p = new Person("me");
it means I can't reassign p
to point to another Person
object. I can still do p.setFirstName("you");
What confuses the situation is that
final int PI = 3.14;
final String greeting = "Hello World!";
look like const
in C++, when in fact the objects that they point to are immutable/unmodifiable by nature. Containers or objects with mutator methods that can alter the internal state of the object are not const
just the reference to those objects are final
and can't be reassigned to reference another object.
The Collections.unmodifiableSet(Set<? extends T>)
will create wrapper on the original set. This wrapper set can not be modified. but still the original set can be modified.
Example:
Set<String> actualSet=new HashSet<String>(); //Creating set
Adding some elements
actualSet.add("aaa");
actualSet.add("bbb");
Printing added elements
System.out.println(actualSet); //[aaa, bbb]
Put the actualSet
into unmodifiable set and assigned to new reference(wrapperSet
).
Set<String> wrapperSet=Collections.unmodifiableSet(orginalSet);
Print the wrapperSet. so it will have actualSet
Values
System.out.println(wrapperSet); //[aaa, bbb]
lets try to remove/add one element on wrapperSet
.
wrapperSet.remove("aaa"); //UnSupportedOperationException
Add one more element in actualSet
actualSet .add("ccc");
Print actualSet
and wrapperSet
. both sets values are same. so If you add/remove any elements on actual set the changes will be reflected on wrapper set as well.
System.out.println(actualSet); //[aaa, ccc, bbb]
System.out.println(wrapperSet); // [aaa, ccc, bbb]
Usage:
This Collections.unmodifiableSet(Set<? extends T>)
is used to prevent modification of Set's getter method of any object. let say
public class Department{
private Set<User> users=new HashSet<User>();
public Set<User> getUsers(){
return Collections.unmodifiableSet(users);
}
}
final
is not (C++-style) const
. Unlike C++, Java does not have const
-methods or anything like that, and methods that can change the object can be called via a final
reference.
Collections.unmodifiable*
is a wrapper that enforces (at run time only, not at compile time) the read-only-ness for the collection concerned.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With