× {{alert.msg}} Never ask again
Get notified about new tutorials RECEIVE NEW TUTORIALS

Use Collections.unmodifiable*() when returning internal collections to improve Java correctness, safety

Michael Safyan
Mar 25, 2016
<p>Can you spot the problem with this code?</p> <pre><code class="language-java">public class MyClass { // ... private final List&lt;SomeType&gt; someInternalList; // ... public Iterable&lt;SomeType&gt; getItems() { return someInternalList; } // ... }</code></pre> <p>It is doubtful that the author of this code intended to allow the caller of "getItems()" to modify the internal list; however, this is exactly what this code does. For example, a caller can -- in fact -- change the list by doing:</p> <pre><code class="language-java">Iterator&lt;SomeType&gt; iter = myObject.getItems().iterator(); if (iter.hasNext()) { iter.next(); iter.remove(); }</code></pre> <p>The code above (assuming that the collection supports it and has at least one entry) will remove the first item. If the function "getItems()" had returned a "List&lt;&gt;" instead of an "Iterable&lt;&gt;", there would be even more ways to modify it.</p> <p>This problem can be solved by creating a copy of the list, but copying a list is an O(n) operation, and most people invoking a function called "get"  (rather than "compute" or "getCopy") don't expect that kind of performance (as a general rule of thumb, a function called "get" should be O(1) or at least O(1) on average over many calls).</p> <p>Enter the <a href="https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html">Collections</a> utility library to the rescue. It provides a method called <a href="https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#unmodifiableList(java.util.List)">unmodifiableList</a>(), which creates a light-weight wrapper list that provides an immutable view into an existing list (rather than a copy).</p> <p>Simply changing:</p> <pre><code class="language-java"> public Iterable&lt;SomeType&gt; getItems() { return someInternalList; } </code></pre> <p>To:</p> <pre><code class="language-java"> public Iterable&lt;SomeType&gt; getItems() { return Collections.umodifiableList(someInternalList); } </code></pre> <p>.. ensures that callers won't modify the internal data structure, with negligible performance impact. </p> <p>The Collections utility library has similar methods for other types of collections (unmodifiableSet, unmodifiableMap ,etc.). In conclusion, the next time you return an internal collection, consider wrapping it in Collections.unmodifiable*().</p>
comments powered by Disqus