I use an ArrayList in one of my Java project's classes. The class keeps track of whether the list has been changed and offers public methods to add and remove elements from the list that automatically set the variable to "changed".
So far the list is public because I want my list to be publicly readable from everywhere. But I only want the class that owns the list to be able to modify it. So no modifications from outside classes. Is that possible? If so, how?
Usually for access control you'd probably use getter and setter methods. But even with a getter method and the list set to private another class could still do getList().remove(element) and thereby modify the list from the outside without the class noticing that the list was changed.
Make your ArrayList field private, but have your getter return Collections.unmodifiableList(list), which provides an unmodifiable view.
This will allow external code to treat it as a normal List, using for each loops and so on, but will disable modification operations. Additionally, unmodifiableList returns a view in constant time.
This is literally the exact use case it was designed for. Javadoc:
This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.
Make your List private and add getter method:
public List getList(){
return new ArrayList(yourPrivateList);
}
You can make the ArrayList member private, and instead of a getter that returns the ArrayList, have a getter that accepts an index i and returns the i'th element of the ArrayList.
public class Test
{
private List<String> list = new ArrayList<String>();
public getString (int i)
{
// you might want to add some validation of i here
return list.get(i);
}
}
getString allows the users of your class to access any element of the list without being able to modify it.
If you want to allow your users to iterate over the list without being able to modify it, you can add a getSize() method to return the size of the list (which would allow the users to iterate over the list using the regular for loop), or your class can implement Iterable (without supporting the remove operation).
You have couple of options here:
The getter that returns the ArrayList can clone before returning the object. This way, even if the outside entity modifies the object, they'll end up modifying the clone - not your original object. Note: The clone operation can be costly. I'd suggest the below option.
Use Collections.unmodifiableList(..). Check the documentation here.
Or as other answers suggest: roll out your own methods for access and iteration.
I think your best option here is to keep your List private and add a getter method that returns a copy of the List, but not the List itself. For example:
public class EncapsulationTest {
private List<Object> privateList = new ArrayList<Object>();
// Your constructors and methods to track list
// modification here ...
public List<Object> getList() {
// Maybe you need a null check here
return new ArrayList<Object>(privateList);
}
public void addElement(Object newElement) {
this.privateList.add(newElement);
// Set your 'changed' variable to true
}
public void removeElement(Object element) {
this.privateList.remove(element);
// Set your 'changed' variable to true
}
}
If you do this, you can still read an exact copy of the List, but you can't modify the List itself. Well, actually you can modify the returned List, but as it is a different object, the changes won't affect your object's List.
I hope it helps.
Related
I have a member variable
private ArrayList<CalendarableItem>[] resourceColumns = null;
and getter for the same
public ArrayList<CalendarableItem>[] getResourceColumns()
{
return resourceColumns;
}
I am seeing findbugs for above getter method.
Malicious code vulnerability : EI: Method returning array may expose internal representation
I found that I have to do a deep copy of array object to remove this error Malicious code vulnerability - May expose internal representation by incorporating reference to mutable object
I dont want to do clone of this object due to performance issue. Do we have any other better solution.
If you want the List to be immutable in depth, remove the getter. This getter returning the list give the possibility to remove, add, ... any items in it.
You could instead use something similar to an adapter to just gave the access you want. Like a specific getter or the size of the list but without giving the access to the list.
private List<CalendarableItem> resourceColumns = new ArrayList<>();
public CalendarableItem getCalendarableItem(int index){
return resourceColumns.get(index);
}
public int getSize(){ return resourceColumns.size(); }
Your list will be private an immutable (for the moment). The only access possible are those you adapt in your class.
If you want to prevent the instance to be updated, you could return a copy of it too because for the moment, the instance return is the one from the list (same reference).
EDIT : I have just notice that this was an Array of ArrayList, so this example is not quite functionnal like this, it was written for a simple ArrayList. You need to update the adapter depending on the needs.
Just a suggestion instead of using ArrayList<CalendarableItem>[] you should use List<List<CalendarableItem>>
Now coming back to your question, you can return clone of array so that in case any one make any changes to array it will not reflect in your initial array.
public ArrayList<CalendarableItem>[] getResourceColumns()
{
return Arrays.copyOf(resourceColumns, resourceColumns.length);
}
If you want/need more control then instead of method getResourceColumns() you will need to write separate methods return object at specific array index etc.
Suppose I have a private ArrayList or a LinkedList inside a class, that I will never assign new reference to it, or in other words this will never happen:
myLinkedList = anotherLinkedList;
So that I won't need to use setMyLinkedList(anotherLinkedList).
But! I need to add elements to it, or remove elements from it.
Should I write a new kind of setter to only, do the task of adding instead of setting, like myLinkedList.add(someElement)?
Or it is OK to do this by using getter, without disobeying Encapsulation principal?
getMyLinkedList().add(someElement)
( + Suppose I am going to lose my mark if I disobey encapsulation :-")
I don't think it a particularly great practice to do something like:
myObj.getMyList().add(x);
since you are exposing a private class variable in a non read only way, but that being said I do see it pretty frequently(I'm looking at you, auto generated classes). I would argue that instead of doing it that way, return an unmodifiable list and allow users of the class to add to the list via an explicit method:
public class MyClass{
private final List<String> myList = new ArrayList<String>();
public List<String> getList(){
return Collections.unmodifiableList(this.myList);
}
public void addToList(final String s){
this.myList.add(s);
}
}
EDIT After reviewing your comments, I wanted to add a bit about your setter idea:
I meant using that line of code inside a new kind of setter inside the class itself, like public void setter(someElement){this.myLinkedList.add(someElement);}
If I'm understanding you correctly, you are saying you want to expose a method that only adds to your list. Overall this is what I think you should be shooting for, and what many have outlined in the answers, however, labeling it as a setter is a bit misleading since you are not reassigning (setting) anything. That, and I strongly recommend returning a read only list from your getter method if possible.
I would suggest in this case it would be best to follow your Encapsulation principals and use a method for adding elements to the list. You have restricted access to your list by making it private so that other classes cannot directly access the datatype.
Let the class that stores your ArrayList have direct access to the list, but when other classes want to add to the list, use an add() method.
In general, you should not assume that the list being returned by the getter is the original one. It could be decorated or proxied for example.
If you want to prevent that a new list is set on the target object, you could define an add method on the target class instead.
As soon as you have a Collection of any kind, it is generally not a bad idea to add methods like add(), remove() to the interface of your class if it makes sense that clients can add or remove objects from your private list.
The reason why it is useful to have these extra methods implemented (it might seem like overkill, because after all those methods mostly just call the method on the Collection) is that you protect evil clients from doing things to your list you don't want them to do, because the interface of most Collections contain more than just the add() and remove() methods and mostly, you don't want clients to be messing around with things you can't control. Therefore the encapsulation principle is that important to your teacher.
Another plus: if at any time, you would decide that a certain condition must be met when an object is added to your list, this can easily be implemented in the method you already have. If you give a client access to the direct reference of your list, it is not easy at all to implement this kind of things (which are not rare).
Hope this helps
So you have a class containing a List field (it should be final, since you don't intend to assign to it), and you want to allow callers to add to the List, but not be able to replace it.
You could either provide a getter for the list:
public List<E> getMyList() {
return myList;
}
Or provide a method to add to that list:
public void addToMyList(E e) {
myList.add(e);
}
Both are valid design decisions, but which you use will depend on your use case. The first option gives callers direct access to the List, effectively making it public. This is useful when users will be modifying and working with the list repeatedly, but can be problematic as you can no longer trust the List is in any sort of reliable state (the caller could empty it, or reorder it, or even maliciously insert objects of a different type). So the first option should only be used when you intend to trust the caller.
The second option gives the caller less power, because they can only add one element at a time. If you want to provide additional features (insertion, add-all, etc.) you'll have to wrap each operation in turn. But it gives you more confidence, since you can be certain the List is only being modified in ways you approve of. This latter option also hides (encapsulates) the implementation detail that you're using a List at all, so if encapsulation is important for your use case, you want to go this way to avoid exposing your internal data structures, and only expose the behavior you want to grant to callers.
It depends on the application - both are acceptable. Take a good look at the class you're writing and decide if you want to allow users to directly access the contents of the list, or if you would prefer that they go through some intermediate process first.
For example, say you have a class ListEncrypter which holds your MyLinkedList list. The purpose of this class is to encrypt anything that is stored in MyLinkedList. In this case, you'd want to provide a custom add method in order to process the added item before placing it in the list, and if you want to access the element, you'd also process it:
public void add(Object element)
{
MyLinkedList.add(encrypt(element););
}
public Object get(int index)
{
return decrypt(MyLinkedList.get(index););
}
In this case, you clearly want to deny the user's access to the MyLinkedList variable, since the contents will be encrypted and they won't be able to do anything with it.
On the other hand, if you're not really doing any processing of the data (and you're sure you won't ever need to in the future), you can skip creating the specialized methods and just allow the user to directly access the list via the get method.
I have a method:
public List getDocuments(Long orgClientId, long userId) {
// do stuff
List list = new ArrayList();
// do stuff to fill the list. The list will be of hashmaps.
return list;
}
I don't want my list to be modified outside this method. How should I return it then? Cloning it? Or just returning a new instance like
return new ArrayList<>(list);
would do it?
You can make it superficially unmodifiable thus:
return Collections.unmodifiableList(list)
This wraps the list in order that invoking any of the mutation methods will result in an exception.
However, does it really matter to you if somebody modifies the list? You are giving back a new list instance each time this method is invoked, so there is no issue with two callers getting the same instance and having to deal with interactions between the mutations.
Whatever step you take to attempt to make it unmodifiable, I can just copy the list into a modifiable container myself.
It's also quite inconvenient to me as a caller if you give me back something which I can't detect whether it is mutable or not - it looks like a List; the only way to see if I can mutate it is by calling a mutation method. That's a runtime failure, which makes it a PITA.
Update, to add an alternative.
An alternative to Collections.unmodifiableList is something like Guava's ImmutableList: this will likely be faster than Collections.unmodifiableList since it does not simply provide an unmodifiable view of existing list by wrapping, but rather provides a custom implementation of List which forbids mutation (there is less indirection).
The advantage of this is that you can return ImmutableList rather than just the List returned by Collections.unmodifiableList: this allows you to give the caller a bit more type information that they can't mutate it. ImmutableList (and its siblings like ImmutableSet) mark the mutation methods #Deprecated so your IDE can warn you that you might be doing something iffy.
The caller might choose to disregard that information (they assign the result to a List, rather than an ImmutableList), but that's their choice.
The idea is that the object returned by umodifiableCollection can't directly be changed, but could change through other means (effectively by changing the internal collection directly).
List<String> list = new ArrayList<String>();
list.add("One");
list.add("Two");
list.add("Three");
List<String> unmodifiableList = Collections.unmodifiableList(list);
// this doesn't throw an exception since it's using the add
// method of the original List reference, which is no problem
list.add("Four");
System.out.println(unmodifiableList);
// this, however, throws an exception
unmodifiableList.add("Five");
unmodifiableList returns an unmodifiable view of the specified list.
This method allows modules to provide users with "read-only" access to
internal lists. Query operations on the returned list "read through"
to the specified list, and attempts to modify the returned list,
whether direct or via its iterator, result in an
UnsupportedOperationException. The returned list will be serializable
if the specified list is serializable.
In java, I have a method which is modifying the contents of a list. Is it better to use:
public List modifyList(List originalList) { // note - my real method uses generics
// iterate over originalList and modify elements
return originalList;
}
Or is it better to do the following:
public void modifyList(List originalList) {
// iterate over originalList and modify elements
// since java objects are handled by reference, the originalList will be modified
// even though the originalList is not explicitly returned by the method
}
Note - The only difference between the two methods is the return type (one function returns void and the other returns a List).
It all depends on how you are using your List - if you are implementing some kind of list and this is the non-static method of your List class, then you should write
public List modifyList() // returning list
or
public int modifyList() // number of elements changed
If it's method outside this class
About performing operations on List or its copy: you should consider desired bahaviour and your expectations - the most importantly - do I need "old" list copy?. Deep copying list can be a little overhead. Shallow copy will unable you to perform operations on certain elements of list (i.e. changing it's attributes - if they are objects) without affecting the "old" list.
About returning void: it's good practise to return changed list (or at least number of changed elements) which will allow you to chain methods invocations, if not needed you can always ignore it.
If you are just manipulating the list, it entirely depends on temperament. Some people(including me) would argue is easier to read code using the first option (and it allows for chaining as pointed out by Adam, if you want that sort of thing).
However, keep in mind that its not really a reference being passed in. Its a pointer really. Hence, if you reinitialize the originalList instance for some reason, as in putting a
originalList = new ArrayList();
in your method body. This will not affect the list you actually passed into the method.
In my opinion you should only encourage method chaining with immutable classes.
If your function mutates an object it is too easy to do it accidentally if in a chain of methods.
One possible benefit of Option 1 is that it can accept a null List. For example, if you are collecting Foos, and generally create a brand new List, but want the option to add to an existing list. e.g. (note name of method as well)
public List<Foo> appendFoos(List<Foo> in) {
if (in == null)
in = new ArrayList<Foo>;
// now go do it, e.g.
in.add(someFooIFound);
return in;
}
and, if you wish, add an explicit no-arg "get" method as well
public List<Foo> getFoos() {
return appendFoos(null);
}
Now, in Option #2, you could do this by having the user create a new, empty ArrayList and passing that in, but Option #1 is more convenient. i.e.
Option 1 Usage:
List<Foo> theFoos = getFoos();
Option 2 Usage:
List<Foo> theFoos = new ArrayList<Foo>();
appendFoos(theFoos);
As List is mutable, so second method is better. You don't need to return modified List.
I have following code in my program:
...
private void generateStack() {
List<AdvertisementsModel> adsForModel = Storage.getAdsForId(model.getId());
...
adsForModel.clear();
...
Storage is static class with static fields and methods. generateStack method is in another class and in instance object. Why does adsForModel.clear(); affects the list in Storage class if asdForModel reference is not final?
Storage.getAdsForId(...) returns a copy of the reference to the same List object. So calls via this reference effect the same list. When you call Storage.getAdsForId there is no new List created - just a new reference to the same list.
Therefore it's good practise to either return explicitly ImmutableList or making a defensive copy of the list in Storage.getAdsForId(...) and returning the copy.
Be aware that you need to make a deep copy when AdvertisementsModel is mutable or you'll run into the same problem on a different level. (Otherwise you may have a list copy now but both lists still containing references to the same AdvertisementsModel objects and changing them still effect the list contents inside Storage.)
Java is pass by value (of the reference). So, if Storage.getAdsForId(model.getId()) returns a reference which is staticly stored within Storage then calling clear() on it in the instance will affect the same List within Storage as well. You could do this instead:
return new ArrayList<AdvertisementsModel>(Storage.getAdsForId(model.getId()));
to return a copy of the list instead which would avoid affecting the list within Storage. Of course, modifying an element of this list will still affect the same element present within the list in Storage. To avoid that, you'd have to deep copy each element in the list.
getAdsForId should return a copy of the list, otherwise it will return a reference and calling clear on the list will empty the original one.
If it is final, is the original list not affected? I have doubts about that... It's the same list instance. For this, I'd use either
new ArrayList<AdvertisementsModel>(Storage.getAdsForId(model.getId()));
which creates a new list instance and if possible, modified the Storage class to return an UnmofifiableList of the original list:
return Collections.unmodifiableList(adsForIdList);
I'd prefer this, as this solution does not create a new List instance with each call, it is the responsibility of the receiving code to decide if that needs to be created or not. However, in multithreaded environments, if the original list might be modified, this might result in ConcurrentModificationExceptions - so in that case it is wiser to create a "defensive copy" of the list in the getter itself. Be sure to keep in mind, that then the modifications to the copy will not affect the original list...