How to create a deep unmodifiable collection? - java

I often make a collection field unmodifiable before returning it from a getter method:
private List<X> _xs;
....
List<X> getXs(){
return Collections.unmodifiableList(_xs);
}
But I can't think of a convenient way of doing that if the X above is itself a List:
private List<List<Y>> _yLists;
.....
List<List<Y>> getYLists() {
return Collections.unmodifiableList(_yLists);
}
The problem in the above is of course that though the client cannot modify the List of lists, it can add/delete Y objects from the embedded lists.
Any thoughts?

The best I could come up with uses ForwardingList from Google Collections. Comments are welcome.
private static <T> List<List<T>> unmodifiableList2(final List<List<T>> input) {
return Collections.unmodifiableList(new ForwardingList<List<T>>() {
#Override protected List<List<T>> delegate() {
return Collections.unmodifiableList(input);
}
#Override public List<T> get(int index) {
return Collections.unmodifiableList(delegate().get(index));
}
});
}

unfortunately, there is no easy way to get deep const-ness in java. you would have to hack around it by always making sure that the list inside the list is also unmodifiable.
i'd be interested too to know any elegant solution.

The clojure collections (map, set, list, vector) can all be nested and are immutable by default. For pure java, there is this library:
http://code.google.com/p/pcollections/

If you look at the implementation of the Collections.unmodifiable*(...) methods, you can see that they just wrap the collection. Doing a deep utility in same way should be doable.
The downside of this is that it adds extra method call to the collection access and so affects performance.

If your only goal here is to enforce encapsulation, a classic solution is to use clone() or similar to return a structure that is not the internal state of the object. This obviously only works if all the objects can be cloned, and if the copied structure is small enough.
If this is a fairly commonly used data structure, another option is to make the API that accesses it more concrete, so that you have more detailed control over the specific calls. Writing your own List implementation, as above is one way to do this, but if you can narrow down the calls to specific use cases, you can expose specific access APIs instead of the List interface.

Just in case someone is interested here is a simple solution:
public List<List<Double>> toUnmodifiable(List<List<Double>> nestedList) {
List<List<Double>> listWithUnmodifiableLists = new ArrayList<>();
for (List<Double> list : nestedList) {
listWithUnmodifiableLists
.add(Collections.unmodifiableList(list));
}
return Collections.unmodifiableList(listWithUnmodifiableLists);
}
This can be used for example as a solution if u want to expose a list with a getList() method, you can return: toUnmodifiable(mNestedList), where mNestedList is the private list in the class.
I personally found this useful when implementing a class used for parsing with GSON in Android, since it doesn't make sense to be able to modify a response, in this case the de-serialized json, I used this method as a way to expose the list with a getter and made sure the list wont be modified.

Related

Should new instance of Java Collection extension (eg. List) implementation be returned as the return value instead of existing one?

I've been taught that if there is some method which return type is java.util.Collection extension implementation (for this example lets assume it's List interface implemented by ArrayList) I should return its new instance. To be precise let me put here an example:
public List<Something> getListOfSomething() {
List<Something> somethingsList = methodCall(); //some method execution which returns list of something
//some code
return new ArrayList<>(somethingList); //returning list implementation
}
If you look at my snippet you'll see constructor call return new ArrayList<>(somethingList).
My questions are:
Is this correct approach?
If yes (or no) - why?
If it depends - depends on what?
I've been looking for an answer through the Stack, but couldn't even find similar question.
It is safe, as it cannot modify the originally returned list.
However that normally is the resposibility of the called method itself.
You would not like having copies of copies, or needlessly copy.
Under some circumstances you could do:
return Collections.unmodifiableList(somethingList);
The returned list is no longer modifiable, but that might not suit the caller.
I would leave the responsibility to the methodCall to not expose internal data.
If it is a private method, and yours is a public one, then it might be your responsibility. Check whether the data stems from a field, as then you risk exposing internal data to the exterior world.
And finally you could return a Stream which is best.
public Stream<Something> getStreamOfSomething() {
List<Something> somethingsList = methodCall();
...
return somethingList.stream();
}
A Stream gives no access to the List object whether it exposes an internal field to the outside world or not. It everytime gives a new stream/iteration through the list, and one could turn it in a list, or whatever.
Also if you need to do something with the elements of the original list, it is likely you would call .stream() on the list anyway. Otherwise:
List<Something> somethingsList = obj.getStreamOfSomething().collect(Collectors.toList());

How to use an iterator to copy a list

If I have a list, and I want to have a method that returns the list without exposing the actual list itself, what would be the best way to do that?
public class open {
private List<Open> users;
public open() {
this.users = new ArrayList<Open>();
}
public List<Open> getUsers() {
//return a copy of the list}
So basically I'd need a copy of the list... I'm guessing that using iterators might be the way to go, but is there a more efficient way to do it?
There are a number of options.
You could use the copy constructor:
return new ArrayList<>(users);
This will explicitly copy the List and return the copy. I wouldn't recommend this unless you really need a mutable copy - it's O(n) obviously.
A much more efficient approach is to use the Collections utility class, this provides a way to return an immutable view:
return Collections.unmodifiableList(users);
As this is a view, return method is O(1) rather than O(n) so more efficient. It deals with ensuring that you cannot modify the List, neither via add & remove etc nor via, for example, Iterator.remove.
It's unnecessary to create a copy of the list. You can return an unmodifiable view of the list with Collections.unmodifiableList.
return Collections.unmodifiableList(users);

Putting two linkedlists together without copying - Java, Using standard API [duplicate]

This question already has answers here:
Merge two lists in constant time in Java
(4 answers)
Closed 9 years ago.
I have two LinkedList in my code and I need to make one that have both. I will not need this Lists anymore, just the new one, which have all data I need.
I could use .addAll(), but performance is I huge issue and I cant wait to copy,adding references, everything every time..
I am looking for something like we normally do if we create our own linkedlist, just connect the last node from one to the fist from the second.. Is there a way to do that using the LinkedList class from the java api?
Merging collections is a different case, although the operation means almost the same, my issue is just regarding performance and just for linkedlists, which normally can do what I need. Also "merging" is kind of an ambiguous term, what I want is just to put then together no matter what order they are, with performance in mind.I am not looking if is possible to merge...
Another thing, my question is just regarding the API, I am not looking for building my own code (boss requirement) and that is why is different from this one: Merge two lists in constant time in Java - not useful answers there either..
If you are using LinkedList then you are most likely not interested in indexed access (since indexed access is slow... but keep in mind that a list only stores references, so for very large lists with few insert/removes you are going to be more memory efficient with an ArrayList as it doesn't need to allocate each node on the heap)
So what you actually want is something that gives you most of the List contract... or maybe not even that.
It could well be that all you want is something that gives you Iterable<String>... if that is the case then you have a very easy life:
public class UberIterable<T> implements Iterable<T> {
private final List<List<T>> lists;
public UberIterable(List<T>... lists) {
this.lists = Arrays.asList(lists);
}
public Iterator<T> iterator() {
return new Iterator<T>() {
Iterator<List<T>> metaNext = lists.iterator();
Iterator<T> next;
public boolean hasNext() {
while (true) {
if (next != null && next.hasNext()) return true;
if (metaNext.hasNext()) next = metaNext.next(); else return false;
}
}
public T next() {
if (!hasNext()) throw new NoSuchElementException();
return next.next();
}
public void remove() {
throw new UnsupportedOperation();
}
}
}
}
That is a basic implementation that will give you a merged view of many lists. If you want to get more of the contract of List you could repeat the same tricks only with a better implementation of ListIterator which will get a lot of what you are probably after, or finally by extending AbstractList and overriding the appropriate methods with your new ListIterator implementation
If you only want to iterate over the new list and you can replace List with Iterable you can use Guava's Iterable.concat as described here:
Combine multiple Collections into a single logical Collection?
I'm afraid the answer is no. The internal Entry class used by LinkedList is private, and all the public methods exposed by LinkedList work with general collections.
Your use case seems reasonable to me, but this implementation doesn't support it.
I'm afraid that the only way to do this is by using reflections... When you take a look at the source code of LinkedList, you can see that the subclass Entry<E> is private, which is a problem if you want to connect the first and last entries to other entries, in order to merge the list.
Update: Even reflections are not safe (unless you add checks), because Oracle changed the name of the subclass Entry to Node and changed the order of arguments of the constructor! in JDK 7, which is stupid IMHO.
Dirty solution: Do a whole copy paste of the source code and change the private keywords to public. However, I'm not sure this is allowed by Oracle. Check their license.
One way you could go about doing this is by using getLast() to grab the last element off the one of the lists and then use addFirst() on the other in order to add it to the front.
As has been said here, however, addAll() would not be copying anything and could be used just as easily.
If your issue is with the actual instantiation of node objects in the LinkedList, you may need to implement your own version that exposes more of the implementation mechanisms in its API.
why not create a wrapper/proxy class that implements List and contains references to the 2 sublists, then implement the List methods (or at least the ones you need downstream) - a little bit of work but if copying either of the lists is really the issue sounds like it is worth it.
import java.util.LinkedList;
public class MergeLinkedList {
public static void main(String[] args) {
LinkedList<String> mainlist = new LinkedList<String>() ;
mainlist.add("A");
mainlist.add("B");
LinkedList<String> secondlist = new LinkedList<String>() ;
secondlist.add("C");
secondlist.add("D");
mainlist.addAll(secondlist);
System.out.println(mainlist);
}
}
O/P
[A, B, C, D]
you have to use addall();

List handling inside a class

Let's say I have a class A that has a list of related elements (type of elements not relevant):
public class A {
private List<String> list;
public List<String> getList() {
return list;
}
public void addElement(String element) {
list.add(element);
}
}
Now I want access to this list from another class, Client. I need to add a new element. The question, a more phylosophical one, is how best is this done from a design point of view.
public class Client {
private A a = new A();
public void method1() {
a.getList().add("");
}
public void method2() {
a.addElement("");
}
}
If anyone could point out any advantage of any of these methods, would be much appreciated.
Thanks.
Generally your getList() method is considered bad style. If class A returns a reference to its actual List, than a caller might call clear() on that list, or add a million elements to it, or so who-knows-what-all. It's a much better idea to return only an Iterator, or only a read-only view of the List using Collections.unmodifiableList().
This means your solution 2, addElement() is better; the addElement() method might contain code to validate the added elements, limit the size of the list, or whatever. And clear() would not be accessible.
If your intention is to really expose the list, method2 is usually a better OOP-style. (Since by using method2 you'll get addAll etc for free.)
Examples of this pattern in the standard API:
HashMap.keySet
Subject.getPrincipals
The documentation should take care to say something like The object is backed by the returned collection, so modifications will ...
The drawback is that by exposing the list you allow clients to do remove and so on, so if your intention is to just collect items through add then method1 may still be a better choice.
Examples of this pattern in the standard API:
Component.addKeyListener
DefaultTableModel.addRow
I wouldn't give access to the list (i.e. getList()) its good however that you added a addElement method. That is a good idea because you can put restrictions on what can be added to the list in that method.
I would choose
public void method2() {
a.addElement("");
}
Because mantains hidden the list inside A. Of course this depends on how related is the list to A if only instances of A should get a reference to the list then this is my choice.
One other reason might be that giving away the list could lead to clients removing items, you might want to avoid clients to consider the list as their own, it's A's, keep it safe! :P
Otherwise the list does not belong to A and should be removed from it.
You should most definitely hide the underlying list in class A. A should not provide a getList() method if possible.
Class B should use a.addElement() exclusively. And, if B needs to read from the list in A, A should provide methods for accessing the list instead of giving B the entire list.
One of the main tenants of OO programming is Encapsulation. Which means that you should hide the underlying implementation of your classes, and abstract out that low-level info.
To your specific question, you will want to use method2(). You shouldn't even be able to use a.getList() from class B if you are following proper OO principles.
When coding, you should consider the maintenance process. The less the classes know about each other the better it it is.
The client should only know that A can have elements .... so I will consider the second design as being much better.
You should provide a method for adding element on class A. Returning the original List is wrong from the design point of view because the user of your class has full access to it.
method2 is better because the client doesnt need to bother with the list implementation. if class A changes its data structure, the client is not affected.

Getters and setters and container objects (ArrayList, HashMap, etc)

Say you have a domain class that has an ArrayList attribute. What is the best practise when writing getters and setters for this type of instance (to avoid it being modified)?
public List getList() {
return Collections.unmodifiableList(list);
}
Return a List that is unmodifiable using the Collection.unmodifiableList() method:
Collections - Collection.unmodifiableList()
You can use Collections.unmodifiableList(). There are equivalents for the other major collections types.
Probably best practice is to move the code that operates on the list into the domain class. Possibly add a domain class that represents the sequence in a way appropriate to the domain.
If you are desperate to expose the list, then there is a choice:
return Collections.unmodifiableList(new ArrayList<Thing>(things));
// Bit big - shame there isn't a single method and class to do this.
return new ArrayList<Thing>(things);
// Do you really want to see client code modifying the list?
return Collections.unmodifiableList(things);
// Client may expecting a snapshot, modifications to the original will mess up.
Note if the elements of the list are mutable, you might want to do something about those too.
lweller's response is the what I would do in most cases, but it does throw an UnsupportOperationException which you may not want to deal with. In that case you might want to consider declaring a composite class, like UnmodifiableList, which contains a List of your choosing and exposes all the methods you want to support excluding those that would modify the list. This, of couse, would no longer be type compatible with the Collection interface.
Also consider making an immutable snapshot of the list.
public List getList() {
ArrayList copy = new ArrayList(this.list);
return Collections.unmodifiableList(copy);
}
We have a naming convention where
listXXX();
gives you a read-only list.
There might be setters/getters in addition to that with the proper access modifiers.
Use the guava ImmutableList class. Your getter should then follow the form:
public ImmutableList<T> getMyList() {
ImmutableList.copyOf(myList);
}
The advantage of guava over the Collections.unmodifiableList is that it reveals to the client that your colllection is immutable in the method signature, so there's very little chance of people mistakenly trying to add something to the collection.

Categories

Resources